1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 13 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: `VecViewFromOptions()`, `VecView()` 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3]; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 929 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 930 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 931 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 932 if (!useLabels) numLabels = 0; 933 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 934 if (!useColors) { 935 numColors = 3; 936 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 937 } 938 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 939 if (!useColors) { 940 numLColors = 4; 941 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 942 } 943 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 944 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 945 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 946 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 994 } 995 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 996 } 997 if (drawHasse) { 998 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 999 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1001 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1003 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1012 } 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1014 1015 /* Plot vertices */ 1016 PetscCall(VecGetArray(coordinates, &coords)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 for (v = vStart; v < vEnd; ++v) { 1019 PetscInt off, dof, d; 1020 PetscBool isLabeled = PETSC_FALSE; 1021 1022 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1023 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1025 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1026 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1027 for (d = 0; d < dof; ++d) { 1028 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1029 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1030 } 1031 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1032 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1033 for (d = 0; d < dof; ++d) { 1034 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1036 } 1037 if (drawHasse) color = colors[0%numColors]; 1038 else color = colors[rank%numColors]; 1039 for (l = 0; l < numLabels; ++l) { 1040 PetscInt val; 1041 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1042 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1043 } 1044 if (drawNumbers[0]) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1046 } else if (drawColors[0]) { 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1048 } else { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1050 } 1051 } 1052 PetscCall(VecRestoreArray(coordinates, &coords)); 1053 PetscCall(PetscViewerFlush(viewer)); 1054 /* Plot edges */ 1055 if (plotEdges) { 1056 PetscCall(VecGetArray(coordinates, &coords)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1058 for (e = eStart; e < eEnd; ++e) { 1059 const PetscInt *cone; 1060 PetscInt coneSize, offA, offB, dof, d; 1061 1062 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1063 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1064 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1065 PetscCall(DMPlexGetCone(dm, e, &cone)); 1066 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1067 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1068 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1070 for (d = 0; d < dof; ++d) { 1071 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1072 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1073 } 1074 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1075 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1076 for (d = 0; d < dof; ++d) { 1077 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1079 } 1080 if (drawHasse) color = colors[1%numColors]; 1081 else color = colors[rank%numColors]; 1082 for (l = 0; l < numLabels; ++l) { 1083 PetscInt val; 1084 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1085 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1086 } 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1088 } 1089 PetscCall(VecRestoreArray(coordinates, &coords)); 1090 PetscCall(PetscViewerFlush(viewer)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1092 } 1093 /* Plot cells */ 1094 if (dim == 3 || !drawNumbers[1]) { 1095 for (e = eStart; e < eEnd; ++e) { 1096 const PetscInt *cone; 1097 1098 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1099 color = colors[rank%numColors]; 1100 for (l = 0; l < numLabels; ++l) { 1101 PetscInt val; 1102 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1103 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1104 } 1105 PetscCall(DMPlexGetCone(dm, e, &cone)); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1107 } 1108 } else { 1109 DMPolytopeType ct; 1110 1111 /* Drawing a 2D polygon */ 1112 for (c = cStart; c < cEnd; ++c) { 1113 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1115 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1116 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1117 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, e; 1120 1121 PetscCall(DMPlexGetCone(dm, c, &cone)); 1122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1123 for (e = 0; e < coneSize; ++e) { 1124 const PetscInt *econe; 1125 1126 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1127 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1128 } 1129 } else { 1130 PetscInt *closure = NULL; 1131 PetscInt closureSize, Nv = 0, v; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize*2; p += 2) { 1135 const PetscInt point = closure[p]; 1136 1137 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1138 } 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1140 for (v = 0; v <= Nv; ++v) { 1141 const PetscInt vertex = closure[v%Nv]; 1142 1143 if (v > 0) { 1144 if (plotEdges) { 1145 const PetscInt *edge; 1146 PetscInt endpoints[2], ne; 1147 1148 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1149 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1150 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1152 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1153 } else { 1154 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1155 } 1156 } 1157 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1158 } 1159 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 PetscCall(VecGetArray(coordinates, &coords)); 1165 for (c = cStart; c < cEnd; ++c) { 1166 double ccoords[3] = {0.0, 0.0, 0.0}; 1167 PetscBool isLabeled = PETSC_FALSE; 1168 PetscInt *closure = NULL; 1169 PetscInt closureSize, dof, d, n = 0; 1170 1171 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1172 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1174 for (p = 0; p < closureSize*2; p += 2) { 1175 const PetscInt point = closure[p]; 1176 PetscInt off; 1177 1178 if ((point < vStart) || (point >= vEnd)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1181 for (d = 0; d < dof; ++d) { 1182 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1183 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1184 } 1185 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1186 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1187 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1188 ++n; 1189 } 1190 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1191 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1195 } 1196 if (drawHasse) color = colors[depth%numColors]; 1197 else color = colors[rank%numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1201 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1202 } 1203 if (drawNumbers[dim]) { 1204 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1205 } else if (drawColors[dim]) { 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1207 } else { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1209 } 1210 } 1211 PetscCall(VecRestoreArray(coordinates, &coords)); 1212 if (drawHasse) { 1213 color = colors[depth%numColors]; 1214 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1215 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1216 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1217 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1219 1220 color = colors[1%numColors]; 1221 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1226 1227 color = colors[0%numColors]; 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1233 1234 for (p = pStart; p < pEnd; ++p) { 1235 const PetscInt *cone; 1236 PetscInt coneSize, cp; 1237 1238 PetscCall(DMPlexGetCone(dm, p, &cone)); 1239 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1240 for (cp = 0; cp < coneSize; ++cp) { 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1242 } 1243 } 1244 } 1245 PetscCall(PetscViewerFlush(viewer)); 1246 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1249 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1250 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1251 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1252 PetscCall(PetscFree3(names, colors, lcolors)); 1253 PetscCall(PetscBTDestroy(&wp)); 1254 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1255 Vec cown,acown; 1256 VecScatter sct; 1257 ISLocalToGlobalMapping g2l; 1258 IS gid,acis; 1259 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1260 MPI_Group ggroup,ngroup; 1261 PetscScalar *array,nid; 1262 const PetscInt *idxs; 1263 PetscInt *idxs2,*start,*adjacency,*work; 1264 PetscInt64 lm[3],gm[3]; 1265 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1266 PetscMPIInt d1,d2,rank; 1267 1268 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1269 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1270 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1271 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1272 #endif 1273 if (ncomm != MPI_COMM_NULL) { 1274 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1275 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1276 d1 = 0; 1277 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1278 nid = d2; 1279 PetscCallMPI(MPI_Group_free(&ggroup)); 1280 PetscCallMPI(MPI_Group_free(&ngroup)); 1281 PetscCallMPI(MPI_Comm_free(&ncomm)); 1282 } else nid = 0.0; 1283 1284 /* Get connectivity */ 1285 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1286 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1287 1288 /* filter overlapped local cells */ 1289 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1290 PetscCall(ISGetIndices(gid,&idxs)); 1291 PetscCall(ISGetLocalSize(gid,&cum)); 1292 PetscCall(PetscMalloc1(cum,&idxs2)); 1293 for (c = cStart, cum = 0; c < cEnd; c++) { 1294 if (idxs[c-cStart] < 0) continue; 1295 idxs2[cum++] = idxs[c-cStart]; 1296 } 1297 PetscCall(ISRestoreIndices(gid,&idxs)); 1298 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1299 PetscCall(ISDestroy(&gid)); 1300 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1301 1302 /* support for node-aware cell locality */ 1303 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1304 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1305 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1306 PetscCall(VecGetArray(cown,&array)); 1307 for (c = 0; c < numVertices; c++) array[c] = nid; 1308 PetscCall(VecRestoreArray(cown,&array)); 1309 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1310 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1311 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1312 PetscCall(ISDestroy(&acis)); 1313 PetscCall(VecScatterDestroy(&sct)); 1314 PetscCall(VecDestroy(&cown)); 1315 1316 /* compute edgeCut */ 1317 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1318 PetscCall(PetscMalloc1(cum,&work)); 1319 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1320 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1321 PetscCall(ISDestroy(&gid)); 1322 PetscCall(VecGetArray(acown,&array)); 1323 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1324 PetscInt totl; 1325 1326 totl = start[c+1]-start[c]; 1327 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1328 for (i = 0; i < totl; i++) { 1329 if (work[i] < 0) { 1330 ect += 1; 1331 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1332 } 1333 } 1334 } 1335 PetscCall(PetscFree(work)); 1336 PetscCall(VecRestoreArray(acown,&array)); 1337 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1338 lm[1] = -numVertices; 1339 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1340 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1341 lm[0] = ect; /* edgeCut */ 1342 lm[1] = ectn; /* node-aware edgeCut */ 1343 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1344 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1345 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1346 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1347 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1348 #else 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1350 #endif 1351 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1352 PetscCall(PetscFree(start)); 1353 PetscCall(PetscFree(adjacency)); 1354 PetscCall(VecDestroy(&acown)); 1355 } else { 1356 const char *name; 1357 PetscInt *sizes, *hybsizes, *ghostsizes; 1358 PetscInt locDepth, depth, cellHeight, dim, d; 1359 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1360 PetscInt numLabels, l, maxSize = 17; 1361 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1362 MPI_Comm comm; 1363 PetscMPIInt size, rank; 1364 1365 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1366 PetscCallMPI(MPI_Comm_size(comm, &size)); 1367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1368 PetscCall(DMGetDimension(dm, &dim)); 1369 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1370 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1371 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1372 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1373 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1374 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1375 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1376 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1377 gcNum = gcEnd - gcStart; 1378 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1379 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1380 for (d = 0; d <= depth; d++) { 1381 PetscInt Nc[2] = {0, 0}, ict; 1382 1383 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1384 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1385 ict = ct0; 1386 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1387 ct0 = (DMPolytopeType) ict; 1388 for (p = pStart; p < pEnd; ++p) { 1389 DMPolytopeType ct; 1390 1391 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1392 if (ct == ct0) ++Nc[0]; 1393 else ++Nc[1]; 1394 } 1395 if (size < maxSize) { 1396 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1397 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1398 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1400 for (p = 0; p < size; ++p) { 1401 if (rank == 0) { 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1403 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1404 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1405 } 1406 } 1407 } else { 1408 PetscInt locMinMax[2]; 1409 1410 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1411 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1412 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1413 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1414 if (d == depth) { 1415 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1416 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1417 } 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1420 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1421 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1422 } 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1424 } 1425 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1426 { 1427 const PetscReal *maxCell; 1428 const PetscReal *L; 1429 const DMBoundaryType *bd; 1430 PetscBool per, localized; 1431 1432 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1433 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1434 if (per) { 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1436 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1437 for (d = 0; d < dim; ++d) { 1438 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1439 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1440 } 1441 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1442 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1443 } 1444 } 1445 PetscCall(DMGetNumLabels(dm, &numLabels)); 1446 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1447 for (l = 0; l < numLabels; ++l) { 1448 DMLabel label; 1449 const char *name; 1450 IS valueIS; 1451 const PetscInt *values; 1452 PetscInt numValues, v; 1453 1454 PetscCall(DMGetLabelName(dm, l, &name)); 1455 PetscCall(DMGetLabel(dm, name, &label)); 1456 PetscCall(DMLabelGetNumValues(label, &numValues)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1459 PetscCall(ISGetIndices(valueIS, &values)); 1460 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1461 for (v = 0; v < numValues; ++v) { 1462 PetscInt size; 1463 1464 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1465 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1467 } 1468 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1469 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1470 PetscCall(ISRestoreIndices(valueIS, &values)); 1471 PetscCall(ISDestroy(&valueIS)); 1472 } 1473 { 1474 char **labelNames; 1475 PetscInt Nl = numLabels; 1476 PetscBool flg; 1477 1478 PetscCall(PetscMalloc1(Nl, &labelNames)); 1479 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1480 for (l = 0; l < Nl; ++l) { 1481 DMLabel label; 1482 1483 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1484 if (flg) { 1485 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1486 PetscCall(DMLabelView(label, viewer)); 1487 } 1488 PetscCall(PetscFree(labelNames[l])); 1489 } 1490 PetscCall(PetscFree(labelNames)); 1491 } 1492 /* If no fields are specified, people do not want to see adjacency */ 1493 if (dm->Nf) { 1494 PetscInt f; 1495 1496 for (f = 0; f < dm->Nf; ++f) { 1497 const char *name; 1498 1499 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1500 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1501 PetscCall(PetscViewerASCIIPushTab(viewer)); 1502 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1503 if (dm->fields[f].adjacency[0]) { 1504 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1505 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1506 } else { 1507 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1508 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1509 } 1510 PetscCall(PetscViewerASCIIPopTab(viewer)); 1511 } 1512 } 1513 PetscCall(DMGetCoarseDM(dm, &cdm)); 1514 if (cdm) { 1515 PetscCall(PetscViewerASCIIPushTab(viewer)); 1516 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1517 PetscCall(PetscViewerASCIIPopTab(viewer)); 1518 } 1519 } 1520 PetscFunctionReturn(0); 1521 } 1522 1523 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1524 { 1525 DMPolytopeType ct; 1526 PetscMPIInt rank; 1527 PetscInt cdim; 1528 1529 PetscFunctionBegin; 1530 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1531 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1532 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1533 switch (ct) { 1534 case DM_POLYTOPE_SEGMENT: 1535 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1536 switch (cdim) { 1537 case 1: 1538 { 1539 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1540 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1541 1542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1543 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1544 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1545 } 1546 break; 1547 case 2: 1548 { 1549 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1550 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1551 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1556 } 1557 break; 1558 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1559 } 1560 break; 1561 case DM_POLYTOPE_TRIANGLE: 1562 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1563 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1564 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1565 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1569 break; 1570 case DM_POLYTOPE_QUADRILATERAL: 1571 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1572 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1573 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1583 break; 1584 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1585 } 1586 PetscFunctionReturn(0); 1587 } 1588 1589 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1590 { 1591 DMPolytopeType ct; 1592 PetscReal centroid[2] = {0., 0.}; 1593 PetscMPIInt rank; 1594 PetscInt fillColor, v, e, d; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1600 switch (ct) { 1601 case DM_POLYTOPE_TRIANGLE: 1602 { 1603 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1604 1605 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1606 for (e = 0; e < 3; ++e) { 1607 refCoords[0] = refVertices[e*2+0]; 1608 refCoords[1] = refVertices[e*2+1]; 1609 for (d = 1; d <= edgeDiv; ++d) { 1610 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1611 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1612 } 1613 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1614 for (d = 0; d < edgeDiv; ++d) { 1615 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1616 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1617 } 1618 } 1619 } 1620 break; 1621 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1622 } 1623 PetscFunctionReturn(0); 1624 } 1625 1626 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1627 { 1628 PetscDraw draw; 1629 DM cdm; 1630 PetscSection coordSection; 1631 Vec coordinates; 1632 const PetscScalar *coords; 1633 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1634 PetscReal *refCoords, *edgeCoords; 1635 PetscBool isnull, drawAffine = PETSC_TRUE; 1636 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1637 1638 PetscFunctionBegin; 1639 PetscCall(DMGetCoordinateDim(dm, &dim)); 1640 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1641 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1642 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1643 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1644 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1645 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1646 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1647 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1648 1649 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1650 PetscCall(PetscDrawIsNull(draw, &isnull)); 1651 if (isnull) PetscFunctionReturn(0); 1652 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1653 1654 PetscCall(VecGetLocalSize(coordinates, &N)); 1655 PetscCall(VecGetArrayRead(coordinates, &coords)); 1656 for (c = 0; c < N; c += dim) { 1657 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1658 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1659 } 1660 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1661 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1662 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1663 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1664 PetscCall(PetscDrawClear(draw)); 1665 1666 for (c = cStart; c < cEnd; ++c) { 1667 PetscScalar *coords = NULL; 1668 PetscInt numCoords; 1669 1670 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1671 if (drawAffine) { 1672 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1673 } else { 1674 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1675 } 1676 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1677 } 1678 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1679 PetscCall(PetscDrawFlush(draw)); 1680 PetscCall(PetscDrawPause(draw)); 1681 PetscCall(PetscDrawSave(draw)); 1682 PetscFunctionReturn(0); 1683 } 1684 1685 #if defined(PETSC_HAVE_EXODUSII) 1686 #include <exodusII.h> 1687 #include <petscviewerexodusii.h> 1688 #endif 1689 1690 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1691 { 1692 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1693 char name[PETSC_MAX_PATH_LEN]; 1694 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1697 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1698 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1699 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1704 if (iascii) { 1705 PetscViewerFormat format; 1706 PetscCall(PetscViewerGetFormat(viewer, &format)); 1707 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1708 PetscCall(DMPlexView_GLVis(dm, viewer)); 1709 } else { 1710 PetscCall(DMPlexView_Ascii(dm, viewer)); 1711 } 1712 } else if (ishdf5) { 1713 #if defined(PETSC_HAVE_HDF5) 1714 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1715 #else 1716 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1717 #endif 1718 } else if (isvtk) { 1719 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1720 } else if (isdraw) { 1721 PetscCall(DMPlexView_Draw(dm, viewer)); 1722 } else if (isglvis) { 1723 PetscCall(DMPlexView_GLVis(dm, viewer)); 1724 #if defined(PETSC_HAVE_EXODUSII) 1725 } else if (isexodus) { 1726 /* 1727 exodusII requires that all sets be part of exactly one cell set. 1728 If the dm does not have a "Cell Sets" label defined, we create one 1729 with ID 1, containig all cells. 1730 Note that if the Cell Sets label is defined but does not cover all cells, 1731 we may still have a problem. This should probably be checked here or in the viewer; 1732 */ 1733 PetscInt numCS; 1734 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1735 if (!numCS) { 1736 PetscInt cStart, cEnd, c; 1737 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1738 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1739 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1740 } 1741 PetscCall(DMView_PlexExodusII(dm, viewer)); 1742 #endif 1743 } else { 1744 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1745 } 1746 /* Optionally view the partition */ 1747 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1748 if (flg) { 1749 Vec ranks; 1750 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1751 PetscCall(VecView(ranks, viewer)); 1752 PetscCall(VecDestroy(&ranks)); 1753 } 1754 /* Optionally view a label */ 1755 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1756 if (flg) { 1757 DMLabel label; 1758 Vec val; 1759 1760 PetscCall(DMGetLabel(dm, name, &label)); 1761 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1762 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1763 PetscCall(VecView(val, viewer)); 1764 PetscCall(VecDestroy(&val)); 1765 } 1766 PetscFunctionReturn(0); 1767 } 1768 1769 /*@ 1770 DMPlexTopologyView - Saves a DMPlex topology into a file 1771 1772 Collective on DM 1773 1774 Input Parameters: 1775 + dm - The DM whose topology is to be saved 1776 - viewer - The PetscViewer for saving 1777 1778 Level: advanced 1779 1780 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1781 @*/ 1782 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1783 { 1784 PetscBool ishdf5; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1790 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 IS globalPointNumbering; 1797 1798 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1799 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1800 PetscCall(ISDestroy(&globalPointNumbering)); 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1802 #else 1803 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1804 #endif 1805 } 1806 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1807 PetscFunctionReturn(0); 1808 } 1809 1810 /*@ 1811 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1812 1813 Collective on DM 1814 1815 Input Parameters: 1816 + dm - The DM whose coordinates are to be saved 1817 - viewer - The PetscViewer for saving 1818 1819 Level: advanced 1820 1821 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1822 @*/ 1823 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1824 { 1825 PetscBool ishdf5; 1826 1827 PetscFunctionBegin; 1828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1829 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1830 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1831 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1832 if (ishdf5) { 1833 #if defined(PETSC_HAVE_HDF5) 1834 PetscViewerFormat format; 1835 PetscCall(PetscViewerGetFormat(viewer, &format)); 1836 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1837 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1838 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1839 #else 1840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1841 #endif 1842 } 1843 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1844 PetscFunctionReturn(0); 1845 } 1846 1847 /*@ 1848 DMPlexLabelsView - Saves DMPlex labels into a file 1849 1850 Collective on DM 1851 1852 Input Parameters: 1853 + dm - The DM whose labels are to be saved 1854 - viewer - The PetscViewer for saving 1855 1856 Level: advanced 1857 1858 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1859 @*/ 1860 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1861 { 1862 PetscBool ishdf5; 1863 1864 PetscFunctionBegin; 1865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1866 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1867 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1868 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1869 if (ishdf5) { 1870 #if defined(PETSC_HAVE_HDF5) 1871 IS globalPointNumbering; 1872 PetscViewerFormat format; 1873 1874 PetscCall(PetscViewerGetFormat(viewer, &format)); 1875 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1876 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1877 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1878 PetscCall(ISDestroy(&globalPointNumbering)); 1879 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1880 #else 1881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1882 #endif 1883 } 1884 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1885 PetscFunctionReturn(0); 1886 } 1887 1888 /*@ 1889 DMPlexSectionView - Saves a section associated with a DMPlex 1890 1891 Collective on DM 1892 1893 Input Parameters: 1894 + dm - The DM that contains the topology on which the section to be saved is defined 1895 . viewer - The PetscViewer for saving 1896 - sectiondm - The DM that contains the section to be saved 1897 1898 Level: advanced 1899 1900 Notes: 1901 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1902 1903 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1904 1905 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1906 @*/ 1907 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1908 { 1909 PetscBool ishdf5; 1910 1911 PetscFunctionBegin; 1912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1913 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1914 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1916 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1917 if (ishdf5) { 1918 #if defined(PETSC_HAVE_HDF5) 1919 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1920 #else 1921 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1922 #endif 1923 } 1924 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@ 1929 DMPlexGlobalVectorView - Saves a global vector 1930 1931 Collective on DM 1932 1933 Input Parameters: 1934 + dm - The DM that represents the topology 1935 . viewer - The PetscViewer to save data with 1936 . sectiondm - The DM that contains the global section on which vec is defined 1937 - vec - The global vector to be saved 1938 1939 Level: advanced 1940 1941 Notes: 1942 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1943 1944 Typical calling sequence 1945 $ DMCreate(PETSC_COMM_WORLD, &dm); 1946 $ DMSetType(dm, DMPLEX); 1947 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1948 $ DMClone(dm, §iondm); 1949 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1950 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1951 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1952 $ PetscSectionSetChart(section, pStart, pEnd); 1953 $ PetscSectionSetUp(section); 1954 $ DMSetLocalSection(sectiondm, section); 1955 $ PetscSectionDestroy(§ion); 1956 $ DMGetGlobalVector(sectiondm, &vec); 1957 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1958 $ DMPlexTopologyView(dm, viewer); 1959 $ DMPlexSectionView(dm, viewer, sectiondm); 1960 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1961 $ DMRestoreGlobalVector(sectiondm, &vec); 1962 $ DMDestroy(§iondm); 1963 $ DMDestroy(&dm); 1964 1965 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1966 @*/ 1967 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1968 { 1969 PetscBool ishdf5; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1975 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1976 /* Check consistency */ 1977 { 1978 PetscSection section; 1979 PetscBool includesConstraints; 1980 PetscInt m, m1; 1981 1982 PetscCall(VecGetLocalSize(vec, &m1)); 1983 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1984 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1985 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1986 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1987 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1988 } 1989 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1990 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1991 if (ishdf5) { 1992 #if defined(PETSC_HAVE_HDF5) 1993 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1999 PetscFunctionReturn(0); 2000 } 2001 2002 /*@ 2003 DMPlexLocalVectorView - Saves a local vector 2004 2005 Collective on DM 2006 2007 Input Parameters: 2008 + dm - The DM that represents the topology 2009 . viewer - The PetscViewer to save data with 2010 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2011 - vec - The local vector to be saved 2012 2013 Level: advanced 2014 2015 Notes: 2016 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2017 2018 Typical calling sequence 2019 $ DMCreate(PETSC_COMM_WORLD, &dm); 2020 $ DMSetType(dm, DMPLEX); 2021 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2022 $ DMClone(dm, §iondm); 2023 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2024 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2025 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2026 $ PetscSectionSetChart(section, pStart, pEnd); 2027 $ PetscSectionSetUp(section); 2028 $ DMSetLocalSection(sectiondm, section); 2029 $ DMGetLocalVector(sectiondm, &vec); 2030 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 $ DMPlexTopologyView(dm, viewer); 2032 $ DMPlexSectionView(dm, viewer, sectiondm); 2033 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2034 $ DMRestoreLocalVector(sectiondm, &vec); 2035 $ DMDestroy(§iondm); 2036 $ DMDestroy(&dm); 2037 2038 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2039 @*/ 2040 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2072 PetscFunctionReturn(0); 2073 } 2074 2075 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2076 { 2077 PetscBool ishdf5; 2078 2079 PetscFunctionBegin; 2080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2081 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2082 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2088 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2089 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2090 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2091 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2092 PetscFunctionReturn(0); 2093 #else 2094 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2095 #endif 2096 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2097 } 2098 2099 /*@ 2100 DMPlexTopologyLoad - Loads a topology into a DMPlex 2101 2102 Collective on DM 2103 2104 Input Parameters: 2105 + dm - The DM into which the topology is loaded 2106 - viewer - The PetscViewer for the saved topology 2107 2108 Output Parameters: 2109 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2110 2111 Level: advanced 2112 2113 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2114 @*/ 2115 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2123 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2124 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2125 if (ishdf5) { 2126 #if defined(PETSC_HAVE_HDF5) 2127 PetscViewerFormat format; 2128 PetscCall(PetscViewerGetFormat(viewer, &format)); 2129 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2130 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2131 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2132 #else 2133 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2134 #endif 2135 } 2136 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2137 PetscFunctionReturn(0); 2138 } 2139 2140 /*@ 2141 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2142 2143 Collective on DM 2144 2145 Input Parameters: 2146 + dm - The DM into which the coordinates are loaded 2147 . viewer - The PetscViewer for the saved coordinates 2148 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2149 2150 Level: advanced 2151 2152 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2153 @*/ 2154 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2155 { 2156 PetscBool ishdf5; 2157 2158 PetscFunctionBegin; 2159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2160 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2161 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2162 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsLoad - Loads labels into a DMPlex 2181 2182 Collective on DM 2183 2184 Input Parameters: 2185 + dm - The DM into which the labels are loaded 2186 . viewer - The PetscViewer for the saved labels 2187 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2188 2189 Level: advanced 2190 2191 Notes: 2192 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2193 2194 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2195 @*/ 2196 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2197 { 2198 PetscBool ishdf5; 2199 2200 PetscFunctionBegin; 2201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2203 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscViewerFormat format; 2209 2210 PetscCall(PetscViewerGetFormat(viewer, &format)); 2211 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2212 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2213 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2214 #else 2215 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2216 #endif 2217 } 2218 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@ 2223 DMPlexSectionLoad - Loads section into a DMPlex 2224 2225 Collective on DM 2226 2227 Input Parameters: 2228 + dm - The DM that represents the topology 2229 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2230 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2231 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2232 2233 Output Parameters 2234 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2235 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2236 2237 Level: advanced 2238 2239 Notes: 2240 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2241 2242 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2243 2244 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2245 2246 Example using 2 processes: 2247 $ NX (number of points on dm): 4 2248 $ sectionA : the on-disk section 2249 $ vecA : a vector associated with sectionA 2250 $ sectionB : sectiondm's local section constructed in this function 2251 $ vecB (local) : a vector associated with sectiondm's local section 2252 $ vecB (global) : a vector associated with sectiondm's global section 2253 $ 2254 $ rank 0 rank 1 2255 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2256 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2257 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2258 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2259 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2260 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2261 $ sectionB->atlasDof : 1 0 1 | 1 3 2262 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2263 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2264 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2265 $ 2266 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2267 2268 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2269 @*/ 2270 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2279 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2280 if (localDofSF) PetscValidPointer(localDofSF, 6); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2296 2297 Collective on DM 2298 2299 Input Parameters: 2300 + dm - The DM that represents the topology 2301 . viewer - The PetscViewer that represents the on-disk vector data 2302 . sectiondm - The DM that contains the global section on which vec is defined 2303 . sf - The SF that migrates the on-disk vector data into vec 2304 - vec - The global vector to set values of 2305 2306 Level: advanced 2307 2308 Notes: 2309 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2310 2311 Typical calling sequence 2312 $ DMCreate(PETSC_COMM_WORLD, &dm); 2313 $ DMSetType(dm, DMPLEX); 2314 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2316 $ DMClone(dm, §iondm); 2317 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2319 $ DMGetGlobalVector(sectiondm, &vec); 2320 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2322 $ DMRestoreGlobalVector(sectiondm, &vec); 2323 $ PetscSFDestroy(&gsf); 2324 $ PetscSFDestroy(&sfX); 2325 $ DMDestroy(§iondm); 2326 $ DMDestroy(&dm); 2327 2328 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2329 @*/ 2330 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2331 { 2332 PetscBool ishdf5; 2333 2334 PetscFunctionBegin; 2335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2336 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2337 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2338 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2339 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2340 /* Check consistency */ 2341 { 2342 PetscSection section; 2343 PetscBool includesConstraints; 2344 PetscInt m, m1; 2345 2346 PetscCall(VecGetLocalSize(vec, &m1)); 2347 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2348 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2349 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2350 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2351 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2352 } 2353 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2354 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2355 if (ishdf5) { 2356 #if defined(PETSC_HAVE_HDF5) 2357 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2358 #else 2359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2360 #endif 2361 } 2362 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2368 2369 Collective on DM 2370 2371 Input Parameters: 2372 + dm - The DM that represents the topology 2373 . viewer - The PetscViewer that represents the on-disk vector data 2374 . sectiondm - The DM that contains the local section on which vec is defined 2375 . sf - The SF that migrates the on-disk vector data into vec 2376 - vec - The local vector to set values of 2377 2378 Level: advanced 2379 2380 Notes: 2381 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Typical calling sequence 2384 $ DMCreate(PETSC_COMM_WORLD, &dm); 2385 $ DMSetType(dm, DMPLEX); 2386 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2387 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2388 $ DMClone(dm, §iondm); 2389 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2391 $ DMGetLocalVector(sectiondm, &vec); 2392 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2393 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2394 $ DMRestoreLocalVector(sectiondm, &vec); 2395 $ PetscSFDestroy(&lsf); 2396 $ PetscSFDestroy(&sfX); 2397 $ DMDestroy(§iondm); 2398 $ DMDestroy(&dm); 2399 2400 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2401 @*/ 2402 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2403 { 2404 PetscBool ishdf5; 2405 2406 PetscFunctionBegin; 2407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2408 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2409 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2410 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2411 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2412 /* Check consistency */ 2413 { 2414 PetscSection section; 2415 PetscBool includesConstraints; 2416 PetscInt m, m1; 2417 2418 PetscCall(VecGetLocalSize(vec, &m1)); 2419 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2420 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2421 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2422 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2423 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2424 } 2425 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2426 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2427 if (ishdf5) { 2428 #if defined(PETSC_HAVE_HDF5) 2429 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2435 PetscFunctionReturn(0); 2436 } 2437 2438 PetscErrorCode DMDestroy_Plex(DM dm) 2439 { 2440 DM_Plex *mesh = (DM_Plex*) dm->data; 2441 2442 PetscFunctionBegin; 2443 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2444 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2445 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2446 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2447 if (--mesh->refct > 0) PetscFunctionReturn(0); 2448 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2449 PetscCall(PetscFree(mesh->cones)); 2450 PetscCall(PetscFree(mesh->coneOrientations)); 2451 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2452 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2453 PetscCall(PetscFree(mesh->supports)); 2454 PetscCall(PetscFree(mesh->facesTmp)); 2455 PetscCall(PetscFree(mesh->tetgenOpts)); 2456 PetscCall(PetscFree(mesh->triangleOpts)); 2457 PetscCall(PetscFree(mesh->transformType)); 2458 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2459 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2460 PetscCall(ISDestroy(&mesh->subpointIS)); 2461 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2462 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2463 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2464 PetscCall(ISDestroy(&mesh->anchorIS)); 2465 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2466 PetscCall(PetscFree(mesh->parents)); 2467 PetscCall(PetscFree(mesh->childIDs)); 2468 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2469 PetscCall(PetscFree(mesh->children)); 2470 PetscCall(DMDestroy(&mesh->referenceTree)); 2471 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2472 PetscCall(PetscFree(mesh->neighbors)); 2473 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2474 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2475 PetscCall(PetscFree(mesh)); 2476 PetscFunctionReturn(0); 2477 } 2478 2479 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2480 { 2481 PetscSection sectionGlobal; 2482 PetscInt bs = -1, mbs; 2483 PetscInt localSize; 2484 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2485 MatType mtype; 2486 ISLocalToGlobalMapping ltog; 2487 2488 PetscFunctionBegin; 2489 PetscCall(MatInitializePackage()); 2490 mtype = dm->mattype; 2491 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2492 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2493 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2494 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2495 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2496 PetscCall(MatSetType(*J, mtype)); 2497 PetscCall(MatSetFromOptions(*J)); 2498 PetscCall(MatGetBlockSize(*J, &mbs)); 2499 if (mbs > 1) bs = mbs; 2500 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2501 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2502 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2503 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2504 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2505 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2506 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2507 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2508 if (!isShell) { 2509 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2510 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2]; 2511 PetscInt pStart, pEnd, p, dof, cdof; 2512 2513 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2514 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2515 for (p = pStart; p < pEnd; ++p) { 2516 PetscInt bdof; 2517 2518 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2519 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2520 dof = dof < 0 ? -(dof+1) : dof; 2521 bdof = cdof && (dof-cdof) ? 1 : dof; 2522 if (dof) { 2523 if (bs < 0) {bs = bdof;} 2524 else if (bs != bdof) {bs = 1; break;} 2525 } 2526 } 2527 /* Must have same blocksize on all procs (some might have no points) */ 2528 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2529 bsLocal[1] = bs; 2530 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2531 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2532 else bs = bsMinMax[0]; 2533 bs = PetscMax(1,bs); 2534 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2535 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2536 PetscCall(MatSetBlockSize(*J, bs)); 2537 PetscCall(MatSetUp(*J)); 2538 } else { 2539 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2540 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2541 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2542 } 2543 } 2544 PetscCall(MatSetDM(*J, dm)); 2545 PetscFunctionReturn(0); 2546 } 2547 2548 /*@ 2549 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2550 2551 Not collective 2552 2553 Input Parameter: 2554 . mesh - The DMPlex 2555 2556 Output Parameters: 2557 . subsection - The subdomain section 2558 2559 Level: developer 2560 2561 .seealso: 2562 @*/ 2563 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2564 { 2565 DM_Plex *mesh = (DM_Plex*) dm->data; 2566 2567 PetscFunctionBegin; 2568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2569 if (!mesh->subdomainSection) { 2570 PetscSection section; 2571 PetscSF sf; 2572 2573 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2574 PetscCall(DMGetLocalSection(dm,§ion)); 2575 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2576 PetscCall(PetscSFDestroy(&sf)); 2577 } 2578 *subsection = mesh->subdomainSection; 2579 PetscFunctionReturn(0); 2580 } 2581 2582 /*@ 2583 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2584 2585 Not collective 2586 2587 Input Parameter: 2588 . mesh - The DMPlex 2589 2590 Output Parameters: 2591 + pStart - The first mesh point 2592 - pEnd - The upper bound for mesh points 2593 2594 Level: beginner 2595 2596 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2597 @*/ 2598 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2599 { 2600 DM_Plex *mesh = (DM_Plex*) dm->data; 2601 2602 PetscFunctionBegin; 2603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2604 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2605 PetscFunctionReturn(0); 2606 } 2607 2608 /*@ 2609 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2610 2611 Not collective 2612 2613 Input Parameters: 2614 + mesh - The DMPlex 2615 . pStart - The first mesh point 2616 - pEnd - The upper bound for mesh points 2617 2618 Output Parameters: 2619 2620 Level: beginner 2621 2622 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2623 @*/ 2624 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2625 { 2626 DM_Plex *mesh = (DM_Plex*) dm->data; 2627 2628 PetscFunctionBegin; 2629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2630 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2631 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2632 PetscFunctionReturn(0); 2633 } 2634 2635 /*@ 2636 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2637 2638 Not collective 2639 2640 Input Parameters: 2641 + mesh - The DMPlex 2642 - p - The point, which must lie in the chart set with DMPlexSetChart() 2643 2644 Output Parameter: 2645 . size - The cone size for point p 2646 2647 Level: beginner 2648 2649 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2650 @*/ 2651 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2652 { 2653 DM_Plex *mesh = (DM_Plex*) dm->data; 2654 2655 PetscFunctionBegin; 2656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2657 PetscValidIntPointer(size, 3); 2658 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2659 PetscFunctionReturn(0); 2660 } 2661 2662 /*@ 2663 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2664 2665 Not collective 2666 2667 Input Parameters: 2668 + mesh - The DMPlex 2669 . p - The point, which must lie in the chart set with DMPlexSetChart() 2670 - size - The cone size for point p 2671 2672 Output Parameter: 2673 2674 Note: 2675 This should be called after DMPlexSetChart(). 2676 2677 Level: beginner 2678 2679 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2680 @*/ 2681 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2682 { 2683 DM_Plex *mesh = (DM_Plex*) dm->data; 2684 2685 PetscFunctionBegin; 2686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2687 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2688 PetscFunctionReturn(0); 2689 } 2690 2691 /*@ 2692 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2693 2694 Not collective 2695 2696 Input Parameters: 2697 + mesh - The DMPlex 2698 . p - The point, which must lie in the chart set with DMPlexSetChart() 2699 - size - The additional cone size for point p 2700 2701 Output Parameter: 2702 2703 Note: 2704 This should be called after DMPlexSetChart(). 2705 2706 Level: beginner 2707 2708 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2709 @*/ 2710 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2711 { 2712 DM_Plex *mesh = (DM_Plex*) dm->data; 2713 PetscFunctionBegin; 2714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2715 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2716 PetscFunctionReturn(0); 2717 } 2718 2719 /*@C 2720 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2721 2722 Not collective 2723 2724 Input Parameters: 2725 + dm - The DMPlex 2726 - p - The point, which must lie in the chart set with DMPlexSetChart() 2727 2728 Output Parameter: 2729 . cone - An array of points which are on the in-edges for point p 2730 2731 Level: beginner 2732 2733 Fortran Notes: 2734 Since it returns an array, this routine is only available in Fortran 90, and you must 2735 include petsc.h90 in your code. 2736 You must also call DMPlexRestoreCone() after you finish using the returned array. 2737 DMPlexRestoreCone() is not needed/available in C. 2738 2739 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2740 @*/ 2741 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2742 { 2743 DM_Plex *mesh = (DM_Plex*) dm->data; 2744 PetscInt off; 2745 2746 PetscFunctionBegin; 2747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2748 PetscValidPointer(cone, 3); 2749 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2750 *cone = &mesh->cones[off]; 2751 PetscFunctionReturn(0); 2752 } 2753 2754 /*@C 2755 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2756 2757 Not collective 2758 2759 Input Parameters: 2760 + dm - The DMPlex 2761 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2762 2763 Output Parameters: 2764 + pConesSection - PetscSection describing the layout of pCones 2765 - pCones - An array of points which are on the in-edges for the point set p 2766 2767 Level: intermediate 2768 2769 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2770 @*/ 2771 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2772 { 2773 PetscSection cs, newcs; 2774 PetscInt *cones; 2775 PetscInt *newarr=NULL; 2776 PetscInt n; 2777 2778 PetscFunctionBegin; 2779 PetscCall(DMPlexGetCones(dm, &cones)); 2780 PetscCall(DMPlexGetConeSection(dm, &cs)); 2781 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2782 if (pConesSection) *pConesSection = newcs; 2783 if (pCones) { 2784 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2785 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2786 } 2787 PetscFunctionReturn(0); 2788 } 2789 2790 /*@ 2791 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2792 2793 Not collective 2794 2795 Input Parameters: 2796 + dm - The DMPlex 2797 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2798 2799 Output Parameter: 2800 . expandedPoints - An array of vertices recursively expanded from input points 2801 2802 Level: advanced 2803 2804 Notes: 2805 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2806 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2807 2808 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2809 @*/ 2810 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2811 { 2812 IS *expandedPointsAll; 2813 PetscInt depth; 2814 2815 PetscFunctionBegin; 2816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2817 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2818 PetscValidPointer(expandedPoints, 3); 2819 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2820 *expandedPoints = expandedPointsAll[0]; 2821 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2822 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2823 PetscFunctionReturn(0); 2824 } 2825 2826 /*@ 2827 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). 2828 2829 Not collective 2830 2831 Input Parameters: 2832 + dm - The DMPlex 2833 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2834 2835 Output Parameters: 2836 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2837 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2838 - sections - (optional) An array of sections which describe mappings from points to their cone points 2839 2840 Level: advanced 2841 2842 Notes: 2843 Like DMPlexGetConeTuple() but recursive. 2844 2845 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. 2846 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2847 2848 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: 2849 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2850 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2851 2852 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2853 @*/ 2854 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2855 { 2856 const PetscInt *arr0=NULL, *cone=NULL; 2857 PetscInt *arr=NULL, *newarr=NULL; 2858 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2859 IS *expandedPoints_; 2860 PetscSection *sections_; 2861 2862 PetscFunctionBegin; 2863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2864 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2865 if (depth) PetscValidIntPointer(depth, 3); 2866 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2867 if (sections) PetscValidPointer(sections, 5); 2868 PetscCall(ISGetLocalSize(points, &n)); 2869 PetscCall(ISGetIndices(points, &arr0)); 2870 PetscCall(DMPlexGetDepth(dm, &depth_)); 2871 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2872 PetscCall(PetscCalloc1(depth_, §ions_)); 2873 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2874 for (d=depth_-1; d>=0; d--) { 2875 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2876 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2877 for (i=0; i<n; i++) { 2878 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2879 if (arr[i] >= start && arr[i] < end) { 2880 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2881 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2882 } else { 2883 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2884 } 2885 } 2886 PetscCall(PetscSectionSetUp(sections_[d])); 2887 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2888 PetscCall(PetscMalloc1(newn, &newarr)); 2889 for (i=0; i<n; i++) { 2890 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2891 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2892 if (cn > 1) { 2893 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2894 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2895 } else { 2896 newarr[co] = arr[i]; 2897 } 2898 } 2899 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2900 arr = newarr; 2901 n = newn; 2902 } 2903 PetscCall(ISRestoreIndices(points, &arr0)); 2904 *depth = depth_; 2905 if (expandedPoints) *expandedPoints = expandedPoints_; 2906 else { 2907 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2908 PetscCall(PetscFree(expandedPoints_)); 2909 } 2910 if (sections) *sections = sections_; 2911 else { 2912 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2913 PetscCall(PetscFree(sections_)); 2914 } 2915 PetscFunctionReturn(0); 2916 } 2917 2918 /*@ 2919 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2920 2921 Not collective 2922 2923 Input Parameters: 2924 + dm - The DMPlex 2925 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2926 2927 Output Parameters: 2928 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2929 . expandedPoints - (optional) An array of recursively expanded cones 2930 - sections - (optional) An array of sections which describe mappings from points to their cone points 2931 2932 Level: advanced 2933 2934 Notes: 2935 See DMPlexGetConeRecursive() for details. 2936 2937 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2938 @*/ 2939 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2940 { 2941 PetscInt d, depth_; 2942 2943 PetscFunctionBegin; 2944 PetscCall(DMPlexGetDepth(dm, &depth_)); 2945 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2946 if (depth) *depth = 0; 2947 if (expandedPoints) { 2948 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2949 PetscCall(PetscFree(*expandedPoints)); 2950 } 2951 if (sections) { 2952 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2953 PetscCall(PetscFree(*sections)); 2954 } 2955 PetscFunctionReturn(0); 2956 } 2957 2958 /*@ 2959 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 2960 2961 Not collective 2962 2963 Input Parameters: 2964 + mesh - The DMPlex 2965 . p - The point, which must lie in the chart set with DMPlexSetChart() 2966 - cone - An array of points which are on the in-edges for point p 2967 2968 Output Parameter: 2969 2970 Note: 2971 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2972 2973 Level: beginner 2974 2975 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2976 @*/ 2977 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 2978 { 2979 DM_Plex *mesh = (DM_Plex*) dm->data; 2980 PetscInt pStart, pEnd; 2981 PetscInt dof, off, c; 2982 2983 PetscFunctionBegin; 2984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2985 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 2986 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 2987 if (dof) PetscValidIntPointer(cone, 3); 2988 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2989 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); 2990 for (c = 0; c < dof; ++c) { 2991 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); 2992 mesh->cones[off+c] = cone[c]; 2993 } 2994 PetscFunctionReturn(0); 2995 } 2996 2997 /*@C 2998 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 2999 3000 Not collective 3001 3002 Input Parameters: 3003 + mesh - The DMPlex 3004 - p - The point, which must lie in the chart set with DMPlexSetChart() 3005 3006 Output Parameter: 3007 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3008 integer giving the prescription for cone traversal. 3009 3010 Level: beginner 3011 3012 Notes: 3013 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3014 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3015 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3016 with the identity. 3017 3018 Fortran Notes: 3019 Since it returns an array, this routine is only available in Fortran 90, and you must 3020 include petsc.h90 in your code. 3021 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3022 DMPlexRestoreConeOrientation() is not needed/available in C. 3023 3024 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3025 @*/ 3026 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3027 { 3028 DM_Plex *mesh = (DM_Plex*) dm->data; 3029 PetscInt off; 3030 3031 PetscFunctionBegin; 3032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3033 if (PetscDefined(USE_DEBUG)) { 3034 PetscInt dof; 3035 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3036 if (dof) PetscValidPointer(coneOrientation, 3); 3037 } 3038 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3039 3040 *coneOrientation = &mesh->coneOrientations[off]; 3041 PetscFunctionReturn(0); 3042 } 3043 3044 /*@ 3045 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3046 3047 Not collective 3048 3049 Input Parameters: 3050 + mesh - The DMPlex 3051 . p - The point, which must lie in the chart set with DMPlexSetChart() 3052 - coneOrientation - An array of orientations 3053 Output Parameter: 3054 3055 Notes: 3056 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3057 3058 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3059 3060 Level: beginner 3061 3062 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3063 @*/ 3064 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3065 { 3066 DM_Plex *mesh = (DM_Plex*) dm->data; 3067 PetscInt pStart, pEnd; 3068 PetscInt dof, off, c; 3069 3070 PetscFunctionBegin; 3071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3072 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3073 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3074 if (dof) PetscValidIntPointer(coneOrientation, 3); 3075 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3076 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); 3077 for (c = 0; c < dof; ++c) { 3078 PetscInt cdof, o = coneOrientation[c]; 3079 3080 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3081 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); 3082 mesh->coneOrientations[off+c] = o; 3083 } 3084 PetscFunctionReturn(0); 3085 } 3086 3087 /*@ 3088 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3089 3090 Not collective 3091 3092 Input Parameters: 3093 + mesh - The DMPlex 3094 . p - The point, which must lie in the chart set with DMPlexSetChart() 3095 . conePos - The local index in the cone where the point should be put 3096 - conePoint - The mesh point to insert 3097 3098 Level: beginner 3099 3100 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3101 @*/ 3102 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3103 { 3104 DM_Plex *mesh = (DM_Plex*) dm->data; 3105 PetscInt pStart, pEnd; 3106 PetscInt dof, off; 3107 3108 PetscFunctionBegin; 3109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3110 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3111 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); 3112 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); 3113 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3114 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3115 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); 3116 mesh->cones[off+conePos] = conePoint; 3117 PetscFunctionReturn(0); 3118 } 3119 3120 /*@ 3121 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3122 3123 Not collective 3124 3125 Input Parameters: 3126 + mesh - The DMPlex 3127 . p - The point, which must lie in the chart set with DMPlexSetChart() 3128 . conePos - The local index in the cone where the point should be put 3129 - coneOrientation - The point orientation to insert 3130 3131 Level: beginner 3132 3133 Notes: 3134 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3135 3136 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3137 @*/ 3138 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3139 { 3140 DM_Plex *mesh = (DM_Plex*) dm->data; 3141 PetscInt pStart, pEnd; 3142 PetscInt dof, off; 3143 3144 PetscFunctionBegin; 3145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3146 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3147 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); 3148 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3149 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3150 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); 3151 mesh->coneOrientations[off+conePos] = coneOrientation; 3152 PetscFunctionReturn(0); 3153 } 3154 3155 /*@ 3156 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3157 3158 Not collective 3159 3160 Input Parameters: 3161 + mesh - The DMPlex 3162 - p - The point, which must lie in the chart set with DMPlexSetChart() 3163 3164 Output Parameter: 3165 . size - The support size for point p 3166 3167 Level: beginner 3168 3169 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3170 @*/ 3171 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3172 { 3173 DM_Plex *mesh = (DM_Plex*) dm->data; 3174 3175 PetscFunctionBegin; 3176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3177 PetscValidIntPointer(size, 3); 3178 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3179 PetscFunctionReturn(0); 3180 } 3181 3182 /*@ 3183 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3184 3185 Not collective 3186 3187 Input Parameters: 3188 + mesh - The DMPlex 3189 . p - The point, which must lie in the chart set with DMPlexSetChart() 3190 - size - The support size for point p 3191 3192 Output Parameter: 3193 3194 Note: 3195 This should be called after DMPlexSetChart(). 3196 3197 Level: beginner 3198 3199 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3200 @*/ 3201 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3202 { 3203 DM_Plex *mesh = (DM_Plex*) dm->data; 3204 3205 PetscFunctionBegin; 3206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3207 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3208 PetscFunctionReturn(0); 3209 } 3210 3211 /*@C 3212 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3213 3214 Not collective 3215 3216 Input Parameters: 3217 + mesh - The DMPlex 3218 - p - The point, which must lie in the chart set with DMPlexSetChart() 3219 3220 Output Parameter: 3221 . support - An array of points which are on the out-edges for point p 3222 3223 Level: beginner 3224 3225 Fortran Notes: 3226 Since it returns an array, this routine is only available in Fortran 90, and you must 3227 include petsc.h90 in your code. 3228 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3229 DMPlexRestoreSupport() is not needed/available in C. 3230 3231 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3232 @*/ 3233 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3234 { 3235 DM_Plex *mesh = (DM_Plex*) dm->data; 3236 PetscInt off; 3237 3238 PetscFunctionBegin; 3239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3240 PetscValidPointer(support, 3); 3241 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3242 *support = &mesh->supports[off]; 3243 PetscFunctionReturn(0); 3244 } 3245 3246 /*@ 3247 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3248 3249 Not collective 3250 3251 Input Parameters: 3252 + mesh - The DMPlex 3253 . p - The point, which must lie in the chart set with DMPlexSetChart() 3254 - support - An array of points which are on the out-edges for point p 3255 3256 Output Parameter: 3257 3258 Note: 3259 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3260 3261 Level: beginner 3262 3263 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3264 @*/ 3265 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3266 { 3267 DM_Plex *mesh = (DM_Plex*) dm->data; 3268 PetscInt pStart, pEnd; 3269 PetscInt dof, off, c; 3270 3271 PetscFunctionBegin; 3272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3273 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3274 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3275 if (dof) PetscValidIntPointer(support, 3); 3276 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3277 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); 3278 for (c = 0; c < dof; ++c) { 3279 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); 3280 mesh->supports[off+c] = support[c]; 3281 } 3282 PetscFunctionReturn(0); 3283 } 3284 3285 /*@ 3286 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3287 3288 Not collective 3289 3290 Input Parameters: 3291 + mesh - The DMPlex 3292 . p - The point, which must lie in the chart set with DMPlexSetChart() 3293 . supportPos - The local index in the cone where the point should be put 3294 - supportPoint - The mesh point to insert 3295 3296 Level: beginner 3297 3298 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3299 @*/ 3300 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3301 { 3302 DM_Plex *mesh = (DM_Plex*) dm->data; 3303 PetscInt pStart, pEnd; 3304 PetscInt dof, off; 3305 3306 PetscFunctionBegin; 3307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3308 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3309 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3310 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3311 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); 3312 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); 3313 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); 3314 mesh->supports[off+supportPos] = supportPoint; 3315 PetscFunctionReturn(0); 3316 } 3317 3318 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3319 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3320 { 3321 switch (ct) { 3322 case DM_POLYTOPE_SEGMENT: 3323 if (o == -1) return -2; 3324 break; 3325 case DM_POLYTOPE_TRIANGLE: 3326 if (o == -3) return -1; 3327 if (o == -2) return -3; 3328 if (o == -1) return -2; 3329 break; 3330 case DM_POLYTOPE_QUADRILATERAL: 3331 if (o == -4) return -2; 3332 if (o == -3) return -1; 3333 if (o == -2) return -4; 3334 if (o == -1) return -3; 3335 break; 3336 default: return o; 3337 } 3338 return o; 3339 } 3340 3341 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3342 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3343 { 3344 switch (ct) { 3345 case DM_POLYTOPE_SEGMENT: 3346 if ((o == -2) || (o == 1)) return -1; 3347 if (o == -1) return 0; 3348 break; 3349 case DM_POLYTOPE_TRIANGLE: 3350 if (o == -3) return -2; 3351 if (o == -2) return -1; 3352 if (o == -1) return -3; 3353 break; 3354 case DM_POLYTOPE_QUADRILATERAL: 3355 if (o == -4) return -2; 3356 if (o == -3) return -1; 3357 if (o == -2) return -4; 3358 if (o == -1) return -3; 3359 break; 3360 default: return o; 3361 } 3362 return o; 3363 } 3364 3365 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3366 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3367 { 3368 PetscInt pStart, pEnd, p; 3369 3370 PetscFunctionBegin; 3371 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3372 for (p = pStart; p < pEnd; ++p) { 3373 const PetscInt *cone, *ornt; 3374 PetscInt coneSize, c; 3375 3376 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3377 PetscCall(DMPlexGetCone(dm, p, &cone)); 3378 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3379 for (c = 0; c < coneSize; ++c) { 3380 DMPolytopeType ct; 3381 const PetscInt o = ornt[c]; 3382 3383 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3384 switch (ct) { 3385 case DM_POLYTOPE_SEGMENT: 3386 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3387 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3388 break; 3389 case DM_POLYTOPE_TRIANGLE: 3390 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3391 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3392 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3393 break; 3394 case DM_POLYTOPE_QUADRILATERAL: 3395 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3396 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3397 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3398 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3399 break; 3400 default: break; 3401 } 3402 } 3403 } 3404 PetscFunctionReturn(0); 3405 } 3406 3407 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3408 { 3409 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3410 PetscInt *closure; 3411 const PetscInt *tmp = NULL, *tmpO = NULL; 3412 PetscInt off = 0, tmpSize, t; 3413 3414 PetscFunctionBeginHot; 3415 if (ornt) { 3416 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3417 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3418 } 3419 if (*points) { 3420 closure = *points; 3421 } else { 3422 PetscInt maxConeSize, maxSupportSize; 3423 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3424 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3425 } 3426 if (useCone) { 3427 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3428 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3429 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3430 } else { 3431 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3432 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3433 } 3434 if (ct == DM_POLYTOPE_UNKNOWN) { 3435 closure[off++] = p; 3436 closure[off++] = 0; 3437 for (t = 0; t < tmpSize; ++t) { 3438 closure[off++] = tmp[t]; 3439 closure[off++] = tmpO ? tmpO[t] : 0; 3440 } 3441 } else { 3442 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3443 3444 /* We assume that cells with a valid type have faces with a valid type */ 3445 closure[off++] = p; 3446 closure[off++] = ornt; 3447 for (t = 0; t < tmpSize; ++t) { 3448 DMPolytopeType ft; 3449 3450 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3451 closure[off++] = tmp[arr[t]]; 3452 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3453 } 3454 } 3455 if (numPoints) *numPoints = tmpSize+1; 3456 if (points) *points = closure; 3457 PetscFunctionReturn(0); 3458 } 3459 3460 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3461 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3462 { 3463 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3464 const PetscInt *cone, *ornt; 3465 PetscInt *pts, *closure = NULL; 3466 DMPolytopeType ft; 3467 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3468 PetscInt dim, coneSize, c, d, clSize, cl; 3469 3470 PetscFunctionBeginHot; 3471 PetscCall(DMGetDimension(dm, &dim)); 3472 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3473 PetscCall(DMPlexGetCone(dm, point, &cone)); 3474 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3475 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3476 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3477 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3478 maxSize = PetscMax(coneSeries, supportSeries); 3479 if (*points) {pts = *points;} 3480 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3481 c = 0; 3482 pts[c++] = point; 3483 pts[c++] = o; 3484 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3485 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3486 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3487 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3488 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3489 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3490 for (d = 2; d < coneSize; ++d) { 3491 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3492 pts[c++] = cone[arr[d*2+0]]; 3493 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3494 } 3495 if (dim >= 3) { 3496 for (d = 2; d < coneSize; ++d) { 3497 const PetscInt fpoint = cone[arr[d*2+0]]; 3498 const PetscInt *fcone, *fornt; 3499 PetscInt fconeSize, fc, i; 3500 3501 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3502 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3503 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3504 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3505 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3506 for (fc = 0; fc < fconeSize; ++fc) { 3507 const PetscInt cp = fcone[farr[fc*2+0]]; 3508 const PetscInt co = farr[fc*2+1]; 3509 3510 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3511 if (i == c) { 3512 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3513 pts[c++] = cp; 3514 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3515 } 3516 } 3517 } 3518 } 3519 *numPoints = c/2; 3520 *points = pts; 3521 PetscFunctionReturn(0); 3522 } 3523 3524 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3525 { 3526 DMPolytopeType ct; 3527 PetscInt *closure, *fifo; 3528 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3529 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3530 PetscInt depth, maxSize; 3531 3532 PetscFunctionBeginHot; 3533 PetscCall(DMPlexGetDepth(dm, &depth)); 3534 if (depth == 1) { 3535 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3536 PetscFunctionReturn(0); 3537 } 3538 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3539 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3540 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3541 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3542 PetscFunctionReturn(0); 3543 } 3544 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3545 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3546 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3547 maxSize = PetscMax(coneSeries, supportSeries); 3548 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3549 if (*points) {closure = *points;} 3550 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3551 closure[closureSize++] = p; 3552 closure[closureSize++] = ornt; 3553 fifo[fifoSize++] = p; 3554 fifo[fifoSize++] = ornt; 3555 fifo[fifoSize++] = ct; 3556 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3557 while (fifoSize - fifoStart) { 3558 const PetscInt q = fifo[fifoStart++]; 3559 const PetscInt o = fifo[fifoStart++]; 3560 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3561 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3562 const PetscInt *tmp, *tmpO; 3563 PetscInt tmpSize, t; 3564 3565 if (PetscDefined(USE_DEBUG)) { 3566 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3567 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); 3568 } 3569 if (useCone) { 3570 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3571 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3572 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3573 } else { 3574 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3575 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3576 tmpO = NULL; 3577 } 3578 for (t = 0; t < tmpSize; ++t) { 3579 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3580 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3581 const PetscInt cp = tmp[ip]; 3582 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3583 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3584 PetscInt c; 3585 3586 /* Check for duplicate */ 3587 for (c = 0; c < closureSize; c += 2) { 3588 if (closure[c] == cp) break; 3589 } 3590 if (c == closureSize) { 3591 closure[closureSize++] = cp; 3592 closure[closureSize++] = co; 3593 fifo[fifoSize++] = cp; 3594 fifo[fifoSize++] = co; 3595 fifo[fifoSize++] = ct; 3596 } 3597 } 3598 } 3599 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3600 if (numPoints) *numPoints = closureSize/2; 3601 if (points) *points = closure; 3602 PetscFunctionReturn(0); 3603 } 3604 3605 /*@C 3606 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3607 3608 Not collective 3609 3610 Input Parameters: 3611 + dm - The DMPlex 3612 . p - The mesh point 3613 - useCone - PETSC_TRUE for the closure, otherwise return the star 3614 3615 Input/Output Parameter: 3616 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3617 if NULL on input, internal storage will be returned, otherwise the provided array is used 3618 3619 Output Parameter: 3620 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3621 3622 Note: 3623 If using internal storage (points is NULL on input), each call overwrites the last output. 3624 3625 Fortran Notes: 3626 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3627 3628 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3629 3630 Level: beginner 3631 3632 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3633 @*/ 3634 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3635 { 3636 PetscFunctionBeginHot; 3637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3638 if (numPoints) PetscValidIntPointer(numPoints, 4); 3639 if (points) PetscValidPointer(points, 5); 3640 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3641 PetscFunctionReturn(0); 3642 } 3643 3644 /*@C 3645 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3646 3647 Not collective 3648 3649 Input Parameters: 3650 + dm - The DMPlex 3651 . p - The mesh point 3652 . useCone - PETSC_TRUE for the closure, otherwise return the star 3653 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3654 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3655 3656 Note: 3657 If not using internal storage (points is not NULL on input), this call is unnecessary 3658 3659 Fortran Notes: 3660 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3661 3662 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3663 3664 Level: beginner 3665 3666 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3667 @*/ 3668 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3669 { 3670 PetscFunctionBeginHot; 3671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3672 if (numPoints) *numPoints = 0; 3673 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3674 PetscFunctionReturn(0); 3675 } 3676 3677 /*@ 3678 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3679 3680 Not collective 3681 3682 Input Parameter: 3683 . mesh - The DMPlex 3684 3685 Output Parameters: 3686 + maxConeSize - The maximum number of in-edges 3687 - maxSupportSize - The maximum number of out-edges 3688 3689 Level: beginner 3690 3691 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3692 @*/ 3693 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3694 { 3695 DM_Plex *mesh = (DM_Plex*) dm->data; 3696 3697 PetscFunctionBegin; 3698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3699 if (maxConeSize) { 3700 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3701 } 3702 if (maxSupportSize) { 3703 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3704 } 3705 PetscFunctionReturn(0); 3706 } 3707 3708 PetscErrorCode DMSetUp_Plex(DM dm) 3709 { 3710 DM_Plex *mesh = (DM_Plex*) dm->data; 3711 PetscInt size, maxSupportSize; 3712 3713 PetscFunctionBegin; 3714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3715 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3716 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3717 PetscCall(PetscMalloc1(size, &mesh->cones)); 3718 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3719 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3720 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3721 if (maxSupportSize) { 3722 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3723 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3724 PetscCall(PetscMalloc1(size, &mesh->supports)); 3725 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3726 } 3727 PetscFunctionReturn(0); 3728 } 3729 3730 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3731 { 3732 PetscFunctionBegin; 3733 if (subdm) PetscCall(DMClone(dm, subdm)); 3734 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3735 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3736 if (dm->useNatural && dm->sfMigration) { 3737 PetscSF sfMigrationInv,sfNatural; 3738 PetscSection section, sectionSeq; 3739 3740 (*subdm)->sfMigration = dm->sfMigration; 3741 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3742 PetscCall(DMGetLocalSection((*subdm), §ion)); 3743 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3744 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3745 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3746 3747 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3748 (*subdm)->sfNatural = sfNatural; 3749 PetscCall(PetscSectionDestroy(§ionSeq)); 3750 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3751 } 3752 PetscFunctionReturn(0); 3753 } 3754 3755 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3756 { 3757 PetscInt i = 0; 3758 3759 PetscFunctionBegin; 3760 PetscCall(DMClone(dms[0], superdm)); 3761 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3762 (*superdm)->useNatural = PETSC_FALSE; 3763 for (i = 0; i < len; i++) { 3764 if (dms[i]->useNatural && dms[i]->sfMigration) { 3765 PetscSF sfMigrationInv,sfNatural; 3766 PetscSection section, sectionSeq; 3767 3768 (*superdm)->sfMigration = dms[i]->sfMigration; 3769 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3770 (*superdm)->useNatural = PETSC_TRUE; 3771 PetscCall(DMGetLocalSection((*superdm), §ion)); 3772 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3773 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3774 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3775 3776 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3777 (*superdm)->sfNatural = sfNatural; 3778 PetscCall(PetscSectionDestroy(§ionSeq)); 3779 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3780 break; 3781 } 3782 } 3783 PetscFunctionReturn(0); 3784 } 3785 3786 /*@ 3787 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3788 3789 Not collective 3790 3791 Input Parameter: 3792 . mesh - The DMPlex 3793 3794 Output Parameter: 3795 3796 Note: 3797 This should be called after all calls to DMPlexSetCone() 3798 3799 Level: beginner 3800 3801 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3802 @*/ 3803 PetscErrorCode DMPlexSymmetrize(DM dm) 3804 { 3805 DM_Plex *mesh = (DM_Plex*) dm->data; 3806 PetscInt *offsets; 3807 PetscInt supportSize; 3808 PetscInt pStart, pEnd, p; 3809 3810 PetscFunctionBegin; 3811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3812 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3813 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3814 /* Calculate support sizes */ 3815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3816 for (p = pStart; p < pEnd; ++p) { 3817 PetscInt dof, off, c; 3818 3819 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3820 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3821 for (c = off; c < off+dof; ++c) { 3822 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3823 } 3824 } 3825 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3826 /* Calculate supports */ 3827 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3828 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3829 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3830 for (p = pStart; p < pEnd; ++p) { 3831 PetscInt dof, off, c; 3832 3833 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3834 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3835 for (c = off; c < off+dof; ++c) { 3836 const PetscInt q = mesh->cones[c]; 3837 PetscInt offS; 3838 3839 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3840 3841 mesh->supports[offS+offsets[q]] = p; 3842 ++offsets[q]; 3843 } 3844 } 3845 PetscCall(PetscFree(offsets)); 3846 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3847 PetscFunctionReturn(0); 3848 } 3849 3850 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3851 { 3852 IS stratumIS; 3853 3854 PetscFunctionBegin; 3855 if (pStart >= pEnd) PetscFunctionReturn(0); 3856 if (PetscDefined(USE_DEBUG)) { 3857 PetscInt qStart, qEnd, numLevels, level; 3858 PetscBool overlap = PETSC_FALSE; 3859 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3860 for (level = 0; level < numLevels; level++) { 3861 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3862 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3863 } 3864 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); 3865 } 3866 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3867 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3868 PetscCall(ISDestroy(&stratumIS)); 3869 PetscFunctionReturn(0); 3870 } 3871 3872 /*@ 3873 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3874 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3875 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3876 the DAG. 3877 3878 Collective on dm 3879 3880 Input Parameter: 3881 . mesh - The DMPlex 3882 3883 Output Parameter: 3884 3885 Notes: 3886 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3887 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3888 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3889 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3890 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3891 3892 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3893 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3894 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 3895 to interpolate only that one (e0), so that 3896 $ cone(c0) = {e0, v2} 3897 $ cone(e0) = {v0, v1} 3898 If DMPlexStratify() is run on this mesh, it will give depths 3899 $ depth 0 = {v0, v1, v2} 3900 $ depth 1 = {e0, c0} 3901 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3902 3903 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3904 3905 Level: beginner 3906 3907 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3908 @*/ 3909 PetscErrorCode DMPlexStratify(DM dm) 3910 { 3911 DM_Plex *mesh = (DM_Plex*) dm->data; 3912 DMLabel label; 3913 PetscInt pStart, pEnd, p; 3914 PetscInt numRoots = 0, numLeaves = 0; 3915 3916 PetscFunctionBegin; 3917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3918 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3919 3920 /* Create depth label */ 3921 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3922 PetscCall(DMCreateLabel(dm, "depth")); 3923 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3924 3925 { 3926 /* Initialize roots and count leaves */ 3927 PetscInt sMin = PETSC_MAX_INT; 3928 PetscInt sMax = PETSC_MIN_INT; 3929 PetscInt coneSize, supportSize; 3930 3931 for (p = pStart; p < pEnd; ++p) { 3932 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3933 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3934 if (!coneSize && supportSize) { 3935 sMin = PetscMin(p, sMin); 3936 sMax = PetscMax(p, sMax); 3937 ++numRoots; 3938 } else if (!supportSize && coneSize) { 3939 ++numLeaves; 3940 } else if (!supportSize && !coneSize) { 3941 /* Isolated points */ 3942 sMin = PetscMin(p, sMin); 3943 sMax = PetscMax(p, sMax); 3944 } 3945 } 3946 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3947 } 3948 3949 if (numRoots + numLeaves == (pEnd - pStart)) { 3950 PetscInt sMin = PETSC_MAX_INT; 3951 PetscInt sMax = PETSC_MIN_INT; 3952 PetscInt coneSize, supportSize; 3953 3954 for (p = pStart; p < pEnd; ++p) { 3955 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3956 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3957 if (!supportSize && coneSize) { 3958 sMin = PetscMin(p, sMin); 3959 sMax = PetscMax(p, sMax); 3960 } 3961 } 3962 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3963 } else { 3964 PetscInt level = 0; 3965 PetscInt qStart, qEnd, q; 3966 3967 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3968 while (qEnd > qStart) { 3969 PetscInt sMin = PETSC_MAX_INT; 3970 PetscInt sMax = PETSC_MIN_INT; 3971 3972 for (q = qStart; q < qEnd; ++q) { 3973 const PetscInt *support; 3974 PetscInt supportSize, s; 3975 3976 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3977 PetscCall(DMPlexGetSupport(dm, q, &support)); 3978 for (s = 0; s < supportSize; ++s) { 3979 sMin = PetscMin(support[s], sMin); 3980 sMax = PetscMax(support[s], sMax); 3981 } 3982 } 3983 PetscCall(DMLabelGetNumValues(label, &level)); 3984 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 3985 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3986 } 3987 } 3988 { /* just in case there is an empty process */ 3989 PetscInt numValues, maxValues = 0, v; 3990 3991 PetscCall(DMLabelGetNumValues(label, &numValues)); 3992 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 3993 for (v = numValues; v < maxValues; v++) { 3994 PetscCall(DMLabelAddStratum(label, v)); 3995 } 3996 } 3997 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 3998 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 3999 PetscFunctionReturn(0); 4000 } 4001 4002 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4003 { 4004 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4005 PetscInt dim, depth, pheight, coneSize; 4006 4007 PetscFunctionBeginHot; 4008 PetscCall(DMGetDimension(dm, &dim)); 4009 PetscCall(DMPlexGetDepth(dm, &depth)); 4010 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4011 pheight = depth - pdepth; 4012 if (depth <= 1) { 4013 switch (pdepth) { 4014 case 0: ct = DM_POLYTOPE_POINT;break; 4015 case 1: 4016 switch (coneSize) { 4017 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4018 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4019 case 4: 4020 switch (dim) { 4021 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4022 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4023 default: break; 4024 } 4025 break; 4026 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4027 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4028 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4029 default: break; 4030 } 4031 } 4032 } else { 4033 if (pdepth == 0) { 4034 ct = DM_POLYTOPE_POINT; 4035 } else if (pheight == 0) { 4036 switch (dim) { 4037 case 1: 4038 switch (coneSize) { 4039 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4040 default: break; 4041 } 4042 break; 4043 case 2: 4044 switch (coneSize) { 4045 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4046 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4047 default: break; 4048 } 4049 break; 4050 case 3: 4051 switch (coneSize) { 4052 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4053 case 5: 4054 { 4055 const PetscInt *cone; 4056 PetscInt faceConeSize; 4057 4058 PetscCall(DMPlexGetCone(dm, p, &cone)); 4059 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4060 switch (faceConeSize) { 4061 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4062 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4063 } 4064 } 4065 break; 4066 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4067 default: break; 4068 } 4069 break; 4070 default: break; 4071 } 4072 } else if (pheight > 0) { 4073 switch (coneSize) { 4074 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4075 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4076 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4077 default: break; 4078 } 4079 } 4080 } 4081 *pt = ct; 4082 PetscFunctionReturn(0); 4083 } 4084 4085 /*@ 4086 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4087 4088 Collective on dm 4089 4090 Input Parameter: 4091 . mesh - The DMPlex 4092 4093 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4094 4095 Level: developer 4096 4097 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4098 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4099 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4100 4101 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4102 @*/ 4103 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4104 { 4105 DM_Plex *mesh; 4106 DMLabel ctLabel; 4107 PetscInt pStart, pEnd, p; 4108 4109 PetscFunctionBegin; 4110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4111 mesh = (DM_Plex *) dm->data; 4112 PetscCall(DMCreateLabel(dm, "celltype")); 4113 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4114 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4115 for (p = pStart; p < pEnd; ++p) { 4116 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4117 PetscInt pdepth; 4118 4119 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4120 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4121 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4122 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4123 } 4124 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4125 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4126 PetscFunctionReturn(0); 4127 } 4128 4129 /*@C 4130 DMPlexGetJoin - Get an array for the join of the set of points 4131 4132 Not Collective 4133 4134 Input Parameters: 4135 + dm - The DMPlex object 4136 . numPoints - The number of input points for the join 4137 - points - The input points 4138 4139 Output Parameters: 4140 + numCoveredPoints - The number of points in the join 4141 - coveredPoints - The points in the join 4142 4143 Level: intermediate 4144 4145 Note: Currently, this is restricted to a single level join 4146 4147 Fortran Notes: 4148 Since it returns an array, this routine is only available in Fortran 90, and you must 4149 include petsc.h90 in your code. 4150 4151 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4152 4153 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4154 @*/ 4155 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4156 { 4157 DM_Plex *mesh = (DM_Plex*) dm->data; 4158 PetscInt *join[2]; 4159 PetscInt joinSize, i = 0; 4160 PetscInt dof, off, p, c, m; 4161 PetscInt maxSupportSize; 4162 4163 PetscFunctionBegin; 4164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4165 PetscValidIntPointer(points, 3); 4166 PetscValidIntPointer(numCoveredPoints, 4); 4167 PetscValidPointer(coveredPoints, 5); 4168 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4169 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4170 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4171 /* Copy in support of first point */ 4172 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4173 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4174 for (joinSize = 0; joinSize < dof; ++joinSize) { 4175 join[i][joinSize] = mesh->supports[off+joinSize]; 4176 } 4177 /* Check each successive support */ 4178 for (p = 1; p < numPoints; ++p) { 4179 PetscInt newJoinSize = 0; 4180 4181 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4182 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4183 for (c = 0; c < dof; ++c) { 4184 const PetscInt point = mesh->supports[off+c]; 4185 4186 for (m = 0; m < joinSize; ++m) { 4187 if (point == join[i][m]) { 4188 join[1-i][newJoinSize++] = point; 4189 break; 4190 } 4191 } 4192 } 4193 joinSize = newJoinSize; 4194 i = 1-i; 4195 } 4196 *numCoveredPoints = joinSize; 4197 *coveredPoints = join[i]; 4198 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4199 PetscFunctionReturn(0); 4200 } 4201 4202 /*@C 4203 DMPlexRestoreJoin - Restore an array for the join of the set of points 4204 4205 Not Collective 4206 4207 Input Parameters: 4208 + dm - The DMPlex object 4209 . numPoints - The number of input points for the join 4210 - points - The input points 4211 4212 Output Parameters: 4213 + numCoveredPoints - The number of points in the join 4214 - coveredPoints - The points in the join 4215 4216 Fortran Notes: 4217 Since it returns an array, this routine is only available in Fortran 90, and you must 4218 include petsc.h90 in your code. 4219 4220 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4221 4222 Level: intermediate 4223 4224 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4225 @*/ 4226 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4227 { 4228 PetscFunctionBegin; 4229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4230 if (points) PetscValidIntPointer(points,3); 4231 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4232 PetscValidPointer(coveredPoints, 5); 4233 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4234 if (numCoveredPoints) *numCoveredPoints = 0; 4235 PetscFunctionReturn(0); 4236 } 4237 4238 /*@C 4239 DMPlexGetFullJoin - Get an array for the join of the set of points 4240 4241 Not Collective 4242 4243 Input Parameters: 4244 + dm - The DMPlex object 4245 . numPoints - The number of input points for the join 4246 - points - The input points 4247 4248 Output Parameters: 4249 + numCoveredPoints - The number of points in the join 4250 - coveredPoints - The points in the join 4251 4252 Fortran Notes: 4253 Since it returns an array, this routine is only available in Fortran 90, and you must 4254 include petsc.h90 in your code. 4255 4256 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4257 4258 Level: intermediate 4259 4260 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4261 @*/ 4262 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4263 { 4264 PetscInt *offsets, **closures; 4265 PetscInt *join[2]; 4266 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4267 PetscInt p, d, c, m, ms; 4268 4269 PetscFunctionBegin; 4270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4271 PetscValidIntPointer(points, 3); 4272 PetscValidIntPointer(numCoveredPoints, 4); 4273 PetscValidPointer(coveredPoints, 5); 4274 4275 PetscCall(DMPlexGetDepth(dm, &depth)); 4276 PetscCall(PetscCalloc1(numPoints, &closures)); 4277 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4278 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4279 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4280 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4281 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4282 4283 for (p = 0; p < numPoints; ++p) { 4284 PetscInt closureSize; 4285 4286 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4287 4288 offsets[p*(depth+2)+0] = 0; 4289 for (d = 0; d < depth+1; ++d) { 4290 PetscInt pStart, pEnd, i; 4291 4292 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4293 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4294 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4295 offsets[p*(depth+2)+d+1] = i; 4296 break; 4297 } 4298 } 4299 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4300 } 4301 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); 4302 } 4303 for (d = 0; d < depth+1; ++d) { 4304 PetscInt dof; 4305 4306 /* Copy in support of first point */ 4307 dof = offsets[d+1] - offsets[d]; 4308 for (joinSize = 0; joinSize < dof; ++joinSize) { 4309 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4310 } 4311 /* Check each successive cone */ 4312 for (p = 1; p < numPoints && joinSize; ++p) { 4313 PetscInt newJoinSize = 0; 4314 4315 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4316 for (c = 0; c < dof; ++c) { 4317 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4318 4319 for (m = 0; m < joinSize; ++m) { 4320 if (point == join[i][m]) { 4321 join[1-i][newJoinSize++] = point; 4322 break; 4323 } 4324 } 4325 } 4326 joinSize = newJoinSize; 4327 i = 1-i; 4328 } 4329 if (joinSize) break; 4330 } 4331 *numCoveredPoints = joinSize; 4332 *coveredPoints = join[i]; 4333 for (p = 0; p < numPoints; ++p) { 4334 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4335 } 4336 PetscCall(PetscFree(closures)); 4337 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4338 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4339 PetscFunctionReturn(0); 4340 } 4341 4342 /*@C 4343 DMPlexGetMeet - Get an array for the meet of the set of points 4344 4345 Not Collective 4346 4347 Input Parameters: 4348 + dm - The DMPlex object 4349 . numPoints - The number of input points for the meet 4350 - points - The input points 4351 4352 Output Parameters: 4353 + numCoveredPoints - The number of points in the meet 4354 - coveredPoints - The points in the meet 4355 4356 Level: intermediate 4357 4358 Note: Currently, this is restricted to a single level meet 4359 4360 Fortran Notes: 4361 Since it returns an array, this routine is only available in Fortran 90, and you must 4362 include petsc.h90 in your code. 4363 4364 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4365 4366 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4367 @*/ 4368 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4369 { 4370 DM_Plex *mesh = (DM_Plex*) dm->data; 4371 PetscInt *meet[2]; 4372 PetscInt meetSize, i = 0; 4373 PetscInt dof, off, p, c, m; 4374 PetscInt maxConeSize; 4375 4376 PetscFunctionBegin; 4377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4378 PetscValidIntPointer(points, 3); 4379 PetscValidIntPointer(numCoveringPoints, 4); 4380 PetscValidPointer(coveringPoints, 5); 4381 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4382 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4383 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4384 /* Copy in cone of first point */ 4385 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4386 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4387 for (meetSize = 0; meetSize < dof; ++meetSize) { 4388 meet[i][meetSize] = mesh->cones[off+meetSize]; 4389 } 4390 /* Check each successive cone */ 4391 for (p = 1; p < numPoints; ++p) { 4392 PetscInt newMeetSize = 0; 4393 4394 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4395 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4396 for (c = 0; c < dof; ++c) { 4397 const PetscInt point = mesh->cones[off+c]; 4398 4399 for (m = 0; m < meetSize; ++m) { 4400 if (point == meet[i][m]) { 4401 meet[1-i][newMeetSize++] = point; 4402 break; 4403 } 4404 } 4405 } 4406 meetSize = newMeetSize; 4407 i = 1-i; 4408 } 4409 *numCoveringPoints = meetSize; 4410 *coveringPoints = meet[i]; 4411 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4412 PetscFunctionReturn(0); 4413 } 4414 4415 /*@C 4416 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4417 4418 Not Collective 4419 4420 Input Parameters: 4421 + dm - The DMPlex object 4422 . numPoints - The number of input points for the meet 4423 - points - The input points 4424 4425 Output Parameters: 4426 + numCoveredPoints - The number of points in the meet 4427 - coveredPoints - The points in the meet 4428 4429 Level: intermediate 4430 4431 Fortran Notes: 4432 Since it returns an array, this routine is only available in Fortran 90, and you must 4433 include petsc.h90 in your code. 4434 4435 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4436 4437 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4438 @*/ 4439 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4440 { 4441 PetscFunctionBegin; 4442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4443 if (points) PetscValidIntPointer(points,3); 4444 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4445 PetscValidPointer(coveredPoints,5); 4446 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4447 if (numCoveredPoints) *numCoveredPoints = 0; 4448 PetscFunctionReturn(0); 4449 } 4450 4451 /*@C 4452 DMPlexGetFullMeet - Get an array for the meet of the set of points 4453 4454 Not Collective 4455 4456 Input Parameters: 4457 + dm - The DMPlex object 4458 . numPoints - The number of input points for the meet 4459 - points - The input points 4460 4461 Output Parameters: 4462 + numCoveredPoints - The number of points in the meet 4463 - coveredPoints - The points in the meet 4464 4465 Level: intermediate 4466 4467 Fortran Notes: 4468 Since it returns an array, this routine is only available in Fortran 90, and you must 4469 include petsc.h90 in your code. 4470 4471 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4472 4473 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4474 @*/ 4475 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4476 { 4477 PetscInt *offsets, **closures; 4478 PetscInt *meet[2]; 4479 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4480 PetscInt p, h, c, m, mc; 4481 4482 PetscFunctionBegin; 4483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4484 PetscValidIntPointer(points, 3); 4485 PetscValidIntPointer(numCoveredPoints, 4); 4486 PetscValidPointer(coveredPoints, 5); 4487 4488 PetscCall(DMPlexGetDepth(dm, &height)); 4489 PetscCall(PetscMalloc1(numPoints, &closures)); 4490 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4491 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4492 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4493 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4494 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4495 4496 for (p = 0; p < numPoints; ++p) { 4497 PetscInt closureSize; 4498 4499 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4500 4501 offsets[p*(height+2)+0] = 0; 4502 for (h = 0; h < height+1; ++h) { 4503 PetscInt pStart, pEnd, i; 4504 4505 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4506 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4507 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4508 offsets[p*(height+2)+h+1] = i; 4509 break; 4510 } 4511 } 4512 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4513 } 4514 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); 4515 } 4516 for (h = 0; h < height+1; ++h) { 4517 PetscInt dof; 4518 4519 /* Copy in cone of first point */ 4520 dof = offsets[h+1] - offsets[h]; 4521 for (meetSize = 0; meetSize < dof; ++meetSize) { 4522 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4523 } 4524 /* Check each successive cone */ 4525 for (p = 1; p < numPoints && meetSize; ++p) { 4526 PetscInt newMeetSize = 0; 4527 4528 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4529 for (c = 0; c < dof; ++c) { 4530 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4531 4532 for (m = 0; m < meetSize; ++m) { 4533 if (point == meet[i][m]) { 4534 meet[1-i][newMeetSize++] = point; 4535 break; 4536 } 4537 } 4538 } 4539 meetSize = newMeetSize; 4540 i = 1-i; 4541 } 4542 if (meetSize) break; 4543 } 4544 *numCoveredPoints = meetSize; 4545 *coveredPoints = meet[i]; 4546 for (p = 0; p < numPoints; ++p) { 4547 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4548 } 4549 PetscCall(PetscFree(closures)); 4550 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4551 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4552 PetscFunctionReturn(0); 4553 } 4554 4555 /*@C 4556 DMPlexEqual - Determine if two DMs have the same topology 4557 4558 Not Collective 4559 4560 Input Parameters: 4561 + dmA - A DMPlex object 4562 - dmB - A DMPlex object 4563 4564 Output Parameters: 4565 . equal - PETSC_TRUE if the topologies are identical 4566 4567 Level: intermediate 4568 4569 Notes: 4570 We are not solving graph isomorphism, so we do not permutation. 4571 4572 .seealso: `DMPlexGetCone()` 4573 @*/ 4574 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4575 { 4576 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4577 4578 PetscFunctionBegin; 4579 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4580 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4581 PetscValidBoolPointer(equal, 3); 4582 4583 *equal = PETSC_FALSE; 4584 PetscCall(DMPlexGetDepth(dmA, &depth)); 4585 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4586 if (depth != depthB) PetscFunctionReturn(0); 4587 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4588 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4589 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4590 for (p = pStart; p < pEnd; ++p) { 4591 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4592 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4593 4594 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4595 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4596 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4597 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4598 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4599 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4600 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4601 for (c = 0; c < coneSize; ++c) { 4602 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4603 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4604 } 4605 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4606 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4607 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4608 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4609 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4610 for (s = 0; s < supportSize; ++s) { 4611 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4612 } 4613 } 4614 *equal = PETSC_TRUE; 4615 PetscFunctionReturn(0); 4616 } 4617 4618 /*@C 4619 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4620 4621 Not Collective 4622 4623 Input Parameters: 4624 + dm - The DMPlex 4625 . cellDim - The cell dimension 4626 - numCorners - The number of vertices on a cell 4627 4628 Output Parameters: 4629 . numFaceVertices - The number of vertices on a face 4630 4631 Level: developer 4632 4633 Notes: 4634 Of course this can only work for a restricted set of symmetric shapes 4635 4636 .seealso: `DMPlexGetCone()` 4637 @*/ 4638 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4639 { 4640 MPI_Comm comm; 4641 4642 PetscFunctionBegin; 4643 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4644 PetscValidIntPointer(numFaceVertices,4); 4645 switch (cellDim) { 4646 case 0: 4647 *numFaceVertices = 0; 4648 break; 4649 case 1: 4650 *numFaceVertices = 1; 4651 break; 4652 case 2: 4653 switch (numCorners) { 4654 case 3: /* triangle */ 4655 *numFaceVertices = 2; /* Edge has 2 vertices */ 4656 break; 4657 case 4: /* quadrilateral */ 4658 *numFaceVertices = 2; /* Edge has 2 vertices */ 4659 break; 4660 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4661 *numFaceVertices = 3; /* Edge has 3 vertices */ 4662 break; 4663 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4664 *numFaceVertices = 3; /* Edge has 3 vertices */ 4665 break; 4666 default: 4667 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4668 } 4669 break; 4670 case 3: 4671 switch (numCorners) { 4672 case 4: /* tetradehdron */ 4673 *numFaceVertices = 3; /* Face has 3 vertices */ 4674 break; 4675 case 6: /* tet cohesive cells */ 4676 *numFaceVertices = 4; /* Face has 4 vertices */ 4677 break; 4678 case 8: /* hexahedron */ 4679 *numFaceVertices = 4; /* Face has 4 vertices */ 4680 break; 4681 case 9: /* tet cohesive Lagrange cells */ 4682 *numFaceVertices = 6; /* Face has 6 vertices */ 4683 break; 4684 case 10: /* quadratic tetrahedron */ 4685 *numFaceVertices = 6; /* Face has 6 vertices */ 4686 break; 4687 case 12: /* hex cohesive Lagrange cells */ 4688 *numFaceVertices = 6; /* Face has 6 vertices */ 4689 break; 4690 case 18: /* quadratic tet cohesive Lagrange cells */ 4691 *numFaceVertices = 6; /* Face has 6 vertices */ 4692 break; 4693 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4694 *numFaceVertices = 9; /* Face has 9 vertices */ 4695 break; 4696 default: 4697 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4698 } 4699 break; 4700 default: 4701 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4702 } 4703 PetscFunctionReturn(0); 4704 } 4705 4706 /*@ 4707 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4708 4709 Not Collective 4710 4711 Input Parameter: 4712 . dm - The DMPlex object 4713 4714 Output Parameter: 4715 . depthLabel - The DMLabel recording point depth 4716 4717 Level: developer 4718 4719 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4720 @*/ 4721 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4722 { 4723 PetscFunctionBegin; 4724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4725 PetscValidPointer(depthLabel, 2); 4726 *depthLabel = dm->depthLabel; 4727 PetscFunctionReturn(0); 4728 } 4729 4730 /*@ 4731 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4732 4733 Not Collective 4734 4735 Input Parameter: 4736 . dm - The DMPlex object 4737 4738 Output Parameter: 4739 . depth - The number of strata (breadth first levels) in the DAG 4740 4741 Level: developer 4742 4743 Notes: 4744 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4745 The point depth is described more in detail in DMPlexGetDepthStratum(). 4746 An empty mesh gives -1. 4747 4748 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4749 @*/ 4750 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4751 { 4752 DMLabel label; 4753 PetscInt d = 0; 4754 4755 PetscFunctionBegin; 4756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4757 PetscValidIntPointer(depth, 2); 4758 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4759 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4760 *depth = d-1; 4761 PetscFunctionReturn(0); 4762 } 4763 4764 /*@ 4765 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4766 4767 Not Collective 4768 4769 Input Parameters: 4770 + dm - The DMPlex object 4771 - stratumValue - The requested depth 4772 4773 Output Parameters: 4774 + start - The first point at this depth 4775 - end - One beyond the last point at this depth 4776 4777 Notes: 4778 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4779 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4780 higher dimension, e.g., "edges". 4781 4782 Level: developer 4783 4784 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4785 @*/ 4786 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4787 { 4788 DMLabel label; 4789 PetscInt pStart, pEnd; 4790 4791 PetscFunctionBegin; 4792 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4793 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4794 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4795 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4796 if (pStart == pEnd) PetscFunctionReturn(0); 4797 if (stratumValue < 0) { 4798 if (start) *start = pStart; 4799 if (end) *end = pEnd; 4800 PetscFunctionReturn(0); 4801 } 4802 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4803 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4804 PetscCall(DMLabelGetStratumBounds(label, stratumValue, start, end)); 4805 PetscFunctionReturn(0); 4806 } 4807 4808 /*@ 4809 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4810 4811 Not Collective 4812 4813 Input Parameters: 4814 + dm - The DMPlex object 4815 - stratumValue - The requested height 4816 4817 Output Parameters: 4818 + start - The first point at this height 4819 - end - One beyond the last point at this height 4820 4821 Notes: 4822 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4823 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4824 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4825 4826 Level: developer 4827 4828 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4829 @*/ 4830 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4831 { 4832 DMLabel label; 4833 PetscInt depth, pStart, pEnd; 4834 4835 PetscFunctionBegin; 4836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4837 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4838 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4840 if (pStart == pEnd) PetscFunctionReturn(0); 4841 if (stratumValue < 0) { 4842 if (start) *start = pStart; 4843 if (end) *end = pEnd; 4844 PetscFunctionReturn(0); 4845 } 4846 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4847 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4848 PetscCall(DMLabelGetNumValues(label, &depth)); 4849 PetscCall(DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end)); 4850 PetscFunctionReturn(0); 4851 } 4852 4853 /*@ 4854 DMPlexGetPointDepth - Get the depth of a given point 4855 4856 Not Collective 4857 4858 Input Parameters: 4859 + dm - The DMPlex object 4860 - point - The point 4861 4862 Output Parameter: 4863 . depth - The depth of the point 4864 4865 Level: intermediate 4866 4867 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4868 @*/ 4869 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4870 { 4871 PetscFunctionBegin; 4872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4873 PetscValidIntPointer(depth, 3); 4874 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4875 PetscFunctionReturn(0); 4876 } 4877 4878 /*@ 4879 DMPlexGetPointHeight - Get the height of a given point 4880 4881 Not Collective 4882 4883 Input Parameters: 4884 + dm - The DMPlex object 4885 - point - The point 4886 4887 Output Parameter: 4888 . height - The height of the point 4889 4890 Level: intermediate 4891 4892 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4893 @*/ 4894 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4895 { 4896 PetscInt n, pDepth; 4897 4898 PetscFunctionBegin; 4899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4900 PetscValidIntPointer(height, 3); 4901 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4902 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4903 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4909 4910 Not Collective 4911 4912 Input Parameter: 4913 . dm - The DMPlex object 4914 4915 Output Parameter: 4916 . celltypeLabel - The DMLabel recording cell polytope type 4917 4918 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4919 DMCreateLabel(dm, "celltype") beforehand. 4920 4921 Level: developer 4922 4923 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4924 @*/ 4925 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4926 { 4927 PetscFunctionBegin; 4928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4929 PetscValidPointer(celltypeLabel, 2); 4930 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4931 *celltypeLabel = dm->celltypeLabel; 4932 PetscFunctionReturn(0); 4933 } 4934 4935 /*@ 4936 DMPlexGetCellType - Get the polytope type of a given cell 4937 4938 Not Collective 4939 4940 Input Parameters: 4941 + dm - The DMPlex object 4942 - cell - The cell 4943 4944 Output Parameter: 4945 . celltype - The polytope type of the cell 4946 4947 Level: intermediate 4948 4949 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4950 @*/ 4951 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4952 { 4953 DMLabel label; 4954 PetscInt ct; 4955 4956 PetscFunctionBegin; 4957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4958 PetscValidPointer(celltype, 3); 4959 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4960 PetscCall(DMLabelGetValue(label, cell, &ct)); 4961 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4962 *celltype = (DMPolytopeType) ct; 4963 PetscFunctionReturn(0); 4964 } 4965 4966 /*@ 4967 DMPlexSetCellType - Set the polytope type of a given cell 4968 4969 Not Collective 4970 4971 Input Parameters: 4972 + dm - The DMPlex object 4973 . cell - The cell 4974 - celltype - The polytope type of the cell 4975 4976 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4977 is executed. This function will override the computed type. However, if automatic classification will not succeed 4978 and a user wants to manually specify all types, the classification must be disabled by calling 4979 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4980 4981 Level: advanced 4982 4983 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4984 @*/ 4985 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 4986 { 4987 DMLabel label; 4988 4989 PetscFunctionBegin; 4990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4991 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4992 PetscCall(DMLabelSetValue(label, cell, celltype)); 4993 PetscFunctionReturn(0); 4994 } 4995 4996 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 4997 { 4998 PetscSection section, s; 4999 Mat m; 5000 PetscInt maxHeight; 5001 5002 PetscFunctionBegin; 5003 PetscCall(DMClone(dm, cdm)); 5004 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5005 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5006 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5007 PetscCall(DMSetLocalSection(*cdm, section)); 5008 PetscCall(PetscSectionDestroy(§ion)); 5009 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5010 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5011 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5012 PetscCall(PetscSectionDestroy(&s)); 5013 PetscCall(MatDestroy(&m)); 5014 5015 PetscCall(DMSetNumFields(*cdm, 1)); 5016 PetscCall(DMCreateDS(*cdm)); 5017 PetscFunctionReturn(0); 5018 } 5019 5020 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5021 { 5022 Vec coordsLocal; 5023 DM coordsDM; 5024 5025 PetscFunctionBegin; 5026 *field = NULL; 5027 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5028 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5029 if (coordsLocal && coordsDM) { 5030 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5031 } 5032 PetscFunctionReturn(0); 5033 } 5034 5035 /*@C 5036 DMPlexGetConeSection - Return a section which describes the layout of cone data 5037 5038 Not Collective 5039 5040 Input Parameters: 5041 . dm - The DMPlex object 5042 5043 Output Parameter: 5044 . section - The PetscSection object 5045 5046 Level: developer 5047 5048 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5049 @*/ 5050 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5051 { 5052 DM_Plex *mesh = (DM_Plex*) dm->data; 5053 5054 PetscFunctionBegin; 5055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5056 if (section) *section = mesh->coneSection; 5057 PetscFunctionReturn(0); 5058 } 5059 5060 /*@C 5061 DMPlexGetSupportSection - Return a section which describes the layout of support data 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 . dm - The DMPlex object 5067 5068 Output Parameter: 5069 . section - The PetscSection object 5070 5071 Level: developer 5072 5073 .seealso: `DMPlexGetConeSection()` 5074 @*/ 5075 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5076 { 5077 DM_Plex *mesh = (DM_Plex*) dm->data; 5078 5079 PetscFunctionBegin; 5080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5081 if (section) *section = mesh->supportSection; 5082 PetscFunctionReturn(0); 5083 } 5084 5085 /*@C 5086 DMPlexGetCones - Return cone data 5087 5088 Not Collective 5089 5090 Input Parameters: 5091 . dm - The DMPlex object 5092 5093 Output Parameter: 5094 . cones - The cone for each point 5095 5096 Level: developer 5097 5098 .seealso: `DMPlexGetConeSection()` 5099 @*/ 5100 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5101 { 5102 DM_Plex *mesh = (DM_Plex*) dm->data; 5103 5104 PetscFunctionBegin; 5105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5106 if (cones) *cones = mesh->cones; 5107 PetscFunctionReturn(0); 5108 } 5109 5110 /*@C 5111 DMPlexGetConeOrientations - Return cone orientation data 5112 5113 Not Collective 5114 5115 Input Parameters: 5116 . dm - The DMPlex object 5117 5118 Output Parameter: 5119 . coneOrientations - The array of cone orientations for all points 5120 5121 Level: developer 5122 5123 Notes: 5124 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5125 5126 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5127 5128 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5129 @*/ 5130 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5131 { 5132 DM_Plex *mesh = (DM_Plex*) dm->data; 5133 5134 PetscFunctionBegin; 5135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5136 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5137 PetscFunctionReturn(0); 5138 } 5139 5140 /******************************** FEM Support **********************************/ 5141 5142 /* 5143 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5144 representing a line in the section. 5145 */ 5146 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5147 { 5148 PetscFunctionBeginHot; 5149 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5150 if (line < 0) { 5151 *k = 0; 5152 *Nc = 0; 5153 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5154 *k = 1; 5155 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5156 /* An order k SEM disc has k-1 dofs on an edge */ 5157 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5158 *k = *k / *Nc + 1; 5159 } 5160 PetscFunctionReturn(0); 5161 } 5162 5163 /*@ 5164 5165 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5166 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5167 section provided (or the section of the DM). 5168 5169 Input Parameters: 5170 + dm - The DM 5171 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5172 - section - The PetscSection to reorder, or NULL for the default section 5173 5174 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5175 degree of the basis. 5176 5177 Example: 5178 A typical interpolated single-quad mesh might order points as 5179 .vb 5180 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5181 5182 v4 -- e6 -- v3 5183 | | 5184 e7 c0 e8 5185 | | 5186 v1 -- e5 -- v2 5187 .ve 5188 5189 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5190 dofs in the order of points, e.g., 5191 .vb 5192 c0 -> [0,1,2,3] 5193 v1 -> [4] 5194 ... 5195 e5 -> [8, 9] 5196 .ve 5197 5198 which corresponds to the dofs 5199 .vb 5200 6 10 11 7 5201 13 2 3 15 5202 12 0 1 14 5203 4 8 9 5 5204 .ve 5205 5206 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5207 .vb 5208 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5209 .ve 5210 5211 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5212 .vb 5213 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5214 .ve 5215 5216 Level: developer 5217 5218 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5219 @*/ 5220 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5221 { 5222 DMLabel label; 5223 PetscInt dim, depth = -1, eStart = -1, Nf; 5224 PetscBool vertexchart; 5225 5226 PetscFunctionBegin; 5227 PetscCall(DMGetDimension(dm, &dim)); 5228 if (dim < 1) PetscFunctionReturn(0); 5229 if (point < 0) { 5230 PetscInt sStart,sEnd; 5231 5232 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5233 point = sEnd-sStart ? sStart : point; 5234 } 5235 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5236 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5237 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5238 if (depth == 1) {eStart = point;} 5239 else if (depth == dim) { 5240 const PetscInt *cone; 5241 5242 PetscCall(DMPlexGetCone(dm, point, &cone)); 5243 if (dim == 2) eStart = cone[0]; 5244 else if (dim == 3) { 5245 const PetscInt *cone2; 5246 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5247 eStart = cone2[0]; 5248 } 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); 5249 } 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); 5250 { /* Determine whether the chart covers all points or just vertices. */ 5251 PetscInt pStart,pEnd,cStart,cEnd; 5252 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5253 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5254 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5255 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5256 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5257 } 5258 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5259 for (PetscInt d=1; d<=dim; d++) { 5260 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5261 PetscInt *perm; 5262 5263 for (f = 0; f < Nf; ++f) { 5264 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5265 size += PetscPowInt(k+1, d)*Nc; 5266 } 5267 PetscCall(PetscMalloc1(size, &perm)); 5268 for (f = 0; f < Nf; ++f) { 5269 switch (d) { 5270 case 1: 5271 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5272 /* 5273 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5274 We want [ vtx0; edge of length k-1; vtx1 ] 5275 */ 5276 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5277 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5278 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5279 foffset = offset; 5280 break; 5281 case 2: 5282 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5283 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5284 /* The SEM order is 5285 5286 v_lb, {e_b}, v_rb, 5287 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5288 v_lt, reverse {e_t}, v_rt 5289 */ 5290 { 5291 const PetscInt of = 0; 5292 const PetscInt oeb = of + PetscSqr(k-1); 5293 const PetscInt oer = oeb + (k-1); 5294 const PetscInt oet = oer + (k-1); 5295 const PetscInt oel = oet + (k-1); 5296 const PetscInt ovlb = oel + (k-1); 5297 const PetscInt ovrb = ovlb + 1; 5298 const PetscInt ovrt = ovrb + 1; 5299 const PetscInt ovlt = ovrt + 1; 5300 PetscInt o; 5301 5302 /* bottom */ 5303 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5304 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5305 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5306 /* middle */ 5307 for (i = 0; i < k-1; ++i) { 5308 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5309 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; 5310 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5311 } 5312 /* top */ 5313 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5314 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5315 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5316 foffset = offset; 5317 } 5318 break; 5319 case 3: 5320 /* The original hex closure is 5321 5322 {c, 5323 f_b, f_t, f_f, f_b, f_r, f_l, 5324 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5325 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5326 */ 5327 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5328 /* The SEM order is 5329 Bottom Slice 5330 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5331 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5332 v_blb, {e_bb}, v_brb, 5333 5334 Middle Slice (j) 5335 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5336 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5337 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5338 5339 Top Slice 5340 v_tlf, {e_tf}, v_trf, 5341 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5342 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5343 */ 5344 { 5345 const PetscInt oc = 0; 5346 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5347 const PetscInt oft = ofb + PetscSqr(k-1); 5348 const PetscInt off = oft + PetscSqr(k-1); 5349 const PetscInt ofk = off + PetscSqr(k-1); 5350 const PetscInt ofr = ofk + PetscSqr(k-1); 5351 const PetscInt ofl = ofr + PetscSqr(k-1); 5352 const PetscInt oebl = ofl + PetscSqr(k-1); 5353 const PetscInt oebb = oebl + (k-1); 5354 const PetscInt oebr = oebb + (k-1); 5355 const PetscInt oebf = oebr + (k-1); 5356 const PetscInt oetf = oebf + (k-1); 5357 const PetscInt oetr = oetf + (k-1); 5358 const PetscInt oetb = oetr + (k-1); 5359 const PetscInt oetl = oetb + (k-1); 5360 const PetscInt oerf = oetl + (k-1); 5361 const PetscInt oelf = oerf + (k-1); 5362 const PetscInt oelb = oelf + (k-1); 5363 const PetscInt oerb = oelb + (k-1); 5364 const PetscInt ovblf = oerb + (k-1); 5365 const PetscInt ovblb = ovblf + 1; 5366 const PetscInt ovbrb = ovblb + 1; 5367 const PetscInt ovbrf = ovbrb + 1; 5368 const PetscInt ovtlf = ovbrf + 1; 5369 const PetscInt ovtrf = ovtlf + 1; 5370 const PetscInt ovtrb = ovtrf + 1; 5371 const PetscInt ovtlb = ovtrb + 1; 5372 PetscInt o, n; 5373 5374 /* Bottom Slice */ 5375 /* bottom */ 5376 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5377 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5378 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5379 /* middle */ 5380 for (i = 0; i < k-1; ++i) { 5381 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5382 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;} 5383 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5384 } 5385 /* top */ 5386 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5387 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5388 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5389 5390 /* Middle Slice */ 5391 for (j = 0; j < k-1; ++j) { 5392 /* bottom */ 5393 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5394 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; 5395 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5396 /* middle */ 5397 for (i = 0; i < k-1; ++i) { 5398 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5399 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; 5400 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5401 } 5402 /* top */ 5403 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5404 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; 5405 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5406 } 5407 5408 /* Top Slice */ 5409 /* bottom */ 5410 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5411 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5413 /* middle */ 5414 for (i = 0; i < k-1; ++i) { 5415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5416 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5417 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5418 } 5419 /* top */ 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5421 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5422 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5423 5424 foffset = offset; 5425 } 5426 break; 5427 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5428 } 5429 } 5430 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5431 /* Check permutation */ 5432 { 5433 PetscInt *check; 5434 5435 PetscCall(PetscMalloc1(size, &check)); 5436 for (i = 0; i < size; ++i) { 5437 check[i] = -1; 5438 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5439 } 5440 for (i = 0; i < size; ++i) check[perm[i]] = i; 5441 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5442 PetscCall(PetscFree(check)); 5443 } 5444 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5445 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5446 PetscInt *loc_perm; 5447 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5448 for (PetscInt i=0; i<size; i++) { 5449 loc_perm[i] = perm[i]; 5450 loc_perm[size+i] = size + perm[i]; 5451 } 5452 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5453 } 5454 } 5455 PetscFunctionReturn(0); 5456 } 5457 5458 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5459 { 5460 PetscDS prob; 5461 PetscInt depth, Nf, h; 5462 DMLabel label; 5463 5464 PetscFunctionBeginHot; 5465 PetscCall(DMGetDS(dm, &prob)); 5466 Nf = prob->Nf; 5467 label = dm->depthLabel; 5468 *dspace = NULL; 5469 if (field < Nf) { 5470 PetscObject disc = prob->disc[field]; 5471 5472 if (disc->classid == PETSCFE_CLASSID) { 5473 PetscDualSpace dsp; 5474 5475 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5476 PetscCall(DMLabelGetNumValues(label,&depth)); 5477 PetscCall(DMLabelGetValue(label,point,&h)); 5478 h = depth - 1 - h; 5479 if (h) { 5480 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5481 } else { 5482 *dspace = dsp; 5483 } 5484 } 5485 } 5486 PetscFunctionReturn(0); 5487 } 5488 5489 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5490 { 5491 PetscScalar *array, *vArray; 5492 const PetscInt *cone, *coneO; 5493 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5494 5495 PetscFunctionBeginHot; 5496 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5497 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5498 PetscCall(DMPlexGetCone(dm, point, &cone)); 5499 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5500 if (!values || !*values) { 5501 if ((point >= pStart) && (point < pEnd)) { 5502 PetscInt dof; 5503 5504 PetscCall(PetscSectionGetDof(section, point, &dof)); 5505 size += dof; 5506 } 5507 for (p = 0; p < numPoints; ++p) { 5508 const PetscInt cp = cone[p]; 5509 PetscInt dof; 5510 5511 if ((cp < pStart) || (cp >= pEnd)) continue; 5512 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5513 size += dof; 5514 } 5515 if (!values) { 5516 if (csize) *csize = size; 5517 PetscFunctionReturn(0); 5518 } 5519 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5520 } else { 5521 array = *values; 5522 } 5523 size = 0; 5524 PetscCall(VecGetArray(v, &vArray)); 5525 if ((point >= pStart) && (point < pEnd)) { 5526 PetscInt dof, off, d; 5527 PetscScalar *varr; 5528 5529 PetscCall(PetscSectionGetDof(section, point, &dof)); 5530 PetscCall(PetscSectionGetOffset(section, point, &off)); 5531 varr = &vArray[off]; 5532 for (d = 0; d < dof; ++d, ++offset) { 5533 array[offset] = varr[d]; 5534 } 5535 size += dof; 5536 } 5537 for (p = 0; p < numPoints; ++p) { 5538 const PetscInt cp = cone[p]; 5539 PetscInt o = coneO[p]; 5540 PetscInt dof, off, d; 5541 PetscScalar *varr; 5542 5543 if ((cp < pStart) || (cp >= pEnd)) continue; 5544 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5545 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5546 varr = &vArray[off]; 5547 if (o >= 0) { 5548 for (d = 0; d < dof; ++d, ++offset) { 5549 array[offset] = varr[d]; 5550 } 5551 } else { 5552 for (d = dof-1; d >= 0; --d, ++offset) { 5553 array[offset] = varr[d]; 5554 } 5555 } 5556 size += dof; 5557 } 5558 PetscCall(VecRestoreArray(v, &vArray)); 5559 if (!*values) { 5560 if (csize) *csize = size; 5561 *values = array; 5562 } else { 5563 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5564 *csize = size; 5565 } 5566 PetscFunctionReturn(0); 5567 } 5568 5569 /* Compress out points not in the section */ 5570 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5571 { 5572 const PetscInt np = *numPoints; 5573 PetscInt pStart, pEnd, p, q; 5574 5575 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5576 for (p = 0, q = 0; p < np; ++p) { 5577 const PetscInt r = points[p*2]; 5578 if ((r >= pStart) && (r < pEnd)) { 5579 points[q*2] = r; 5580 points[q*2+1] = points[p*2+1]; 5581 ++q; 5582 } 5583 } 5584 *numPoints = q; 5585 return 0; 5586 } 5587 5588 /* Compressed closure does not apply closure permutation */ 5589 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5590 { 5591 const PetscInt *cla = NULL; 5592 PetscInt np, *pts = NULL; 5593 5594 PetscFunctionBeginHot; 5595 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5596 if (*clPoints) { 5597 PetscInt dof, off; 5598 5599 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5600 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5601 PetscCall(ISGetIndices(*clPoints, &cla)); 5602 np = dof/2; 5603 pts = (PetscInt *) &cla[off]; 5604 } else { 5605 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5606 PetscCall(CompressPoints_Private(section, &np, pts)); 5607 } 5608 *numPoints = np; 5609 *points = pts; 5610 *clp = cla; 5611 PetscFunctionReturn(0); 5612 } 5613 5614 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5615 { 5616 PetscFunctionBeginHot; 5617 if (!*clPoints) { 5618 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5619 } else { 5620 PetscCall(ISRestoreIndices(*clPoints, clp)); 5621 } 5622 *numPoints = 0; 5623 *points = NULL; 5624 *clSec = NULL; 5625 *clPoints = NULL; 5626 *clp = NULL; 5627 PetscFunctionReturn(0); 5628 } 5629 5630 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5631 { 5632 PetscInt offset = 0, p; 5633 const PetscInt **perms = NULL; 5634 const PetscScalar **flips = NULL; 5635 5636 PetscFunctionBeginHot; 5637 *size = 0; 5638 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5639 for (p = 0; p < numPoints; p++) { 5640 const PetscInt point = points[2*p]; 5641 const PetscInt *perm = perms ? perms[p] : NULL; 5642 const PetscScalar *flip = flips ? flips[p] : NULL; 5643 PetscInt dof, off, d; 5644 const PetscScalar *varr; 5645 5646 PetscCall(PetscSectionGetDof(section, point, &dof)); 5647 PetscCall(PetscSectionGetOffset(section, point, &off)); 5648 varr = &vArray[off]; 5649 if (clperm) { 5650 if (perm) { 5651 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5652 } else { 5653 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5654 } 5655 if (flip) { 5656 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5657 } 5658 } else { 5659 if (perm) { 5660 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5661 } else { 5662 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5663 } 5664 if (flip) { 5665 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5666 } 5667 } 5668 offset += dof; 5669 } 5670 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5671 *size = offset; 5672 PetscFunctionReturn(0); 5673 } 5674 5675 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[]) 5676 { 5677 PetscInt offset = 0, f; 5678 5679 PetscFunctionBeginHot; 5680 *size = 0; 5681 for (f = 0; f < numFields; ++f) { 5682 PetscInt p; 5683 const PetscInt **perms = NULL; 5684 const PetscScalar **flips = NULL; 5685 5686 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5687 for (p = 0; p < numPoints; p++) { 5688 const PetscInt point = points[2*p]; 5689 PetscInt fdof, foff, b; 5690 const PetscScalar *varr; 5691 const PetscInt *perm = perms ? perms[p] : NULL; 5692 const PetscScalar *flip = flips ? flips[p] : NULL; 5693 5694 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5695 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5696 varr = &vArray[foff]; 5697 if (clperm) { 5698 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5699 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5700 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5701 } else { 5702 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5703 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5704 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5705 } 5706 offset += fdof; 5707 } 5708 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5709 } 5710 *size = offset; 5711 PetscFunctionReturn(0); 5712 } 5713 5714 /*@C 5715 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5716 5717 Not collective 5718 5719 Input Parameters: 5720 + dm - The DM 5721 . section - The section describing the layout in v, or NULL to use the default section 5722 . v - The local vector 5723 - point - The point in the DM 5724 5725 Input/Output Parameters: 5726 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5727 - values - An array to use for the values, or NULL to have it allocated automatically; 5728 if the user provided NULL, it is a borrowed array and should not be freed 5729 5730 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5731 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5732 $ assembly function, and a user may already have allocated storage for this operation. 5733 $ 5734 $ A typical use could be 5735 $ 5736 $ values = NULL; 5737 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5738 $ for (cl = 0; cl < clSize; ++cl) { 5739 $ <Compute on closure> 5740 $ } 5741 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5742 $ 5743 $ or 5744 $ 5745 $ PetscMalloc1(clMaxSize, &values); 5746 $ for (p = pStart; p < pEnd; ++p) { 5747 $ clSize = clMaxSize; 5748 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5749 $ for (cl = 0; cl < clSize; ++cl) { 5750 $ <Compute on closure> 5751 $ } 5752 $ } 5753 $ PetscFree(values); 5754 5755 Fortran Notes: 5756 Since it returns an array, this routine is only available in Fortran 90, and you must 5757 include petsc.h90 in your code. 5758 5759 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5760 5761 Level: intermediate 5762 5763 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5764 @*/ 5765 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5766 { 5767 PetscSection clSection; 5768 IS clPoints; 5769 PetscInt *points = NULL; 5770 const PetscInt *clp, *perm; 5771 PetscInt depth, numFields, numPoints, asize; 5772 5773 PetscFunctionBeginHot; 5774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5775 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5776 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5777 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5778 PetscCall(DMPlexGetDepth(dm, &depth)); 5779 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5780 if (depth == 1 && numFields < 2) { 5781 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5782 PetscFunctionReturn(0); 5783 } 5784 /* Get points */ 5785 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5786 /* Get sizes */ 5787 asize = 0; 5788 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5789 PetscInt dof; 5790 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5791 asize += dof; 5792 } 5793 if (values) { 5794 const PetscScalar *vArray; 5795 PetscInt size; 5796 5797 if (*values) { 5798 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); 5799 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5800 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5801 PetscCall(VecGetArrayRead(v, &vArray)); 5802 /* Get values */ 5803 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5804 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5805 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5806 /* Cleanup array */ 5807 PetscCall(VecRestoreArrayRead(v, &vArray)); 5808 } 5809 if (csize) *csize = asize; 5810 /* Cleanup points */ 5811 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5812 PetscFunctionReturn(0); 5813 } 5814 5815 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5816 { 5817 DMLabel depthLabel; 5818 PetscSection clSection; 5819 IS clPoints; 5820 PetscScalar *array; 5821 const PetscScalar *vArray; 5822 PetscInt *points = NULL; 5823 const PetscInt *clp, *perm = NULL; 5824 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5825 5826 PetscFunctionBeginHot; 5827 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5828 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5829 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5830 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5831 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5832 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5833 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5834 if (mdepth == 1 && numFields < 2) { 5835 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5836 PetscFunctionReturn(0); 5837 } 5838 /* Get points */ 5839 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5840 for (clsize=0,p=0; p<Np; p++) { 5841 PetscInt dof; 5842 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5843 clsize += dof; 5844 } 5845 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5846 /* Filter points */ 5847 for (p = 0; p < numPoints*2; p += 2) { 5848 PetscInt dep; 5849 5850 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5851 if (dep != depth) continue; 5852 points[Np*2+0] = points[p]; 5853 points[Np*2+1] = points[p+1]; 5854 ++Np; 5855 } 5856 /* Get array */ 5857 if (!values || !*values) { 5858 PetscInt asize = 0, dof; 5859 5860 for (p = 0; p < Np*2; p += 2) { 5861 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5862 asize += dof; 5863 } 5864 if (!values) { 5865 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5866 if (csize) *csize = asize; 5867 PetscFunctionReturn(0); 5868 } 5869 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5870 } else { 5871 array = *values; 5872 } 5873 PetscCall(VecGetArrayRead(v, &vArray)); 5874 /* Get values */ 5875 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5876 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5877 /* Cleanup points */ 5878 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5879 /* Cleanup array */ 5880 PetscCall(VecRestoreArrayRead(v, &vArray)); 5881 if (!*values) { 5882 if (csize) *csize = size; 5883 *values = array; 5884 } else { 5885 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5886 *csize = size; 5887 } 5888 PetscFunctionReturn(0); 5889 } 5890 5891 /*@C 5892 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5893 5894 Not collective 5895 5896 Input Parameters: 5897 + dm - The DM 5898 . section - The section describing the layout in v, or NULL to use the default section 5899 . v - The local vector 5900 . point - The point in the DM 5901 . csize - The number of values in the closure, or NULL 5902 - values - The array of values, which is a borrowed array and should not be freed 5903 5904 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5905 5906 Fortran Notes: 5907 Since it returns an array, this routine is only available in Fortran 90, and you must 5908 include petsc.h90 in your code. 5909 5910 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5911 5912 Level: intermediate 5913 5914 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5915 @*/ 5916 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5917 { 5918 PetscInt size = 0; 5919 5920 PetscFunctionBegin; 5921 /* Should work without recalculating size */ 5922 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5923 *values = NULL; 5924 PetscFunctionReturn(0); 5925 } 5926 5927 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5928 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5929 5930 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[]) 5931 { 5932 PetscInt cdof; /* The number of constraints on this point */ 5933 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5934 PetscScalar *a; 5935 PetscInt off, cind = 0, k; 5936 5937 PetscFunctionBegin; 5938 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5939 PetscCall(PetscSectionGetOffset(section, point, &off)); 5940 a = &array[off]; 5941 if (!cdof || setBC) { 5942 if (clperm) { 5943 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5944 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5945 } else { 5946 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5947 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5948 } 5949 } else { 5950 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5951 if (clperm) { 5952 if (perm) {for (k = 0; k < dof; ++k) { 5953 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5954 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5955 } 5956 } else { 5957 for (k = 0; k < dof; ++k) { 5958 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5959 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5960 } 5961 } 5962 } else { 5963 if (perm) { 5964 for (k = 0; k < dof; ++k) { 5965 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5966 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5967 } 5968 } else { 5969 for (k = 0; k < dof; ++k) { 5970 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5971 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5972 } 5973 } 5974 } 5975 } 5976 PetscFunctionReturn(0); 5977 } 5978 5979 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[]) 5980 { 5981 PetscInt cdof; /* The number of constraints on this point */ 5982 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5983 PetscScalar *a; 5984 PetscInt off, cind = 0, k; 5985 5986 PetscFunctionBegin; 5987 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5988 PetscCall(PetscSectionGetOffset(section, point, &off)); 5989 a = &array[off]; 5990 if (cdof) { 5991 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5992 if (clperm) { 5993 if (perm) { 5994 for (k = 0; k < dof; ++k) { 5995 if ((cind < cdof) && (k == cdofs[cind])) { 5996 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5997 cind++; 5998 } 5999 } 6000 } else { 6001 for (k = 0; k < dof; ++k) { 6002 if ((cind < cdof) && (k == cdofs[cind])) { 6003 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6004 cind++; 6005 } 6006 } 6007 } 6008 } else { 6009 if (perm) { 6010 for (k = 0; k < dof; ++k) { 6011 if ((cind < cdof) && (k == cdofs[cind])) { 6012 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6013 cind++; 6014 } 6015 } 6016 } else { 6017 for (k = 0; k < dof; ++k) { 6018 if ((cind < cdof) && (k == cdofs[cind])) { 6019 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6020 cind++; 6021 } 6022 } 6023 } 6024 } 6025 } 6026 PetscFunctionReturn(0); 6027 } 6028 6029 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[]) 6030 { 6031 PetscScalar *a; 6032 PetscInt fdof, foff, fcdof, foffset = *offset; 6033 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6034 PetscInt cind = 0, b; 6035 6036 PetscFunctionBegin; 6037 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6038 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6039 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6040 a = &array[foff]; 6041 if (!fcdof || setBC) { 6042 if (clperm) { 6043 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6044 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6045 } else { 6046 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6047 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6048 } 6049 } else { 6050 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6051 if (clperm) { 6052 if (perm) { 6053 for (b = 0; b < fdof; b++) { 6054 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6055 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6056 } 6057 } else { 6058 for (b = 0; b < fdof; b++) { 6059 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6060 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6061 } 6062 } 6063 } else { 6064 if (perm) { 6065 for (b = 0; b < fdof; b++) { 6066 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6067 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6068 } 6069 } else { 6070 for (b = 0; b < fdof; b++) { 6071 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6072 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6073 } 6074 } 6075 } 6076 } 6077 *offset += fdof; 6078 PetscFunctionReturn(0); 6079 } 6080 6081 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[]) 6082 { 6083 PetscScalar *a; 6084 PetscInt fdof, foff, fcdof, foffset = *offset; 6085 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6086 PetscInt Nc, cind = 0, ncind = 0, b; 6087 PetscBool ncSet, fcSet; 6088 6089 PetscFunctionBegin; 6090 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6091 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6092 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6093 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6094 a = &array[foff]; 6095 if (fcdof) { 6096 /* We just override fcdof and fcdofs with Ncc and comps */ 6097 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6098 if (clperm) { 6099 if (perm) { 6100 if (comps) { 6101 for (b = 0; b < fdof; b++) { 6102 ncSet = fcSet = PETSC_FALSE; 6103 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6104 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6105 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6106 } 6107 } else { 6108 for (b = 0; b < fdof; b++) { 6109 if ((cind < fcdof) && (b == fcdofs[cind])) { 6110 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6111 ++cind; 6112 } 6113 } 6114 } 6115 } else { 6116 if (comps) { 6117 for (b = 0; b < fdof; b++) { 6118 ncSet = fcSet = PETSC_FALSE; 6119 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6120 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6121 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6122 } 6123 } else { 6124 for (b = 0; b < fdof; b++) { 6125 if ((cind < fcdof) && (b == fcdofs[cind])) { 6126 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6127 ++cind; 6128 } 6129 } 6130 } 6131 } 6132 } else { 6133 if (perm) { 6134 if (comps) { 6135 for (b = 0; b < fdof; b++) { 6136 ncSet = fcSet = PETSC_FALSE; 6137 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6138 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6139 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6140 } 6141 } else { 6142 for (b = 0; b < fdof; b++) { 6143 if ((cind < fcdof) && (b == fcdofs[cind])) { 6144 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6145 ++cind; 6146 } 6147 } 6148 } 6149 } else { 6150 if (comps) { 6151 for (b = 0; b < fdof; b++) { 6152 ncSet = fcSet = PETSC_FALSE; 6153 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6154 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6155 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6156 } 6157 } else { 6158 for (b = 0; b < fdof; b++) { 6159 if ((cind < fcdof) && (b == fcdofs[cind])) { 6160 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6161 ++cind; 6162 } 6163 } 6164 } 6165 } 6166 } 6167 } 6168 *offset += fdof; 6169 PetscFunctionReturn(0); 6170 } 6171 6172 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6173 { 6174 PetscScalar *array; 6175 const PetscInt *cone, *coneO; 6176 PetscInt pStart, pEnd, p, numPoints, off, dof; 6177 6178 PetscFunctionBeginHot; 6179 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6180 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6181 PetscCall(DMPlexGetCone(dm, point, &cone)); 6182 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6183 PetscCall(VecGetArray(v, &array)); 6184 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6185 const PetscInt cp = !p ? point : cone[p-1]; 6186 const PetscInt o = !p ? 0 : coneO[p-1]; 6187 6188 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6189 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6190 /* ADD_VALUES */ 6191 { 6192 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6193 PetscScalar *a; 6194 PetscInt cdof, coff, cind = 0, k; 6195 6196 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6197 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6198 a = &array[coff]; 6199 if (!cdof) { 6200 if (o >= 0) { 6201 for (k = 0; k < dof; ++k) { 6202 a[k] += values[off+k]; 6203 } 6204 } else { 6205 for (k = 0; k < dof; ++k) { 6206 a[k] += values[off+dof-k-1]; 6207 } 6208 } 6209 } else { 6210 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6211 if (o >= 0) { 6212 for (k = 0; k < dof; ++k) { 6213 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6214 a[k] += values[off+k]; 6215 } 6216 } else { 6217 for (k = 0; k < dof; ++k) { 6218 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6219 a[k] += values[off+dof-k-1]; 6220 } 6221 } 6222 } 6223 } 6224 } 6225 PetscCall(VecRestoreArray(v, &array)); 6226 PetscFunctionReturn(0); 6227 } 6228 6229 /*@C 6230 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6231 6232 Not collective 6233 6234 Input Parameters: 6235 + dm - The DM 6236 . section - The section describing the layout in v, or NULL to use the default section 6237 . v - The local vector 6238 . point - The point in the DM 6239 . values - The array of values 6240 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6241 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6242 6243 Fortran Notes: 6244 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6245 6246 Level: intermediate 6247 6248 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6249 @*/ 6250 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6251 { 6252 PetscSection clSection; 6253 IS clPoints; 6254 PetscScalar *array; 6255 PetscInt *points = NULL; 6256 const PetscInt *clp, *clperm = NULL; 6257 PetscInt depth, numFields, numPoints, p, clsize; 6258 6259 PetscFunctionBeginHot; 6260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6261 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6262 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6263 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6264 PetscCall(DMPlexGetDepth(dm, &depth)); 6265 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6266 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6267 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6268 PetscFunctionReturn(0); 6269 } 6270 /* Get points */ 6271 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6272 for (clsize=0,p=0; p<numPoints; p++) { 6273 PetscInt dof; 6274 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6275 clsize += dof; 6276 } 6277 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6278 /* Get array */ 6279 PetscCall(VecGetArray(v, &array)); 6280 /* Get values */ 6281 if (numFields > 0) { 6282 PetscInt offset = 0, f; 6283 for (f = 0; f < numFields; ++f) { 6284 const PetscInt **perms = NULL; 6285 const PetscScalar **flips = NULL; 6286 6287 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6288 switch (mode) { 6289 case INSERT_VALUES: 6290 for (p = 0; p < numPoints; p++) { 6291 const PetscInt point = points[2*p]; 6292 const PetscInt *perm = perms ? perms[p] : NULL; 6293 const PetscScalar *flip = flips ? flips[p] : NULL; 6294 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6295 } break; 6296 case INSERT_ALL_VALUES: 6297 for (p = 0; p < numPoints; p++) { 6298 const PetscInt point = points[2*p]; 6299 const PetscInt *perm = perms ? perms[p] : NULL; 6300 const PetscScalar *flip = flips ? flips[p] : NULL; 6301 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6302 } break; 6303 case INSERT_BC_VALUES: 6304 for (p = 0; p < numPoints; p++) { 6305 const PetscInt point = points[2*p]; 6306 const PetscInt *perm = perms ? perms[p] : NULL; 6307 const PetscScalar *flip = flips ? flips[p] : NULL; 6308 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6309 } break; 6310 case ADD_VALUES: 6311 for (p = 0; p < numPoints; p++) { 6312 const PetscInt point = points[2*p]; 6313 const PetscInt *perm = perms ? perms[p] : NULL; 6314 const PetscScalar *flip = flips ? flips[p] : NULL; 6315 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6316 } break; 6317 case ADD_ALL_VALUES: 6318 for (p = 0; p < numPoints; p++) { 6319 const PetscInt point = points[2*p]; 6320 const PetscInt *perm = perms ? perms[p] : NULL; 6321 const PetscScalar *flip = flips ? flips[p] : NULL; 6322 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6323 } break; 6324 case ADD_BC_VALUES: 6325 for (p = 0; p < numPoints; p++) { 6326 const PetscInt point = points[2*p]; 6327 const PetscInt *perm = perms ? perms[p] : NULL; 6328 const PetscScalar *flip = flips ? flips[p] : NULL; 6329 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6330 } break; 6331 default: 6332 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6333 } 6334 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6335 } 6336 } else { 6337 PetscInt dof, off; 6338 const PetscInt **perms = NULL; 6339 const PetscScalar **flips = NULL; 6340 6341 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6342 switch (mode) { 6343 case INSERT_VALUES: 6344 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6345 const PetscInt point = points[2*p]; 6346 const PetscInt *perm = perms ? perms[p] : NULL; 6347 const PetscScalar *flip = flips ? flips[p] : NULL; 6348 PetscCall(PetscSectionGetDof(section, point, &dof)); 6349 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6350 } break; 6351 case INSERT_ALL_VALUES: 6352 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6353 const PetscInt point = points[2*p]; 6354 const PetscInt *perm = perms ? perms[p] : NULL; 6355 const PetscScalar *flip = flips ? flips[p] : NULL; 6356 PetscCall(PetscSectionGetDof(section, point, &dof)); 6357 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6358 } break; 6359 case INSERT_BC_VALUES: 6360 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6361 const PetscInt point = points[2*p]; 6362 const PetscInt *perm = perms ? perms[p] : NULL; 6363 const PetscScalar *flip = flips ? flips[p] : NULL; 6364 PetscCall(PetscSectionGetDof(section, point, &dof)); 6365 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6366 } break; 6367 case ADD_VALUES: 6368 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6369 const PetscInt point = points[2*p]; 6370 const PetscInt *perm = perms ? perms[p] : NULL; 6371 const PetscScalar *flip = flips ? flips[p] : NULL; 6372 PetscCall(PetscSectionGetDof(section, point, &dof)); 6373 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6374 } break; 6375 case ADD_ALL_VALUES: 6376 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6377 const PetscInt point = points[2*p]; 6378 const PetscInt *perm = perms ? perms[p] : NULL; 6379 const PetscScalar *flip = flips ? flips[p] : NULL; 6380 PetscCall(PetscSectionGetDof(section, point, &dof)); 6381 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6382 } break; 6383 case ADD_BC_VALUES: 6384 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6385 const PetscInt point = points[2*p]; 6386 const PetscInt *perm = perms ? perms[p] : NULL; 6387 const PetscScalar *flip = flips ? flips[p] : NULL; 6388 PetscCall(PetscSectionGetDof(section, point, &dof)); 6389 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6390 } break; 6391 default: 6392 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6393 } 6394 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6395 } 6396 /* Cleanup points */ 6397 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6398 /* Cleanup array */ 6399 PetscCall(VecRestoreArray(v, &array)); 6400 PetscFunctionReturn(0); 6401 } 6402 6403 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6404 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6405 { 6406 PetscFunctionBegin; 6407 if (label) { 6408 PetscInt val, fdof; 6409 6410 /* There is a problem with this: 6411 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6412 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6413 Thus I am only going to check val != -1, not val != labelId 6414 */ 6415 PetscCall(DMLabelGetValue(label, point, &val)); 6416 if (val < 0) { 6417 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6418 *offset += fdof; 6419 PetscFunctionReturn(1); 6420 } 6421 } 6422 PetscFunctionReturn(0); 6423 } 6424 6425 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6426 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) 6427 { 6428 PetscSection clSection; 6429 IS clPoints; 6430 PetscScalar *array; 6431 PetscInt *points = NULL; 6432 const PetscInt *clp; 6433 PetscInt numFields, numPoints, p; 6434 PetscInt offset = 0, f; 6435 6436 PetscFunctionBeginHot; 6437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6438 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6439 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6440 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6441 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6442 /* Get points */ 6443 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6444 /* Get array */ 6445 PetscCall(VecGetArray(v, &array)); 6446 /* Get values */ 6447 for (f = 0; f < numFields; ++f) { 6448 const PetscInt **perms = NULL; 6449 const PetscScalar **flips = NULL; 6450 6451 if (!fieldActive[f]) { 6452 for (p = 0; p < numPoints*2; p += 2) { 6453 PetscInt fdof; 6454 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6455 offset += fdof; 6456 } 6457 continue; 6458 } 6459 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6460 switch (mode) { 6461 case INSERT_VALUES: 6462 for (p = 0; p < numPoints; p++) { 6463 const PetscInt point = points[2*p]; 6464 const PetscInt *perm = perms ? perms[p] : NULL; 6465 const PetscScalar *flip = flips ? flips[p] : NULL; 6466 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6467 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6468 } break; 6469 case INSERT_ALL_VALUES: 6470 for (p = 0; p < numPoints; p++) { 6471 const PetscInt point = points[2*p]; 6472 const PetscInt *perm = perms ? perms[p] : NULL; 6473 const PetscScalar *flip = flips ? flips[p] : NULL; 6474 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6475 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6476 } break; 6477 case INSERT_BC_VALUES: 6478 for (p = 0; p < numPoints; p++) { 6479 const PetscInt point = points[2*p]; 6480 const PetscInt *perm = perms ? perms[p] : NULL; 6481 const PetscScalar *flip = flips ? flips[p] : NULL; 6482 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6483 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6484 } break; 6485 case ADD_VALUES: 6486 for (p = 0; p < numPoints; p++) { 6487 const PetscInt point = points[2*p]; 6488 const PetscInt *perm = perms ? perms[p] : NULL; 6489 const PetscScalar *flip = flips ? flips[p] : NULL; 6490 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6491 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6492 } break; 6493 case ADD_ALL_VALUES: 6494 for (p = 0; p < numPoints; p++) { 6495 const PetscInt point = points[2*p]; 6496 const PetscInt *perm = perms ? perms[p] : NULL; 6497 const PetscScalar *flip = flips ? flips[p] : NULL; 6498 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6499 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6500 } break; 6501 default: 6502 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6503 } 6504 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6505 } 6506 /* Cleanup points */ 6507 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6508 /* Cleanup array */ 6509 PetscCall(VecRestoreArray(v, &array)); 6510 PetscFunctionReturn(0); 6511 } 6512 6513 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6514 { 6515 PetscMPIInt rank; 6516 PetscInt i, j; 6517 6518 PetscFunctionBegin; 6519 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6520 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6521 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6522 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6523 numCIndices = numCIndices ? numCIndices : numRIndices; 6524 if (!values) PetscFunctionReturn(0); 6525 for (i = 0; i < numRIndices; i++) { 6526 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6527 for (j = 0; j < numCIndices; j++) { 6528 #if defined(PETSC_USE_COMPLEX) 6529 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6530 #else 6531 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6532 #endif 6533 } 6534 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6535 } 6536 PetscFunctionReturn(0); 6537 } 6538 6539 /* 6540 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6541 6542 Input Parameters: 6543 + section - The section for this data layout 6544 . islocal - Is the section (and thus indices being requested) local or global? 6545 . point - The point contributing dofs with these indices 6546 . off - The global offset of this point 6547 . loff - The local offset of each field 6548 . setBC - The flag determining whether to include indices of boundary values 6549 . perm - A permutation of the dofs on this point, or NULL 6550 - indperm - A permutation of the entire indices array, or NULL 6551 6552 Output Parameter: 6553 . indices - Indices for dofs on this point 6554 6555 Level: developer 6556 6557 Note: The indices could be local or global, depending on the value of 'off'. 6558 */ 6559 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6560 { 6561 PetscInt dof; /* The number of unknowns on this point */ 6562 PetscInt cdof; /* The number of constraints on this point */ 6563 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6564 PetscInt cind = 0, k; 6565 6566 PetscFunctionBegin; 6567 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6568 PetscCall(PetscSectionGetDof(section, point, &dof)); 6569 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6570 if (!cdof || setBC) { 6571 for (k = 0; k < dof; ++k) { 6572 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6573 const PetscInt ind = indperm ? indperm[preind] : preind; 6574 6575 indices[ind] = off + k; 6576 } 6577 } else { 6578 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6579 for (k = 0; k < dof; ++k) { 6580 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6581 const PetscInt ind = indperm ? indperm[preind] : preind; 6582 6583 if ((cind < cdof) && (k == cdofs[cind])) { 6584 /* Insert check for returning constrained indices */ 6585 indices[ind] = -(off+k+1); 6586 ++cind; 6587 } else { 6588 indices[ind] = off + k - (islocal ? 0 : cind); 6589 } 6590 } 6591 } 6592 *loff += dof; 6593 PetscFunctionReturn(0); 6594 } 6595 6596 /* 6597 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6598 6599 Input Parameters: 6600 + section - a section (global or local) 6601 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6602 . point - point within section 6603 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6604 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6605 . setBC - identify constrained (boundary condition) points via involution. 6606 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6607 . permsoff - offset 6608 - indperm - index permutation 6609 6610 Output Parameter: 6611 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6612 . indices - array to hold indices (as defined by section) of each dof associated with point 6613 6614 Notes: 6615 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6616 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6617 in the local vector. 6618 6619 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6620 significant). It is invalid to call with a global section and setBC=true. 6621 6622 Developer Note: 6623 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6624 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6625 offset could be obtained from the section instead of passing it explicitly as we do now. 6626 6627 Example: 6628 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6629 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6630 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6631 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. 6632 6633 Level: developer 6634 */ 6635 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[]) 6636 { 6637 PetscInt numFields, foff, f; 6638 6639 PetscFunctionBegin; 6640 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6641 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6642 for (f = 0, foff = 0; f < numFields; ++f) { 6643 PetscInt fdof, cfdof; 6644 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6645 PetscInt cind = 0, b; 6646 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6647 6648 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6649 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6650 if (!cfdof || setBC) { 6651 for (b = 0; b < fdof; ++b) { 6652 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6653 const PetscInt ind = indperm ? indperm[preind] : preind; 6654 6655 indices[ind] = off+foff+b; 6656 } 6657 } else { 6658 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6659 for (b = 0; b < fdof; ++b) { 6660 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6661 const PetscInt ind = indperm ? indperm[preind] : preind; 6662 6663 if ((cind < cfdof) && (b == fcdofs[cind])) { 6664 indices[ind] = -(off+foff+b+1); 6665 ++cind; 6666 } else { 6667 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6668 } 6669 } 6670 } 6671 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6672 foffs[f] += fdof; 6673 } 6674 PetscFunctionReturn(0); 6675 } 6676 6677 /* 6678 This version believes the globalSection offsets for each field, rather than just the point offset 6679 6680 . foffs - The offset into 'indices' for each field, since it is segregated by field 6681 6682 Notes: 6683 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6684 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6685 */ 6686 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6687 { 6688 PetscInt numFields, foff, f; 6689 6690 PetscFunctionBegin; 6691 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6692 for (f = 0; f < numFields; ++f) { 6693 PetscInt fdof, cfdof; 6694 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6695 PetscInt cind = 0, b; 6696 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6697 6698 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6699 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6700 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6701 if (!cfdof) { 6702 for (b = 0; b < fdof; ++b) { 6703 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6704 const PetscInt ind = indperm ? indperm[preind] : preind; 6705 6706 indices[ind] = foff+b; 6707 } 6708 } else { 6709 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6710 for (b = 0; b < fdof; ++b) { 6711 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6712 const PetscInt ind = indperm ? indperm[preind] : preind; 6713 6714 if ((cind < cfdof) && (b == fcdofs[cind])) { 6715 indices[ind] = -(foff+b+1); 6716 ++cind; 6717 } else { 6718 indices[ind] = foff+b-cind; 6719 } 6720 } 6721 } 6722 foffs[f] += fdof; 6723 } 6724 PetscFunctionReturn(0); 6725 } 6726 6727 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) 6728 { 6729 Mat cMat; 6730 PetscSection aSec, cSec; 6731 IS aIS; 6732 PetscInt aStart = -1, aEnd = -1; 6733 const PetscInt *anchors; 6734 PetscInt numFields, f, p, q, newP = 0; 6735 PetscInt newNumPoints = 0, newNumIndices = 0; 6736 PetscInt *newPoints, *indices, *newIndices; 6737 PetscInt maxAnchor, maxDof; 6738 PetscInt newOffsets[32]; 6739 PetscInt *pointMatOffsets[32]; 6740 PetscInt *newPointOffsets[32]; 6741 PetscScalar *pointMat[32]; 6742 PetscScalar *newValues=NULL,*tmpValues; 6743 PetscBool anyConstrained = PETSC_FALSE; 6744 6745 PetscFunctionBegin; 6746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6747 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6748 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6749 6750 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6751 /* if there are point-to-point constraints */ 6752 if (aSec) { 6753 PetscCall(PetscArrayzero(newOffsets, 32)); 6754 PetscCall(ISGetIndices(aIS,&anchors)); 6755 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6756 /* figure out how many points are going to be in the new element matrix 6757 * (we allow double counting, because it's all just going to be summed 6758 * into the global matrix anyway) */ 6759 for (p = 0; p < 2*numPoints; p+=2) { 6760 PetscInt b = points[p]; 6761 PetscInt bDof = 0, bSecDof; 6762 6763 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6764 if (!bSecDof) { 6765 continue; 6766 } 6767 if (b >= aStart && b < aEnd) { 6768 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6769 } 6770 if (bDof) { 6771 /* this point is constrained */ 6772 /* it is going to be replaced by its anchors */ 6773 PetscInt bOff, q; 6774 6775 anyConstrained = PETSC_TRUE; 6776 newNumPoints += bDof; 6777 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6778 for (q = 0; q < bDof; q++) { 6779 PetscInt a = anchors[bOff + q]; 6780 PetscInt aDof; 6781 6782 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6783 newNumIndices += aDof; 6784 for (f = 0; f < numFields; ++f) { 6785 PetscInt fDof; 6786 6787 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6788 newOffsets[f+1] += fDof; 6789 } 6790 } 6791 } 6792 else { 6793 /* this point is not constrained */ 6794 newNumPoints++; 6795 newNumIndices += bSecDof; 6796 for (f = 0; f < numFields; ++f) { 6797 PetscInt fDof; 6798 6799 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6800 newOffsets[f+1] += fDof; 6801 } 6802 } 6803 } 6804 } 6805 if (!anyConstrained) { 6806 if (outNumPoints) *outNumPoints = 0; 6807 if (outNumIndices) *outNumIndices = 0; 6808 if (outPoints) *outPoints = NULL; 6809 if (outValues) *outValues = NULL; 6810 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6811 PetscFunctionReturn(0); 6812 } 6813 6814 if (outNumPoints) *outNumPoints = newNumPoints; 6815 if (outNumIndices) *outNumIndices = newNumIndices; 6816 6817 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6818 6819 if (!outPoints && !outValues) { 6820 if (offsets) { 6821 for (f = 0; f <= numFields; f++) { 6822 offsets[f] = newOffsets[f]; 6823 } 6824 } 6825 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6826 PetscFunctionReturn(0); 6827 } 6828 6829 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6830 6831 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6832 6833 /* workspaces */ 6834 if (numFields) { 6835 for (f = 0; f < numFields; f++) { 6836 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6837 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6838 } 6839 } 6840 else { 6841 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6842 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6843 } 6844 6845 /* get workspaces for the point-to-point matrices */ 6846 if (numFields) { 6847 PetscInt totalOffset, totalMatOffset; 6848 6849 for (p = 0; p < numPoints; p++) { 6850 PetscInt b = points[2*p]; 6851 PetscInt bDof = 0, bSecDof; 6852 6853 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6854 if (!bSecDof) { 6855 for (f = 0; f < numFields; f++) { 6856 newPointOffsets[f][p + 1] = 0; 6857 pointMatOffsets[f][p + 1] = 0; 6858 } 6859 continue; 6860 } 6861 if (b >= aStart && b < aEnd) { 6862 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6863 } 6864 if (bDof) { 6865 for (f = 0; f < numFields; f++) { 6866 PetscInt fDof, q, bOff, allFDof = 0; 6867 6868 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6869 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6870 for (q = 0; q < bDof; q++) { 6871 PetscInt a = anchors[bOff + q]; 6872 PetscInt aFDof; 6873 6874 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6875 allFDof += aFDof; 6876 } 6877 newPointOffsets[f][p+1] = allFDof; 6878 pointMatOffsets[f][p+1] = fDof * allFDof; 6879 } 6880 } 6881 else { 6882 for (f = 0; f < numFields; f++) { 6883 PetscInt fDof; 6884 6885 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6886 newPointOffsets[f][p+1] = fDof; 6887 pointMatOffsets[f][p+1] = 0; 6888 } 6889 } 6890 } 6891 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6892 newPointOffsets[f][0] = totalOffset; 6893 pointMatOffsets[f][0] = totalMatOffset; 6894 for (p = 0; p < numPoints; p++) { 6895 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6896 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6897 } 6898 totalOffset = newPointOffsets[f][numPoints]; 6899 totalMatOffset = pointMatOffsets[f][numPoints]; 6900 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6901 } 6902 } 6903 else { 6904 for (p = 0; p < numPoints; p++) { 6905 PetscInt b = points[2*p]; 6906 PetscInt bDof = 0, bSecDof; 6907 6908 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6909 if (!bSecDof) { 6910 newPointOffsets[0][p + 1] = 0; 6911 pointMatOffsets[0][p + 1] = 0; 6912 continue; 6913 } 6914 if (b >= aStart && b < aEnd) { 6915 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6916 } 6917 if (bDof) { 6918 PetscInt bOff, q, allDof = 0; 6919 6920 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6921 for (q = 0; q < bDof; q++) { 6922 PetscInt a = anchors[bOff + q], aDof; 6923 6924 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6925 allDof += aDof; 6926 } 6927 newPointOffsets[0][p+1] = allDof; 6928 pointMatOffsets[0][p+1] = bSecDof * allDof; 6929 } 6930 else { 6931 newPointOffsets[0][p+1] = bSecDof; 6932 pointMatOffsets[0][p+1] = 0; 6933 } 6934 } 6935 newPointOffsets[0][0] = 0; 6936 pointMatOffsets[0][0] = 0; 6937 for (p = 0; p < numPoints; p++) { 6938 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6939 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6940 } 6941 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6942 } 6943 6944 /* output arrays */ 6945 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6946 6947 /* get the point-to-point matrices; construct newPoints */ 6948 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6949 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6950 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6951 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6952 if (numFields) { 6953 for (p = 0, newP = 0; p < numPoints; p++) { 6954 PetscInt b = points[2*p]; 6955 PetscInt o = points[2*p+1]; 6956 PetscInt bDof = 0, bSecDof; 6957 6958 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6959 if (!bSecDof) { 6960 continue; 6961 } 6962 if (b >= aStart && b < aEnd) { 6963 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6964 } 6965 if (bDof) { 6966 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6967 6968 fStart[0] = 0; 6969 fEnd[0] = 0; 6970 for (f = 0; f < numFields; f++) { 6971 PetscInt fDof; 6972 6973 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6974 fStart[f+1] = fStart[f] + fDof; 6975 fEnd[f+1] = fStart[f+1]; 6976 } 6977 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6978 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6979 6980 fAnchorStart[0] = 0; 6981 fAnchorEnd[0] = 0; 6982 for (f = 0; f < numFields; f++) { 6983 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6984 6985 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 6986 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 6987 } 6988 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6989 for (q = 0; q < bDof; q++) { 6990 PetscInt a = anchors[bOff + q], aOff; 6991 6992 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6993 newPoints[2*(newP + q)] = a; 6994 newPoints[2*(newP + q) + 1] = 0; 6995 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 6996 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 6997 } 6998 newP += bDof; 6999 7000 if (outValues) { 7001 /* get the point-to-point submatrix */ 7002 for (f = 0; f < numFields; f++) { 7003 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7004 } 7005 } 7006 } 7007 else { 7008 newPoints[2 * newP] = b; 7009 newPoints[2 * newP + 1] = o; 7010 newP++; 7011 } 7012 } 7013 } else { 7014 for (p = 0; p < numPoints; p++) { 7015 PetscInt b = points[2*p]; 7016 PetscInt o = points[2*p+1]; 7017 PetscInt bDof = 0, bSecDof; 7018 7019 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7020 if (!bSecDof) { 7021 continue; 7022 } 7023 if (b >= aStart && b < aEnd) { 7024 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7025 } 7026 if (bDof) { 7027 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7028 7029 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7030 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7031 7032 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7033 for (q = 0; q < bDof; q++) { 7034 PetscInt a = anchors[bOff + q], aOff; 7035 7036 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7037 7038 newPoints[2*(newP + q)] = a; 7039 newPoints[2*(newP + q) + 1] = 0; 7040 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7041 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7042 } 7043 newP += bDof; 7044 7045 /* get the point-to-point submatrix */ 7046 if (outValues) { 7047 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7048 } 7049 } 7050 else { 7051 newPoints[2 * newP] = b; 7052 newPoints[2 * newP + 1] = o; 7053 newP++; 7054 } 7055 } 7056 } 7057 7058 if (outValues) { 7059 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7060 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7061 /* multiply constraints on the right */ 7062 if (numFields) { 7063 for (f = 0; f < numFields; f++) { 7064 PetscInt oldOff = offsets[f]; 7065 7066 for (p = 0; p < numPoints; p++) { 7067 PetscInt cStart = newPointOffsets[f][p]; 7068 PetscInt b = points[2 * p]; 7069 PetscInt c, r, k; 7070 PetscInt dof; 7071 7072 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7073 if (!dof) { 7074 continue; 7075 } 7076 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7077 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7078 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7079 7080 for (r = 0; r < numIndices; r++) { 7081 for (c = 0; c < nCols; c++) { 7082 for (k = 0; k < dof; k++) { 7083 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7084 } 7085 } 7086 } 7087 } 7088 else { 7089 /* copy this column as is */ 7090 for (r = 0; r < numIndices; r++) { 7091 for (c = 0; c < dof; c++) { 7092 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7093 } 7094 } 7095 } 7096 oldOff += dof; 7097 } 7098 } 7099 } 7100 else { 7101 PetscInt oldOff = 0; 7102 for (p = 0; p < numPoints; p++) { 7103 PetscInt cStart = newPointOffsets[0][p]; 7104 PetscInt b = points[2 * p]; 7105 PetscInt c, r, k; 7106 PetscInt dof; 7107 7108 PetscCall(PetscSectionGetDof(section,b,&dof)); 7109 if (!dof) { 7110 continue; 7111 } 7112 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7113 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7114 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7115 7116 for (r = 0; r < numIndices; r++) { 7117 for (c = 0; c < nCols; c++) { 7118 for (k = 0; k < dof; k++) { 7119 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7120 } 7121 } 7122 } 7123 } 7124 else { 7125 /* copy this column as is */ 7126 for (r = 0; r < numIndices; r++) { 7127 for (c = 0; c < dof; c++) { 7128 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7129 } 7130 } 7131 } 7132 oldOff += dof; 7133 } 7134 } 7135 7136 if (multiplyLeft) { 7137 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7138 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7139 /* multiply constraints transpose on the left */ 7140 if (numFields) { 7141 for (f = 0; f < numFields; f++) { 7142 PetscInt oldOff = offsets[f]; 7143 7144 for (p = 0; p < numPoints; p++) { 7145 PetscInt rStart = newPointOffsets[f][p]; 7146 PetscInt b = points[2 * p]; 7147 PetscInt c, r, k; 7148 PetscInt dof; 7149 7150 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7151 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7152 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7153 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7154 7155 for (r = 0; r < nRows; r++) { 7156 for (c = 0; c < newNumIndices; c++) { 7157 for (k = 0; k < dof; k++) { 7158 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7159 } 7160 } 7161 } 7162 } 7163 else { 7164 /* copy this row as is */ 7165 for (r = 0; r < dof; r++) { 7166 for (c = 0; c < newNumIndices; c++) { 7167 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7168 } 7169 } 7170 } 7171 oldOff += dof; 7172 } 7173 } 7174 } 7175 else { 7176 PetscInt oldOff = 0; 7177 7178 for (p = 0; p < numPoints; p++) { 7179 PetscInt rStart = newPointOffsets[0][p]; 7180 PetscInt b = points[2 * p]; 7181 PetscInt c, r, k; 7182 PetscInt dof; 7183 7184 PetscCall(PetscSectionGetDof(section,b,&dof)); 7185 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7186 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7187 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7188 7189 for (r = 0; r < nRows; r++) { 7190 for (c = 0; c < newNumIndices; c++) { 7191 for (k = 0; k < dof; k++) { 7192 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7193 } 7194 } 7195 } 7196 } 7197 else { 7198 /* copy this row as is */ 7199 for (r = 0; r < dof; r++) { 7200 for (c = 0; c < newNumIndices; c++) { 7201 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7202 } 7203 } 7204 } 7205 oldOff += dof; 7206 } 7207 } 7208 7209 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7210 } 7211 else { 7212 newValues = tmpValues; 7213 } 7214 } 7215 7216 /* clean up */ 7217 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7218 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7219 7220 if (numFields) { 7221 for (f = 0; f < numFields; f++) { 7222 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7223 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7224 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7225 } 7226 } 7227 else { 7228 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7229 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7230 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7231 } 7232 PetscCall(ISRestoreIndices(aIS,&anchors)); 7233 7234 /* output */ 7235 if (outPoints) { 7236 *outPoints = newPoints; 7237 } 7238 else { 7239 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7240 } 7241 if (outValues) { 7242 *outValues = newValues; 7243 } 7244 for (f = 0; f <= numFields; f++) { 7245 offsets[f] = newOffsets[f]; 7246 } 7247 PetscFunctionReturn(0); 7248 } 7249 7250 /*@C 7251 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7252 7253 Not collective 7254 7255 Input Parameters: 7256 + dm - The DM 7257 . section - The PetscSection describing the points (a local section) 7258 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7259 . point - The point defining the closure 7260 - useClPerm - Use the closure point permutation if available 7261 7262 Output Parameters: 7263 + numIndices - The number of dof indices in the closure of point with the input sections 7264 . indices - The dof indices 7265 . outOffsets - Array to write the field offsets into, or NULL 7266 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7267 7268 Notes: 7269 Must call DMPlexRestoreClosureIndices() to free allocated memory 7270 7271 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7272 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7273 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7274 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7275 indices (with the above semantics) are implied. 7276 7277 Level: advanced 7278 7279 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7280 @*/ 7281 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7282 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7283 { 7284 /* Closure ordering */ 7285 PetscSection clSection; 7286 IS clPoints; 7287 const PetscInt *clp; 7288 PetscInt *points; 7289 const PetscInt *clperm = NULL; 7290 /* Dof permutation and sign flips */ 7291 const PetscInt **perms[32] = {NULL}; 7292 const PetscScalar **flips[32] = {NULL}; 7293 PetscScalar *valCopy = NULL; 7294 /* Hanging node constraints */ 7295 PetscInt *pointsC = NULL; 7296 PetscScalar *valuesC = NULL; 7297 PetscInt NclC, NiC; 7298 7299 PetscInt *idx; 7300 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7301 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7302 7303 PetscFunctionBeginHot; 7304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7305 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7306 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7307 if (numIndices) PetscValidIntPointer(numIndices, 6); 7308 if (indices) PetscValidPointer(indices, 7); 7309 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7310 if (values) PetscValidPointer(values, 9); 7311 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7312 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7313 PetscCall(PetscArrayzero(offsets, 32)); 7314 /* 1) Get points in closure */ 7315 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7316 if (useClPerm) { 7317 PetscInt depth, clsize; 7318 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7319 for (clsize=0,p=0; p<Ncl; p++) { 7320 PetscInt dof; 7321 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7322 clsize += dof; 7323 } 7324 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7325 } 7326 /* 2) Get number of indices on these points and field offsets from section */ 7327 for (p = 0; p < Ncl*2; p += 2) { 7328 PetscInt dof, fdof; 7329 7330 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7331 for (f = 0; f < Nf; ++f) { 7332 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7333 offsets[f+1] += fdof; 7334 } 7335 Ni += dof; 7336 } 7337 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7338 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7339 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7340 for (f = 0; f < PetscMax(1, Nf); ++f) { 7341 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7342 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7343 /* may need to apply sign changes to the element matrix */ 7344 if (values && flips[f]) { 7345 PetscInt foffset = offsets[f]; 7346 7347 for (p = 0; p < Ncl; ++p) { 7348 PetscInt pnt = points[2*p], fdof; 7349 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7350 7351 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7352 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7353 if (flip) { 7354 PetscInt i, j, k; 7355 7356 if (!valCopy) { 7357 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7358 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7359 *values = valCopy; 7360 } 7361 for (i = 0; i < fdof; ++i) { 7362 PetscScalar fval = flip[i]; 7363 7364 for (k = 0; k < Ni; ++k) { 7365 valCopy[Ni * (foffset + i) + k] *= fval; 7366 valCopy[Ni * k + (foffset + i)] *= fval; 7367 } 7368 } 7369 } 7370 foffset += fdof; 7371 } 7372 } 7373 } 7374 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7375 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7376 if (NclC) { 7377 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7378 for (f = 0; f < PetscMax(1, Nf); ++f) { 7379 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7380 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7381 } 7382 for (f = 0; f < PetscMax(1, Nf); ++f) { 7383 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7384 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7385 } 7386 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7387 Ncl = NclC; 7388 Ni = NiC; 7389 points = pointsC; 7390 if (values) *values = valuesC; 7391 } 7392 /* 5) Calculate indices */ 7393 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7394 if (Nf) { 7395 PetscInt idxOff; 7396 PetscBool useFieldOffsets; 7397 7398 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7399 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7400 if (useFieldOffsets) { 7401 for (p = 0; p < Ncl; ++p) { 7402 const PetscInt pnt = points[p*2]; 7403 7404 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7405 } 7406 } else { 7407 for (p = 0; p < Ncl; ++p) { 7408 const PetscInt pnt = points[p*2]; 7409 7410 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7411 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7412 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7413 * global section. */ 7414 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7415 } 7416 } 7417 } else { 7418 PetscInt off = 0, idxOff; 7419 7420 for (p = 0; p < Ncl; ++p) { 7421 const PetscInt pnt = points[p*2]; 7422 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7423 7424 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7425 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7426 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7427 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7428 } 7429 } 7430 /* 6) Cleanup */ 7431 for (f = 0; f < PetscMax(1, Nf); ++f) { 7432 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7433 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7434 } 7435 if (NclC) { 7436 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7437 } else { 7438 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7439 } 7440 7441 if (numIndices) *numIndices = Ni; 7442 if (indices) *indices = idx; 7443 PetscFunctionReturn(0); 7444 } 7445 7446 /*@C 7447 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7448 7449 Not collective 7450 7451 Input Parameters: 7452 + dm - The DM 7453 . section - The PetscSection describing the points (a local section) 7454 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7455 . point - The point defining the closure 7456 - useClPerm - Use the closure point permutation if available 7457 7458 Output Parameters: 7459 + numIndices - The number of dof indices in the closure of point with the input sections 7460 . indices - The dof indices 7461 . outOffsets - Array to write the field offsets into, or NULL 7462 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7463 7464 Notes: 7465 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7466 7467 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7468 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7469 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7470 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7471 indices (with the above semantics) are implied. 7472 7473 Level: advanced 7474 7475 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7476 @*/ 7477 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7478 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7479 { 7480 PetscFunctionBegin; 7481 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7482 PetscValidPointer(indices, 7); 7483 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7484 PetscFunctionReturn(0); 7485 } 7486 7487 /*@C 7488 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7489 7490 Not collective 7491 7492 Input Parameters: 7493 + dm - The DM 7494 . section - The section describing the layout in v, or NULL to use the default section 7495 . globalSection - The section describing the layout in v, or NULL to use the default global section 7496 . A - The matrix 7497 . point - The point in the DM 7498 . values - The array of values 7499 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7500 7501 Fortran Notes: 7502 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7503 7504 Level: intermediate 7505 7506 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7507 @*/ 7508 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7509 { 7510 DM_Plex *mesh = (DM_Plex*) dm->data; 7511 PetscInt *indices; 7512 PetscInt numIndices; 7513 const PetscScalar *valuesOrig = values; 7514 PetscErrorCode ierr; 7515 7516 PetscFunctionBegin; 7517 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7518 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7519 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7520 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7521 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7522 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7523 7524 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7525 7526 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7527 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7528 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7529 if (ierr) { 7530 PetscMPIInt rank; 7531 7532 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7533 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7534 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7535 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7536 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7537 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7538 } 7539 if (mesh->printFEM > 1) { 7540 PetscInt i; 7541 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7542 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7543 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7544 } 7545 7546 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7547 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7548 PetscFunctionReturn(0); 7549 } 7550 7551 /*@C 7552 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7553 7554 Not collective 7555 7556 Input Parameters: 7557 + dmRow - The DM for the row fields 7558 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7559 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7560 . dmCol - The DM for the column fields 7561 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7562 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7563 . A - The matrix 7564 . point - The point in the DMs 7565 . values - The array of values 7566 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7567 7568 Level: intermediate 7569 7570 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7571 @*/ 7572 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7573 { 7574 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7575 PetscInt *indicesRow, *indicesCol; 7576 PetscInt numIndicesRow, numIndicesCol; 7577 const PetscScalar *valuesOrig = values; 7578 PetscErrorCode ierr; 7579 7580 PetscFunctionBegin; 7581 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7582 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7583 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7584 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7585 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7586 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7587 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7588 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7589 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7590 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7591 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7592 7593 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7594 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7595 7596 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7597 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7598 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7599 if (ierr) { 7600 PetscMPIInt rank; 7601 7602 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7603 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7604 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7605 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7606 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7607 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7608 } 7609 7610 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7611 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7612 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7613 PetscFunctionReturn(0); 7614 } 7615 7616 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7617 { 7618 DM_Plex *mesh = (DM_Plex*) dmf->data; 7619 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7620 PetscInt *cpoints = NULL; 7621 PetscInt *findices, *cindices; 7622 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7623 PetscInt foffsets[32], coffsets[32]; 7624 DMPolytopeType ct; 7625 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7626 PetscErrorCode ierr; 7627 7628 PetscFunctionBegin; 7629 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7630 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7631 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7632 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7633 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7634 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7635 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7636 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7637 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7638 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7639 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7640 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7641 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7642 PetscCall(PetscArrayzero(foffsets, 32)); 7643 PetscCall(PetscArrayzero(coffsets, 32)); 7644 /* Column indices */ 7645 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7646 maxFPoints = numCPoints; 7647 /* Compress out points not in the section */ 7648 /* TODO: Squeeze out points with 0 dof as well */ 7649 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7650 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7651 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7652 cpoints[q*2] = cpoints[p]; 7653 cpoints[q*2+1] = cpoints[p+1]; 7654 ++q; 7655 } 7656 } 7657 numCPoints = q; 7658 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7659 PetscInt fdof; 7660 7661 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7662 if (!dof) continue; 7663 for (f = 0; f < numFields; ++f) { 7664 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7665 coffsets[f+1] += fdof; 7666 } 7667 numCIndices += dof; 7668 } 7669 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7670 /* Row indices */ 7671 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7672 { 7673 DMPlexTransform tr; 7674 DMPolytopeType *rct; 7675 PetscInt *rsize, *rcone, *rornt, Nt; 7676 7677 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7678 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7679 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7680 numSubcells = rsize[Nt-1]; 7681 PetscCall(DMPlexTransformDestroy(&tr)); 7682 } 7683 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7684 for (r = 0, q = 0; r < numSubcells; ++r) { 7685 /* TODO Map from coarse to fine cells */ 7686 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7687 /* Compress out points not in the section */ 7688 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7689 for (p = 0; p < numFPoints*2; p += 2) { 7690 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7691 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7692 if (!dof) continue; 7693 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7694 if (s < q) continue; 7695 ftotpoints[q*2] = fpoints[p]; 7696 ftotpoints[q*2+1] = fpoints[p+1]; 7697 ++q; 7698 } 7699 } 7700 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7701 } 7702 numFPoints = q; 7703 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7704 PetscInt fdof; 7705 7706 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7707 if (!dof) continue; 7708 for (f = 0; f < numFields; ++f) { 7709 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7710 foffsets[f+1] += fdof; 7711 } 7712 numFIndices += dof; 7713 } 7714 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7715 7716 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7717 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7718 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7719 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7720 if (numFields) { 7721 const PetscInt **permsF[32] = {NULL}; 7722 const PetscInt **permsC[32] = {NULL}; 7723 7724 for (f = 0; f < numFields; f++) { 7725 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7726 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7727 } 7728 for (p = 0; p < numFPoints; p++) { 7729 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7730 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7731 } 7732 for (p = 0; p < numCPoints; p++) { 7733 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7734 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7735 } 7736 for (f = 0; f < numFields; f++) { 7737 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7738 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7739 } 7740 } else { 7741 const PetscInt **permsF = NULL; 7742 const PetscInt **permsC = NULL; 7743 7744 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7745 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7746 for (p = 0, off = 0; p < numFPoints; p++) { 7747 const PetscInt *perm = permsF ? permsF[p] : NULL; 7748 7749 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7750 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7751 } 7752 for (p = 0, off = 0; p < numCPoints; p++) { 7753 const PetscInt *perm = permsC ? permsC[p] : NULL; 7754 7755 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7756 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7757 } 7758 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7759 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7760 } 7761 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7762 /* TODO: flips */ 7763 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7764 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7765 if (ierr) { 7766 PetscMPIInt rank; 7767 7768 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7769 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7770 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7771 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7772 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7773 } 7774 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7775 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7776 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7777 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7778 PetscFunctionReturn(0); 7779 } 7780 7781 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7782 { 7783 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7784 PetscInt *cpoints = NULL; 7785 PetscInt foffsets[32], coffsets[32]; 7786 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7787 DMPolytopeType ct; 7788 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7789 7790 PetscFunctionBegin; 7791 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7792 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7793 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7794 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7795 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7796 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7797 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7798 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7799 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7800 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7801 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7802 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7803 PetscCall(PetscArrayzero(foffsets, 32)); 7804 PetscCall(PetscArrayzero(coffsets, 32)); 7805 /* Column indices */ 7806 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7807 maxFPoints = numCPoints; 7808 /* Compress out points not in the section */ 7809 /* TODO: Squeeze out points with 0 dof as well */ 7810 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7811 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7812 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7813 cpoints[q*2] = cpoints[p]; 7814 cpoints[q*2+1] = cpoints[p+1]; 7815 ++q; 7816 } 7817 } 7818 numCPoints = q; 7819 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7820 PetscInt fdof; 7821 7822 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7823 if (!dof) continue; 7824 for (f = 0; f < numFields; ++f) { 7825 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7826 coffsets[f+1] += fdof; 7827 } 7828 numCIndices += dof; 7829 } 7830 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7831 /* Row indices */ 7832 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7833 { 7834 DMPlexTransform tr; 7835 DMPolytopeType *rct; 7836 PetscInt *rsize, *rcone, *rornt, Nt; 7837 7838 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7839 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7840 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7841 numSubcells = rsize[Nt-1]; 7842 PetscCall(DMPlexTransformDestroy(&tr)); 7843 } 7844 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7845 for (r = 0, q = 0; r < numSubcells; ++r) { 7846 /* TODO Map from coarse to fine cells */ 7847 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7848 /* Compress out points not in the section */ 7849 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7850 for (p = 0; p < numFPoints*2; p += 2) { 7851 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7852 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7853 if (!dof) continue; 7854 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7855 if (s < q) continue; 7856 ftotpoints[q*2] = fpoints[p]; 7857 ftotpoints[q*2+1] = fpoints[p+1]; 7858 ++q; 7859 } 7860 } 7861 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7862 } 7863 numFPoints = q; 7864 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7865 PetscInt fdof; 7866 7867 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7868 if (!dof) continue; 7869 for (f = 0; f < numFields; ++f) { 7870 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7871 foffsets[f+1] += fdof; 7872 } 7873 numFIndices += dof; 7874 } 7875 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7876 7877 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7878 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7879 if (numFields) { 7880 const PetscInt **permsF[32] = {NULL}; 7881 const PetscInt **permsC[32] = {NULL}; 7882 7883 for (f = 0; f < numFields; f++) { 7884 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7885 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7886 } 7887 for (p = 0; p < numFPoints; p++) { 7888 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7889 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7890 } 7891 for (p = 0; p < numCPoints; p++) { 7892 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7893 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7894 } 7895 for (f = 0; f < numFields; f++) { 7896 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7897 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7898 } 7899 } else { 7900 const PetscInt **permsF = NULL; 7901 const PetscInt **permsC = NULL; 7902 7903 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7904 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7905 for (p = 0, off = 0; p < numFPoints; p++) { 7906 const PetscInt *perm = permsF ? permsF[p] : NULL; 7907 7908 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7909 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7910 } 7911 for (p = 0, off = 0; p < numCPoints; p++) { 7912 const PetscInt *perm = permsC ? permsC[p] : NULL; 7913 7914 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7915 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7916 } 7917 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7918 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7919 } 7920 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7921 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7922 PetscFunctionReturn(0); 7923 } 7924 7925 /*@C 7926 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7927 7928 Input Parameter: 7929 . dm - The DMPlex object 7930 7931 Output Parameter: 7932 . cellHeight - The height of a cell 7933 7934 Level: developer 7935 7936 .seealso `DMPlexSetVTKCellHeight()` 7937 @*/ 7938 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7939 { 7940 DM_Plex *mesh = (DM_Plex*) dm->data; 7941 7942 PetscFunctionBegin; 7943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7944 PetscValidIntPointer(cellHeight, 2); 7945 *cellHeight = mesh->vtkCellHeight; 7946 PetscFunctionReturn(0); 7947 } 7948 7949 /*@C 7950 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7951 7952 Input Parameters: 7953 + dm - The DMPlex object 7954 - cellHeight - The height of a cell 7955 7956 Level: developer 7957 7958 .seealso `DMPlexGetVTKCellHeight()` 7959 @*/ 7960 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7961 { 7962 DM_Plex *mesh = (DM_Plex*) dm->data; 7963 7964 PetscFunctionBegin; 7965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7966 mesh->vtkCellHeight = cellHeight; 7967 PetscFunctionReturn(0); 7968 } 7969 7970 /*@ 7971 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7972 7973 Input Parameter: 7974 . dm - The DMPlex object 7975 7976 Output Parameters: 7977 + gcStart - The first ghost cell, or NULL 7978 - gcEnd - The upper bound on ghost cells, or NULL 7979 7980 Level: advanced 7981 7982 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7983 @*/ 7984 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7985 { 7986 DMLabel ctLabel; 7987 7988 PetscFunctionBegin; 7989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7990 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7991 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7992 PetscFunctionReturn(0); 7993 } 7994 7995 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 7996 { 7997 PetscSection section, globalSection; 7998 PetscInt *numbers, p; 7999 8000 PetscFunctionBegin; 8001 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8002 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8003 for (p = pStart; p < pEnd; ++p) { 8004 PetscCall(PetscSectionSetDof(section, p, 1)); 8005 } 8006 PetscCall(PetscSectionSetUp(section)); 8007 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8008 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8009 for (p = pStart; p < pEnd; ++p) { 8010 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8011 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8012 else numbers[p-pStart] += shift; 8013 } 8014 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8015 if (globalSize) { 8016 PetscLayout layout; 8017 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8018 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8019 PetscCall(PetscLayoutDestroy(&layout)); 8020 } 8021 PetscCall(PetscSectionDestroy(§ion)); 8022 PetscCall(PetscSectionDestroy(&globalSection)); 8023 PetscFunctionReturn(0); 8024 } 8025 8026 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8027 { 8028 PetscInt cellHeight, cStart, cEnd; 8029 8030 PetscFunctionBegin; 8031 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8032 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8033 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8034 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8035 PetscFunctionReturn(0); 8036 } 8037 8038 /*@ 8039 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8040 8041 Input Parameter: 8042 . dm - The DMPlex object 8043 8044 Output Parameter: 8045 . globalCellNumbers - Global cell numbers for all cells on this process 8046 8047 Level: developer 8048 8049 .seealso `DMPlexGetVertexNumbering()` 8050 @*/ 8051 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8052 { 8053 DM_Plex *mesh = (DM_Plex*) dm->data; 8054 8055 PetscFunctionBegin; 8056 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8057 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8058 *globalCellNumbers = mesh->globalCellNumbers; 8059 PetscFunctionReturn(0); 8060 } 8061 8062 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8063 { 8064 PetscInt vStart, vEnd; 8065 8066 PetscFunctionBegin; 8067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8068 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8069 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8070 PetscFunctionReturn(0); 8071 } 8072 8073 /*@ 8074 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8075 8076 Input Parameter: 8077 . dm - The DMPlex object 8078 8079 Output Parameter: 8080 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8081 8082 Level: developer 8083 8084 .seealso `DMPlexGetCellNumbering()` 8085 @*/ 8086 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8087 { 8088 DM_Plex *mesh = (DM_Plex*) dm->data; 8089 8090 PetscFunctionBegin; 8091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8092 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8093 *globalVertexNumbers = mesh->globalVertexNumbers; 8094 PetscFunctionReturn(0); 8095 } 8096 8097 /*@ 8098 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8099 8100 Input Parameter: 8101 . dm - The DMPlex object 8102 8103 Output Parameter: 8104 . globalPointNumbers - Global numbers for all points on this process 8105 8106 Level: developer 8107 8108 .seealso `DMPlexGetCellNumbering()` 8109 @*/ 8110 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8111 { 8112 IS nums[4]; 8113 PetscInt depths[4], gdepths[4], starts[4]; 8114 PetscInt depth, d, shift = 0; 8115 8116 PetscFunctionBegin; 8117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8118 PetscCall(DMPlexGetDepth(dm, &depth)); 8119 /* For unstratified meshes use dim instead of depth */ 8120 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8121 for (d = 0; d <= depth; ++d) { 8122 PetscInt end; 8123 8124 depths[d] = depth-d; 8125 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8126 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8127 } 8128 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8129 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8130 for (d = 0; d <= depth; ++d) { 8131 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]); 8132 } 8133 for (d = 0; d <= depth; ++d) { 8134 PetscInt pStart, pEnd, gsize; 8135 8136 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8137 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8138 shift += gsize; 8139 } 8140 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8141 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8142 PetscFunctionReturn(0); 8143 } 8144 8145 /*@ 8146 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8147 8148 Input Parameter: 8149 . dm - The DMPlex object 8150 8151 Output Parameter: 8152 . ranks - The rank field 8153 8154 Options Database Keys: 8155 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8156 8157 Level: intermediate 8158 8159 .seealso: `DMView()` 8160 @*/ 8161 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8162 { 8163 DM rdm; 8164 PetscFE fe; 8165 PetscScalar *r; 8166 PetscMPIInt rank; 8167 DMPolytopeType ct; 8168 PetscInt dim, cStart, cEnd, c; 8169 PetscBool simplex; 8170 8171 PetscFunctionBeginUser; 8172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8173 PetscValidPointer(ranks, 2); 8174 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8175 PetscCall(DMClone(dm, &rdm)); 8176 PetscCall(DMGetDimension(rdm, &dim)); 8177 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8178 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8179 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8180 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8181 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8182 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8183 PetscCall(PetscFEDestroy(&fe)); 8184 PetscCall(DMCreateDS(rdm)); 8185 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8186 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8187 PetscCall(VecGetArray(*ranks, &r)); 8188 for (c = cStart; c < cEnd; ++c) { 8189 PetscScalar *lr; 8190 8191 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8192 if (lr) *lr = rank; 8193 } 8194 PetscCall(VecRestoreArray(*ranks, &r)); 8195 PetscCall(DMDestroy(&rdm)); 8196 PetscFunctionReturn(0); 8197 } 8198 8199 /*@ 8200 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8201 8202 Input Parameters: 8203 + dm - The DMPlex 8204 - label - The DMLabel 8205 8206 Output Parameter: 8207 . val - The label value field 8208 8209 Options Database Keys: 8210 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8211 8212 Level: intermediate 8213 8214 .seealso: `DMView()` 8215 @*/ 8216 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8217 { 8218 DM rdm; 8219 PetscFE fe; 8220 PetscScalar *v; 8221 PetscInt dim, cStart, cEnd, c; 8222 8223 PetscFunctionBeginUser; 8224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8225 PetscValidPointer(label, 2); 8226 PetscValidPointer(val, 3); 8227 PetscCall(DMClone(dm, &rdm)); 8228 PetscCall(DMGetDimension(rdm, &dim)); 8229 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8230 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8231 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8232 PetscCall(PetscFEDestroy(&fe)); 8233 PetscCall(DMCreateDS(rdm)); 8234 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8235 PetscCall(DMCreateGlobalVector(rdm, val)); 8236 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8237 PetscCall(VecGetArray(*val, &v)); 8238 for (c = cStart; c < cEnd; ++c) { 8239 PetscScalar *lv; 8240 PetscInt cval; 8241 8242 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8243 PetscCall(DMLabelGetValue(label, c, &cval)); 8244 *lv = cval; 8245 } 8246 PetscCall(VecRestoreArray(*val, &v)); 8247 PetscCall(DMDestroy(&rdm)); 8248 PetscFunctionReturn(0); 8249 } 8250 8251 /*@ 8252 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8253 8254 Input Parameter: 8255 . dm - The DMPlex object 8256 8257 Notes: 8258 This is a useful diagnostic when creating meshes programmatically. 8259 8260 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8261 8262 Level: developer 8263 8264 .seealso: `DMCreate()`, `DMSetFromOptions()` 8265 @*/ 8266 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8267 { 8268 PetscSection coneSection, supportSection; 8269 const PetscInt *cone, *support; 8270 PetscInt coneSize, c, supportSize, s; 8271 PetscInt pStart, pEnd, p, pp, csize, ssize; 8272 PetscBool storagecheck = PETSC_TRUE; 8273 8274 PetscFunctionBegin; 8275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8276 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8277 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8278 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8279 /* Check that point p is found in the support of its cone points, and vice versa */ 8280 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8281 for (p = pStart; p < pEnd; ++p) { 8282 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8283 PetscCall(DMPlexGetCone(dm, p, &cone)); 8284 for (c = 0; c < coneSize; ++c) { 8285 PetscBool dup = PETSC_FALSE; 8286 PetscInt d; 8287 for (d = c-1; d >= 0; --d) { 8288 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8289 } 8290 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8291 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8292 for (s = 0; s < supportSize; ++s) { 8293 if (support[s] == p) break; 8294 } 8295 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8296 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8297 for (s = 0; s < coneSize; ++s) { 8298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8299 } 8300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8301 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8302 for (s = 0; s < supportSize; ++s) { 8303 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8304 } 8305 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8306 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]); 8307 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8308 } 8309 } 8310 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8311 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8312 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8313 PetscCall(DMPlexGetSupport(dm, p, &support)); 8314 for (s = 0; s < supportSize; ++s) { 8315 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8316 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8317 for (c = 0; c < coneSize; ++c) { 8318 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8319 if (cone[c] != pp) { c = 0; break; } 8320 if (cone[c] == p) break; 8321 } 8322 if (c >= coneSize) { 8323 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8324 for (c = 0; c < supportSize; ++c) { 8325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8326 } 8327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8328 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8329 for (c = 0; c < coneSize; ++c) { 8330 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8331 } 8332 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8333 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8334 } 8335 } 8336 } 8337 if (storagecheck) { 8338 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8339 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8340 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8341 } 8342 PetscFunctionReturn(0); 8343 } 8344 8345 /* 8346 For submeshes with cohesive cells (see DMPlexConstructCohesiveCells()), we allow a special case where some of the boundary of a face (edges and vertices) are not duplicated. We call these special boundary points "unsplit", since the same edge or vertex appears in both copies of the face. These unsplit points throw off our counting, so we have to explicitly account for them here. 8347 */ 8348 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8349 { 8350 DMPolytopeType cct; 8351 PetscInt ptpoints[4]; 8352 const PetscInt *cone, *ccone, *ptcone; 8353 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8354 8355 PetscFunctionBegin; 8356 *unsplit = 0; 8357 switch (ct) { 8358 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8359 ptpoints[npt++] = c; 8360 break; 8361 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8362 PetscCall(DMPlexGetCone(dm, c, &cone)); 8363 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8364 for (cp = 0; cp < coneSize; ++cp) { 8365 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8366 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8367 } 8368 break; 8369 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8370 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8371 PetscCall(DMPlexGetCone(dm, c, &cone)); 8372 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8373 for (cp = 0; cp < coneSize; ++cp) { 8374 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8375 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8376 for (ccp = 0; ccp < cconeSize; ++ccp) { 8377 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8378 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8379 PetscInt p; 8380 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8381 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8382 } 8383 } 8384 } 8385 break; 8386 default: break; 8387 } 8388 for (pt = 0; pt < npt; ++pt) { 8389 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8390 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8391 } 8392 PetscFunctionReturn(0); 8393 } 8394 8395 /*@ 8396 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8397 8398 Input Parameters: 8399 + dm - The DMPlex object 8400 - cellHeight - Normally 0 8401 8402 Notes: 8403 This is a useful diagnostic when creating meshes programmatically. 8404 Currently applicable only to homogeneous simplex or tensor meshes. 8405 8406 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8407 8408 Level: developer 8409 8410 .seealso: `DMCreate()`, `DMSetFromOptions()` 8411 @*/ 8412 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8413 { 8414 DMPlexInterpolatedFlag interp; 8415 DMPolytopeType ct; 8416 PetscInt vStart, vEnd, cStart, cEnd, c; 8417 8418 PetscFunctionBegin; 8419 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8420 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8421 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8422 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8423 for (c = cStart; c < cEnd; ++c) { 8424 PetscInt *closure = NULL; 8425 PetscInt coneSize, closureSize, cl, Nv = 0; 8426 8427 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8428 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8429 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8430 if (interp == DMPLEX_INTERPOLATED_FULL) { 8431 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8432 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)); 8433 } 8434 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8435 for (cl = 0; cl < closureSize*2; cl += 2) { 8436 const PetscInt p = closure[cl]; 8437 if ((p >= vStart) && (p < vEnd)) ++Nv; 8438 } 8439 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8440 /* Special Case: Tensor faces with identified vertices */ 8441 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8442 PetscInt unsplit; 8443 8444 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8445 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8446 } 8447 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)); 8448 } 8449 PetscFunctionReturn(0); 8450 } 8451 8452 /*@ 8453 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8454 8455 Not Collective 8456 8457 Input Parameters: 8458 + dm - The DMPlex object 8459 - cellHeight - Normally 0 8460 8461 Notes: 8462 This is a useful diagnostic when creating meshes programmatically. 8463 This routine is only relevant for meshes that are fully interpolated across all ranks. 8464 It will error out if a partially interpolated mesh is given on some rank. 8465 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8466 8467 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8468 8469 Level: developer 8470 8471 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8472 @*/ 8473 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8474 { 8475 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8476 DMPlexInterpolatedFlag interpEnum; 8477 8478 PetscFunctionBegin; 8479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8480 PetscCall(DMPlexIsInterpolated(dm, &interpEnum)); 8481 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8482 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 8483 PetscMPIInt rank; 8484 MPI_Comm comm; 8485 8486 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8487 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8488 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 8489 } 8490 8491 PetscCall(DMGetDimension(dm, &dim)); 8492 PetscCall(DMPlexGetDepth(dm, &depth)); 8493 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8494 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8495 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8496 for (c = cStart; c < cEnd; ++c) { 8497 const PetscInt *cone, *ornt, *faceSizes, *faces; 8498 const DMPolytopeType *faceTypes; 8499 DMPolytopeType ct; 8500 PetscInt numFaces, coneSize, f; 8501 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8502 8503 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8504 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8505 if (unsplit) continue; 8506 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8507 PetscCall(DMPlexGetCone(dm, c, &cone)); 8508 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8509 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8510 for (cl = 0; cl < closureSize*2; cl += 2) { 8511 const PetscInt p = closure[cl]; 8512 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8513 } 8514 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8515 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); 8516 for (f = 0; f < numFaces; ++f) { 8517 DMPolytopeType fct; 8518 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8519 8520 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8521 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8522 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8523 const PetscInt p = fclosure[cl]; 8524 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8525 } 8526 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]); 8527 for (v = 0; v < fnumCorners; ++v) { 8528 if (fclosure[v] != faces[fOff+v]) { 8529 PetscInt v1; 8530 8531 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8532 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8533 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8534 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8535 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8536 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]); 8537 } 8538 } 8539 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8540 fOff += faceSizes[f]; 8541 } 8542 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8543 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8544 } 8545 } 8546 PetscFunctionReturn(0); 8547 } 8548 8549 /*@ 8550 DMPlexCheckGeometry - Check the geometry of mesh cells 8551 8552 Input Parameter: 8553 . dm - The DMPlex object 8554 8555 Notes: 8556 This is a useful diagnostic when creating meshes programmatically. 8557 8558 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8559 8560 Level: developer 8561 8562 .seealso: `DMCreate()`, `DMSetFromOptions()` 8563 @*/ 8564 PetscErrorCode DMPlexCheckGeometry(DM dm) 8565 { 8566 Vec coordinates; 8567 PetscReal detJ, J[9], refVol = 1.0; 8568 PetscReal vol; 8569 PetscBool periodic; 8570 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8571 8572 PetscFunctionBegin; 8573 PetscCall(DMGetDimension(dm, &dim)); 8574 PetscCall(DMGetCoordinateDim(dm, &dE)); 8575 if (dim != dE) PetscFunctionReturn(0); 8576 PetscCall(DMPlexGetDepth(dm, &depth)); 8577 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8578 for (d = 0; d < dim; ++d) refVol *= 2.0; 8579 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8580 /* Make sure local coordinates are created, because that step is collective */ 8581 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8582 for (c = cStart; c < cEnd; ++c) { 8583 DMPolytopeType ct; 8584 PetscInt unsplit; 8585 PetscBool ignoreZeroVol = PETSC_FALSE; 8586 8587 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8588 switch (ct) { 8589 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8590 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8591 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8592 ignoreZeroVol = PETSC_TRUE; break; 8593 default: break; 8594 } 8595 switch (ct) { 8596 case DM_POLYTOPE_TRI_PRISM: 8597 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8598 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8599 case DM_POLYTOPE_PYRAMID: 8600 continue; 8601 default: break; 8602 } 8603 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8604 if (unsplit) continue; 8605 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8606 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); 8607 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8608 if (depth > 1 && !periodic) { 8609 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8610 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); 8611 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8612 } 8613 } 8614 PetscFunctionReturn(0); 8615 } 8616 8617 /*@ 8618 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 8619 8620 Input Parameters: 8621 . dm - The DMPlex object 8622 8623 Notes: 8624 This is mainly intended for debugging/testing purposes. 8625 It currently checks only meshes with no partition overlapping. 8626 8627 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8628 8629 Level: developer 8630 8631 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8632 @*/ 8633 PetscErrorCode DMPlexCheckPointSF(DM dm) 8634 { 8635 PetscSF pointSF; 8636 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 8637 const PetscInt *locals, *rootdegree; 8638 PetscBool distributed; 8639 8640 PetscFunctionBegin; 8641 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8642 PetscCall(DMGetPointSF(dm, &pointSF)); 8643 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8644 if (!distributed) PetscFunctionReturn(0); 8645 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8646 if (overlap) { 8647 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping")); 8648 PetscFunctionReturn(0); 8649 } 8650 PetscCheck(pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 8651 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL)); 8652 PetscCheck(nroots >= 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 8653 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8654 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8655 8656 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 8657 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8658 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8659 for (l = 0; l < nleaves; ++l) { 8660 const PetscInt point = locals[l]; 8661 8662 PetscCheck(point <= cStart || point >= cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8663 } 8664 8665 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8666 for (l = 0; l < nleaves; ++l) { 8667 const PetscInt point = locals[l]; 8668 const PetscInt *cone; 8669 PetscInt coneSize, c, idx; 8670 8671 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8672 PetscCall(DMPlexGetCone(dm, point, &cone)); 8673 for (c = 0; c < coneSize; ++c) { 8674 if (!rootdegree[cone[c]]) { 8675 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8676 PetscCheck(idx >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8677 } 8678 } 8679 } 8680 PetscFunctionReturn(0); 8681 } 8682 8683 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight) 8684 { 8685 PetscFunctionBegin; 8686 PetscCall(DMPlexCheckSymmetry(dm)); 8687 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8688 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8689 PetscCall(DMPlexCheckGeometry(dm)); 8690 PetscCall(DMPlexCheckPointSF(dm)); 8691 PetscCall(DMPlexCheckInterfaceCones(dm)); 8692 PetscFunctionReturn(0); 8693 } 8694 8695 typedef struct cell_stats 8696 { 8697 PetscReal min, max, sum, squaresum; 8698 PetscInt count; 8699 } cell_stats_t; 8700 8701 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8702 { 8703 PetscInt i, N = *len; 8704 8705 for (i = 0; i < N; i++) { 8706 cell_stats_t *A = (cell_stats_t *) a; 8707 cell_stats_t *B = (cell_stats_t *) b; 8708 8709 B->min = PetscMin(A->min,B->min); 8710 B->max = PetscMax(A->max,B->max); 8711 B->sum += A->sum; 8712 B->squaresum += A->squaresum; 8713 B->count += A->count; 8714 } 8715 } 8716 8717 /*@ 8718 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8719 8720 Collective on dm 8721 8722 Input Parameters: 8723 + dm - The DMPlex object 8724 . output - If true, statistics will be displayed on stdout 8725 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8726 8727 Notes: 8728 This is mainly intended for debugging/testing purposes. 8729 8730 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8731 8732 Level: developer 8733 8734 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8735 @*/ 8736 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8737 { 8738 DM dmCoarse; 8739 cell_stats_t stats, globalStats; 8740 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8741 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8742 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8743 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8744 PetscMPIInt rank,size; 8745 8746 PetscFunctionBegin; 8747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8748 stats.min = PETSC_MAX_REAL; 8749 stats.max = PETSC_MIN_REAL; 8750 stats.sum = stats.squaresum = 0.; 8751 stats.count = 0; 8752 8753 PetscCallMPI(MPI_Comm_size(comm, &size)); 8754 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8755 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8756 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8757 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8758 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8759 for (c = cStart; c < cEnd; c++) { 8760 PetscInt i; 8761 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8762 8763 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8764 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8765 for (i = 0; i < PetscSqr(cdim); ++i) { 8766 frobJ += J[i] * J[i]; 8767 frobInvJ += invJ[i] * invJ[i]; 8768 } 8769 cond2 = frobJ * frobInvJ; 8770 cond = PetscSqrtReal(cond2); 8771 8772 stats.min = PetscMin(stats.min,cond); 8773 stats.max = PetscMax(stats.max,cond); 8774 stats.sum += cond; 8775 stats.squaresum += cond2; 8776 stats.count++; 8777 if (output && cond > limit) { 8778 PetscSection coordSection; 8779 Vec coordsLocal; 8780 PetscScalar *coords = NULL; 8781 PetscInt Nv, d, clSize, cl, *closure = NULL; 8782 8783 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8784 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8785 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8786 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8787 for (i = 0; i < Nv/cdim; ++i) { 8788 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8789 for (d = 0; d < cdim; ++d) { 8790 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8791 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8792 } 8793 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8794 } 8795 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8796 for (cl = 0; cl < clSize*2; cl += 2) { 8797 const PetscInt edge = closure[cl]; 8798 8799 if ((edge >= eStart) && (edge < eEnd)) { 8800 PetscReal len; 8801 8802 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8803 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8804 } 8805 } 8806 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8807 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8808 } 8809 } 8810 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8811 8812 if (size > 1) { 8813 PetscMPIInt blockLengths[2] = {4,1}; 8814 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8815 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8816 MPI_Op statReduce; 8817 8818 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8819 PetscCallMPI(MPI_Type_commit(&statType)); 8820 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8821 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8822 PetscCallMPI(MPI_Op_free(&statReduce)); 8823 PetscCallMPI(MPI_Type_free(&statType)); 8824 } else { 8825 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8826 } 8827 if (rank == 0) { 8828 count = globalStats.count; 8829 min = globalStats.min; 8830 max = globalStats.max; 8831 mean = globalStats.sum / globalStats.count; 8832 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8833 } 8834 8835 if (output) { 8836 PetscCall(PetscPrintf(comm,"Mesh with %" PetscInt_FMT " cells, shape condition numbers: min = %g, max = %g, mean = %g, stddev = %g\n", count, (double) min, (double) max, (double) mean, (double) stdev)); 8837 } 8838 PetscCall(PetscFree2(J,invJ)); 8839 8840 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8841 if (dmCoarse) { 8842 PetscBool isplex; 8843 8844 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8845 if (isplex) { 8846 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8847 } 8848 } 8849 PetscFunctionReturn(0); 8850 } 8851 8852 /*@ 8853 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8854 orthogonal quality below given tolerance. 8855 8856 Collective on dm 8857 8858 Input Parameters: 8859 + dm - The DMPlex object 8860 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8861 - atol - [0, 1] Absolute tolerance for tagging cells. 8862 8863 Output Parameters: 8864 + OrthQual - Vec containing orthogonal quality per cell 8865 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8866 8867 Options Database Keys: 8868 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8869 supported. 8870 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8871 8872 Notes: 8873 Orthogonal quality is given by the following formula: 8874 8875 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8876 8877 Where A_i is the i'th face-normal vector, f_i is the vector from the cell centroid to the i'th face centroid, and c_i 8878 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8879 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8880 calculating the cosine of the angle between these vectors. 8881 8882 Orthogonal quality ranges from 1 (best) to 0 (worst). 8883 8884 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8885 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8886 8887 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8888 8889 Level: intermediate 8890 8891 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8892 @*/ 8893 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8894 { 8895 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8896 PetscInt *idx; 8897 PetscScalar *oqVals; 8898 const PetscScalar *cellGeomArr, *faceGeomArr; 8899 PetscReal *ci, *fi, *Ai; 8900 MPI_Comm comm; 8901 Vec cellgeom, facegeom; 8902 DM dmFace, dmCell; 8903 IS glob; 8904 ISLocalToGlobalMapping ltog; 8905 PetscViewer vwr; 8906 8907 PetscFunctionBegin; 8908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8909 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8910 PetscValidPointer(OrthQual, 4); 8911 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8912 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8913 PetscCall(DMGetDimension(dm, &nc)); 8914 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8915 { 8916 DMPlexInterpolatedFlag interpFlag; 8917 8918 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8919 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8920 PetscMPIInt rank; 8921 8922 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8923 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8924 } 8925 } 8926 if (OrthQualLabel) { 8927 PetscValidPointer(OrthQualLabel, 5); 8928 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8929 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8930 } else {*OrthQualLabel = NULL;} 8931 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8932 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8933 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8934 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8935 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8936 PetscCall(VecCreate(comm, OrthQual)); 8937 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8938 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 8939 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8940 PetscCall(VecSetUp(*OrthQual)); 8941 PetscCall(ISDestroy(&glob)); 8942 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8943 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8944 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8945 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8946 PetscCall(VecGetDM(cellgeom, &dmCell)); 8947 PetscCall(VecGetDM(facegeom, &dmFace)); 8948 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8949 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 8950 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8951 PetscInt cellarr[2], *adj = NULL; 8952 PetscScalar *cArr, *fArr; 8953 PetscReal minvalc = 1.0, minvalf = 1.0; 8954 PetscFVCellGeom *cg; 8955 8956 idx[cellIter] = cell-cStart; 8957 cellarr[0] = cell; 8958 /* Make indexing into cellGeom easier */ 8959 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8960 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8961 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8962 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8963 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 8964 PetscInt i; 8965 const PetscInt neigh = adj[cellneigh]; 8966 PetscReal normci = 0, normfi = 0, normai = 0; 8967 PetscFVCellGeom *cgneigh; 8968 PetscFVFaceGeom *fg; 8969 8970 /* Don't count ourselves in the neighbor list */ 8971 if (neigh == cell) continue; 8972 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8973 cellarr[1] = neigh; 8974 { 8975 PetscInt numcovpts; 8976 const PetscInt *covpts; 8977 8978 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8979 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8980 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8981 } 8982 8983 /* Compute c_i, f_i and their norms */ 8984 for (i = 0; i < nc; i++) { 8985 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8986 fi[i] = fg->centroid[i] - cg->centroid[i]; 8987 Ai[i] = fg->normal[i]; 8988 normci += PetscPowReal(ci[i], 2); 8989 normfi += PetscPowReal(fi[i], 2); 8990 normai += PetscPowReal(Ai[i], 2); 8991 } 8992 normci = PetscSqrtReal(normci); 8993 normfi = PetscSqrtReal(normfi); 8994 normai = PetscSqrtReal(normai); 8995 8996 /* Normalize and compute for each face-cell-normal pair */ 8997 for (i = 0; i < nc; i++) { 8998 ci[i] = ci[i]/normci; 8999 fi[i] = fi[i]/normfi; 9000 Ai[i] = Ai[i]/normai; 9001 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9002 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9003 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9004 } 9005 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9006 minvalc = PetscRealPart(cArr[cellneighiter]); 9007 } 9008 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9009 minvalf = PetscRealPart(fArr[cellneighiter]); 9010 } 9011 } 9012 PetscCall(PetscFree(adj)); 9013 PetscCall(PetscFree2(cArr, fArr)); 9014 /* Defer to cell if they're equal */ 9015 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9016 if (OrthQualLabel) { 9017 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9018 } 9019 } 9020 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9021 PetscCall(VecAssemblyBegin(*OrthQual)); 9022 PetscCall(VecAssemblyEnd(*OrthQual)); 9023 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9024 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9025 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9026 if (OrthQualLabel) { 9027 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9028 } 9029 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9030 PetscCall(PetscViewerDestroy(&vwr)); 9031 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9032 PetscFunctionReturn(0); 9033 } 9034 9035 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9036 * interpolator construction */ 9037 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9038 { 9039 PetscSection section, newSection, gsection; 9040 PetscSF sf; 9041 PetscBool hasConstraints, ghasConstraints; 9042 9043 PetscFunctionBegin; 9044 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9045 PetscValidPointer(odm,2); 9046 PetscCall(DMGetLocalSection(dm, §ion)); 9047 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9048 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9049 if (!ghasConstraints) { 9050 PetscCall(PetscObjectReference((PetscObject)dm)); 9051 *odm = dm; 9052 PetscFunctionReturn(0); 9053 } 9054 PetscCall(DMClone(dm, odm)); 9055 PetscCall(DMCopyFields(dm, *odm)); 9056 PetscCall(DMGetLocalSection(*odm, &newSection)); 9057 PetscCall(DMGetPointSF(*odm, &sf)); 9058 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9059 PetscCall(DMSetGlobalSection(*odm, gsection)); 9060 PetscCall(PetscSectionDestroy(&gsection)); 9061 PetscFunctionReturn(0); 9062 } 9063 9064 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9065 { 9066 DM dmco, dmfo; 9067 Mat interpo; 9068 Vec rscale; 9069 Vec cglobalo, clocal; 9070 Vec fglobal, fglobalo, flocal; 9071 PetscBool regular; 9072 9073 PetscFunctionBegin; 9074 PetscCall(DMGetFullDM(dmc, &dmco)); 9075 PetscCall(DMGetFullDM(dmf, &dmfo)); 9076 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9077 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9078 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9079 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9080 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9081 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9082 PetscCall(VecSet(cglobalo, 0.)); 9083 PetscCall(VecSet(clocal, 0.)); 9084 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9085 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9086 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9087 PetscCall(VecSet(fglobal, 0.)); 9088 PetscCall(VecSet(fglobalo, 0.)); 9089 PetscCall(VecSet(flocal, 0.)); 9090 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9091 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9092 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9093 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9094 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9095 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9096 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9097 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9098 *shift = fglobal; 9099 PetscCall(VecDestroy(&flocal)); 9100 PetscCall(VecDestroy(&fglobalo)); 9101 PetscCall(VecDestroy(&clocal)); 9102 PetscCall(VecDestroy(&cglobalo)); 9103 PetscCall(VecDestroy(&rscale)); 9104 PetscCall(MatDestroy(&interpo)); 9105 PetscCall(DMDestroy(&dmfo)); 9106 PetscCall(DMDestroy(&dmco)); 9107 PetscFunctionReturn(0); 9108 } 9109 9110 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9111 { 9112 PetscObject shifto; 9113 Vec shift; 9114 9115 PetscFunctionBegin; 9116 if (!interp) { 9117 Vec rscale; 9118 9119 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9120 PetscCall(VecDestroy(&rscale)); 9121 } else { 9122 PetscCall(PetscObjectReference((PetscObject)interp)); 9123 } 9124 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9125 if (!shifto) { 9126 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9127 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9128 shifto = (PetscObject) shift; 9129 PetscCall(VecDestroy(&shift)); 9130 } 9131 shift = (Vec) shifto; 9132 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9133 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9134 PetscCall(MatDestroy(&interp)); 9135 PetscFunctionReturn(0); 9136 } 9137 9138 /* Pointwise interpolation 9139 Just code FEM for now 9140 u^f = I u^c 9141 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9142 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9143 I_{ij} = psi^f_i phi^c_j 9144 */ 9145 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9146 { 9147 PetscSection gsc, gsf; 9148 PetscInt m, n; 9149 void *ctx; 9150 DM cdm; 9151 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9152 9153 PetscFunctionBegin; 9154 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9155 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9156 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9157 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9158 9159 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9160 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9161 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9162 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9163 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9164 9165 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9166 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9167 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9168 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9169 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9170 if (scaling) { 9171 /* Use naive scaling */ 9172 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9173 } 9174 PetscFunctionReturn(0); 9175 } 9176 9177 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9178 { 9179 VecScatter ctx; 9180 9181 PetscFunctionBegin; 9182 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9183 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9184 PetscCall(VecScatterDestroy(&ctx)); 9185 PetscFunctionReturn(0); 9186 } 9187 9188 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9189 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9190 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9191 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9192 { 9193 const PetscInt Nc = uOff[1] - uOff[0]; 9194 PetscInt c; 9195 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9196 } 9197 9198 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9199 { 9200 DM dmc; 9201 PetscDS ds; 9202 Vec ones, locmass; 9203 IS cellIS; 9204 PetscFormKey key; 9205 PetscInt depth; 9206 9207 PetscFunctionBegin; 9208 PetscCall(DMClone(dm, &dmc)); 9209 PetscCall(DMCopyDisc(dm, dmc)); 9210 PetscCall(DMGetDS(dmc, &ds)); 9211 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9212 PetscCall(DMCreateGlobalVector(dmc, mass)); 9213 PetscCall(DMGetLocalVector(dmc, &ones)); 9214 PetscCall(DMGetLocalVector(dmc, &locmass)); 9215 PetscCall(DMPlexGetDepth(dmc, &depth)); 9216 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9217 PetscCall(VecSet(locmass, 0.0)); 9218 PetscCall(VecSet(ones, 1.0)); 9219 key.label = NULL; 9220 key.value = 0; 9221 key.field = 0; 9222 key.part = 0; 9223 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9224 PetscCall(ISDestroy(&cellIS)); 9225 PetscCall(VecSet(*mass, 0.0)); 9226 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9227 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9228 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9229 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9230 PetscCall(DMDestroy(&dmc)); 9231 PetscFunctionReturn(0); 9232 } 9233 9234 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9235 { 9236 PetscSection gsc, gsf; 9237 PetscInt m, n; 9238 void *ctx; 9239 DM cdm; 9240 PetscBool regular; 9241 9242 PetscFunctionBegin; 9243 if (dmFine == dmCoarse) { 9244 DM dmc; 9245 PetscDS ds; 9246 PetscWeakForm wf; 9247 Vec u; 9248 IS cellIS; 9249 PetscFormKey key; 9250 PetscInt depth; 9251 9252 PetscCall(DMClone(dmFine, &dmc)); 9253 PetscCall(DMCopyDisc(dmFine, dmc)); 9254 PetscCall(DMGetDS(dmc, &ds)); 9255 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9256 PetscCall(PetscWeakFormClear(wf)); 9257 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9258 PetscCall(DMCreateMatrix(dmc, mass)); 9259 PetscCall(DMGetGlobalVector(dmc, &u)); 9260 PetscCall(DMPlexGetDepth(dmc, &depth)); 9261 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9262 PetscCall(MatZeroEntries(*mass)); 9263 key.label = NULL; 9264 key.value = 0; 9265 key.field = 0; 9266 key.part = 0; 9267 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9268 PetscCall(ISDestroy(&cellIS)); 9269 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9270 PetscCall(DMDestroy(&dmc)); 9271 } else { 9272 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9273 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9274 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9275 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9276 9277 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9278 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9279 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9280 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9281 9282 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9283 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9284 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9285 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9286 } 9287 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9288 PetscFunctionReturn(0); 9289 } 9290 9291 /*@ 9292 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9293 9294 Input Parameter: 9295 . dm - The DMPlex object 9296 9297 Output Parameter: 9298 . regular - The flag 9299 9300 Level: intermediate 9301 9302 .seealso: `DMPlexSetRegularRefinement()` 9303 @*/ 9304 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9305 { 9306 PetscFunctionBegin; 9307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9308 PetscValidBoolPointer(regular, 2); 9309 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9310 PetscFunctionReturn(0); 9311 } 9312 9313 /*@ 9314 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9315 9316 Input Parameters: 9317 + dm - The DMPlex object 9318 - regular - The flag 9319 9320 Level: intermediate 9321 9322 .seealso: `DMPlexGetRegularRefinement()` 9323 @*/ 9324 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9325 { 9326 PetscFunctionBegin; 9327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9328 ((DM_Plex *) dm->data)->regularRefinement = regular; 9329 PetscFunctionReturn(0); 9330 } 9331 9332 /* anchors */ 9333 /*@ 9334 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9335 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9336 9337 not collective 9338 9339 Input Parameter: 9340 . dm - The DMPlex object 9341 9342 Output Parameters: 9343 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9344 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9345 9346 Level: intermediate 9347 9348 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9349 @*/ 9350 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9351 { 9352 DM_Plex *plex = (DM_Plex *)dm->data; 9353 9354 PetscFunctionBegin; 9355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9356 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9357 if (anchorSection) *anchorSection = plex->anchorSection; 9358 if (anchorIS) *anchorIS = plex->anchorIS; 9359 PetscFunctionReturn(0); 9360 } 9361 9362 /*@ 9363 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9364 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9365 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9366 9367 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9368 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9369 9370 collective on dm 9371 9372 Input Parameters: 9373 + dm - The DMPlex object 9374 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 9375 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9376 9377 The reference counts of anchorSection and anchorIS are incremented. 9378 9379 Level: intermediate 9380 9381 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9382 @*/ 9383 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9384 { 9385 DM_Plex *plex = (DM_Plex *)dm->data; 9386 PetscMPIInt result; 9387 9388 PetscFunctionBegin; 9389 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9390 if (anchorSection) { 9391 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9392 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9393 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9394 } 9395 if (anchorIS) { 9396 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9397 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9398 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9399 } 9400 9401 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9402 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9403 plex->anchorSection = anchorSection; 9404 9405 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9406 PetscCall(ISDestroy(&plex->anchorIS)); 9407 plex->anchorIS = anchorIS; 9408 9409 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9410 PetscInt size, a, pStart, pEnd; 9411 const PetscInt *anchors; 9412 9413 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9414 PetscCall(ISGetLocalSize(anchorIS,&size)); 9415 PetscCall(ISGetIndices(anchorIS,&anchors)); 9416 for (a = 0; a < size; a++) { 9417 PetscInt p; 9418 9419 p = anchors[a]; 9420 if (p >= pStart && p < pEnd) { 9421 PetscInt dof; 9422 9423 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9424 if (dof) { 9425 9426 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9427 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9428 } 9429 } 9430 } 9431 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9432 } 9433 /* reset the generic constraints */ 9434 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9435 PetscFunctionReturn(0); 9436 } 9437 9438 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9439 { 9440 PetscSection anchorSection; 9441 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9442 9443 PetscFunctionBegin; 9444 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9445 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9446 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9447 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9448 if (numFields) { 9449 PetscInt f; 9450 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9451 9452 for (f = 0; f < numFields; f++) { 9453 PetscInt numComp; 9454 9455 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9456 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9457 } 9458 } 9459 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9460 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9461 pStart = PetscMax(pStart,sStart); 9462 pEnd = PetscMin(pEnd,sEnd); 9463 pEnd = PetscMax(pStart,pEnd); 9464 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9465 for (p = pStart; p < pEnd; p++) { 9466 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9467 if (dof) { 9468 PetscCall(PetscSectionGetDof(section,p,&dof)); 9469 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9470 for (f = 0; f < numFields; f++) { 9471 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9472 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9473 } 9474 } 9475 } 9476 PetscCall(PetscSectionSetUp(*cSec)); 9477 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9478 PetscFunctionReturn(0); 9479 } 9480 9481 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9482 { 9483 PetscSection aSec; 9484 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9485 const PetscInt *anchors; 9486 PetscInt numFields, f; 9487 IS aIS; 9488 MatType mtype; 9489 PetscBool iscuda,iskokkos; 9490 9491 PetscFunctionBegin; 9492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9493 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9494 PetscCall(PetscSectionGetStorageSize(section, &n)); 9495 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9496 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9497 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9498 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9499 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9500 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9501 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9502 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9503 else mtype = MATSEQAIJ; 9504 PetscCall(MatSetType(*cMat,mtype)); 9505 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9506 PetscCall(ISGetIndices(aIS,&anchors)); 9507 /* cSec will be a subset of aSec and section */ 9508 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9509 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9510 PetscCall(PetscMalloc1(m+1,&i)); 9511 i[0] = 0; 9512 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9513 for (p = pStart; p < pEnd; p++) { 9514 PetscInt rDof, rOff, r; 9515 9516 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9517 if (!rDof) continue; 9518 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9519 if (numFields) { 9520 for (f = 0; f < numFields; f++) { 9521 annz = 0; 9522 for (r = 0; r < rDof; r++) { 9523 a = anchors[rOff + r]; 9524 if (a < sStart || a >= sEnd) continue; 9525 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9526 annz += aDof; 9527 } 9528 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9529 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9530 for (q = 0; q < dof; q++) { 9531 i[off + q + 1] = i[off + q] + annz; 9532 } 9533 } 9534 } else { 9535 annz = 0; 9536 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9537 for (q = 0; q < dof; q++) { 9538 a = anchors[rOff + q]; 9539 if (a < sStart || a >= sEnd) continue; 9540 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9541 annz += aDof; 9542 } 9543 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9544 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9545 for (q = 0; q < dof; q++) { 9546 i[off + q + 1] = i[off + q] + annz; 9547 } 9548 } 9549 } 9550 nnz = i[m]; 9551 PetscCall(PetscMalloc1(nnz,&j)); 9552 offset = 0; 9553 for (p = pStart; p < pEnd; p++) { 9554 if (numFields) { 9555 for (f = 0; f < numFields; f++) { 9556 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9557 for (q = 0; q < dof; q++) { 9558 PetscInt rDof, rOff, r; 9559 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9560 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9561 for (r = 0; r < rDof; r++) { 9562 PetscInt s; 9563 9564 a = anchors[rOff + r]; 9565 if (a < sStart || a >= sEnd) continue; 9566 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9567 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9568 for (s = 0; s < aDof; s++) { 9569 j[offset++] = aOff + s; 9570 } 9571 } 9572 } 9573 } 9574 } else { 9575 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9576 for (q = 0; q < dof; q++) { 9577 PetscInt rDof, rOff, r; 9578 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9579 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9580 for (r = 0; r < rDof; r++) { 9581 PetscInt s; 9582 9583 a = anchors[rOff + r]; 9584 if (a < sStart || a >= sEnd) continue; 9585 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9586 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9587 for (s = 0; s < aDof; s++) { 9588 j[offset++] = aOff + s; 9589 } 9590 } 9591 } 9592 } 9593 } 9594 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9595 PetscCall(PetscFree(i)); 9596 PetscCall(PetscFree(j)); 9597 PetscCall(ISRestoreIndices(aIS,&anchors)); 9598 PetscFunctionReturn(0); 9599 } 9600 9601 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9602 { 9603 DM_Plex *plex = (DM_Plex *)dm->data; 9604 PetscSection anchorSection, section, cSec; 9605 Mat cMat; 9606 9607 PetscFunctionBegin; 9608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9609 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9610 if (anchorSection) { 9611 PetscInt Nf; 9612 9613 PetscCall(DMGetLocalSection(dm,§ion)); 9614 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9615 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9616 PetscCall(DMGetNumFields(dm,&Nf)); 9617 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9618 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9619 PetscCall(PetscSectionDestroy(&cSec)); 9620 PetscCall(MatDestroy(&cMat)); 9621 } 9622 PetscFunctionReturn(0); 9623 } 9624 9625 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9626 { 9627 IS subis; 9628 PetscSection section, subsection; 9629 9630 PetscFunctionBegin; 9631 PetscCall(DMGetLocalSection(dm, §ion)); 9632 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9633 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9634 /* Create subdomain */ 9635 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9636 /* Create submodel */ 9637 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9638 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9639 PetscCall(DMSetLocalSection(*subdm, subsection)); 9640 PetscCall(PetscSectionDestroy(&subsection)); 9641 PetscCall(DMCopyDisc(dm, *subdm)); 9642 /* Create map from submodel to global model */ 9643 if (is) { 9644 PetscSection sectionGlobal, subsectionGlobal; 9645 IS spIS; 9646 const PetscInt *spmap; 9647 PetscInt *subIndices; 9648 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9649 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9650 9651 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9652 PetscCall(ISGetIndices(spIS, &spmap)); 9653 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9654 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9655 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9656 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9657 for (p = pStart; p < pEnd; ++p) { 9658 PetscInt gdof, pSubSize = 0; 9659 9660 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9661 if (gdof > 0) { 9662 for (f = 0; f < Nf; ++f) { 9663 PetscInt fdof, fcdof; 9664 9665 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9666 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9667 pSubSize += fdof-fcdof; 9668 } 9669 subSize += pSubSize; 9670 if (pSubSize) { 9671 if (bs < 0) { 9672 bs = pSubSize; 9673 } else if (bs != pSubSize) { 9674 /* Layout does not admit a pointwise block size */ 9675 bs = 1; 9676 } 9677 } 9678 } 9679 } 9680 /* Must have same blocksize on all procs (some might have no points) */ 9681 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9682 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9683 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9684 else {bs = bsMinMax[0];} 9685 PetscCall(PetscMalloc1(subSize, &subIndices)); 9686 for (p = pStart; p < pEnd; ++p) { 9687 PetscInt gdof, goff; 9688 9689 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9690 if (gdof > 0) { 9691 const PetscInt point = spmap[p]; 9692 9693 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9694 for (f = 0; f < Nf; ++f) { 9695 PetscInt fdof, fcdof, fc, f2, poff = 0; 9696 9697 /* Can get rid of this loop by storing field information in the global section */ 9698 for (f2 = 0; f2 < f; ++f2) { 9699 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9700 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9701 poff += fdof-fcdof; 9702 } 9703 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9704 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9705 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9706 subIndices[subOff] = goff+poff+fc; 9707 } 9708 } 9709 } 9710 } 9711 PetscCall(ISRestoreIndices(spIS, &spmap)); 9712 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9713 if (bs > 1) { 9714 /* We need to check that the block size does not come from non-contiguous fields */ 9715 PetscInt i, j, set = 1; 9716 for (i = 0; i < subSize; i += bs) { 9717 for (j = 0; j < bs; ++j) { 9718 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9719 } 9720 } 9721 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9722 } 9723 /* Attach nullspace */ 9724 for (f = 0; f < Nf; ++f) { 9725 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9726 if ((*subdm)->nullspaceConstructors[f]) break; 9727 } 9728 if (f < Nf) { 9729 MatNullSpace nullSpace; 9730 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9731 9732 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9733 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9734 } 9735 } 9736 PetscFunctionReturn(0); 9737 } 9738 9739 /*@ 9740 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9741 9742 Input Parameter: 9743 - dm - The DM 9744 9745 Level: developer 9746 9747 Options Database Keys: 9748 . -dm_plex_monitor_throughput - Activate the monitor 9749 9750 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9751 @*/ 9752 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9753 { 9754 #if defined(PETSC_USE_LOG) 9755 PetscStageLog stageLog; 9756 PetscLogEvent event; 9757 PetscLogStage stage; 9758 PetscEventPerfInfo eventInfo; 9759 PetscReal cellRate, flopRate; 9760 PetscInt cStart, cEnd, Nf, N; 9761 const char *name; 9762 #endif 9763 9764 PetscFunctionBegin; 9765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9766 #if defined(PETSC_USE_LOG) 9767 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9768 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9769 PetscCall(DMGetNumFields(dm, &Nf)); 9770 PetscCall(PetscLogGetStageLog(&stageLog)); 9771 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9772 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9773 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9774 N = (cEnd - cStart)*Nf*eventInfo.count; 9775 flopRate = eventInfo.flops/eventInfo.time; 9776 cellRate = N/eventInfo.time; 9777 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "DM (%s) FE Residual Integration: %" 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))); 9778 #else 9779 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9780 #endif 9781 PetscFunctionReturn(0); 9782 } 9783