1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 13 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso `DMPlexGetSimplexOrBoxCells()`, `DMPlexGetCellType()`, `DMPlexGetHeightStratum()`, `DMPolytopeTypeGetNumVertices()` 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: `VecViewFromOptions()`, `VecView()` 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3] = {0., 0., 0.}; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 929 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors_depth", drawColors, &n, &flg)); 930 PetscCheck(!flg || n == dim+1,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Number of flags %" PetscInt_FMT " != %" PetscInt_FMT " dim+1", n, dim+1); 931 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels)); 932 if (!useLabels) numLabels = 0; 933 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors)); 934 if (!useColors) { 935 numColors = 3; 936 for (c = 0; c < numColors; ++c) PetscCall(PetscStrallocpy(defcolors[c], &colors[c])); 937 } 938 PetscCall(PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors)); 939 if (!useColors) { 940 numLColors = 4; 941 for (c = 0; c < numLColors; ++c) PetscCall(PetscStrallocpy(deflcolors[c], &lcolors[c])); 942 } 943 PetscCall(PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg)); 944 plotEdges = (PetscBool)(depth > 1 && drawNumbers[1] && dim < 3); 945 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg)); 946 PetscCheck(!flg || !plotEdges || depth >= dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 994 } 995 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 996 } 997 if (drawHasse) { 998 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 999 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1001 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1003 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1012 } 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1014 1015 /* Plot vertices */ 1016 PetscCall(VecGetArray(coordinates, &coords)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 for (v = vStart; v < vEnd; ++v) { 1019 PetscInt off, dof, d; 1020 PetscBool isLabeled = PETSC_FALSE; 1021 1022 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1023 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1025 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1026 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1027 for (d = 0; d < dof; ++d) { 1028 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1029 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1030 } 1031 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1032 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1033 for (d = 0; d < dof; ++d) { 1034 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1036 } 1037 if (drawHasse) color = colors[0%numColors]; 1038 else color = colors[rank%numColors]; 1039 for (l = 0; l < numLabels; ++l) { 1040 PetscInt val; 1041 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1042 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1043 } 1044 if (drawNumbers[0]) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1046 } else if (drawColors[0]) { 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1048 } else { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1050 } 1051 } 1052 PetscCall(VecRestoreArray(coordinates, &coords)); 1053 PetscCall(PetscViewerFlush(viewer)); 1054 /* Plot edges */ 1055 if (plotEdges) { 1056 PetscCall(VecGetArray(coordinates, &coords)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1058 for (e = eStart; e < eEnd; ++e) { 1059 const PetscInt *cone; 1060 PetscInt coneSize, offA, offB, dof, d; 1061 1062 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1063 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1064 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1065 PetscCall(DMPlexGetCone(dm, e, &cone)); 1066 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1067 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1068 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1070 for (d = 0; d < dof; ++d) { 1071 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1072 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1073 } 1074 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1075 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1076 for (d = 0; d < dof; ++d) { 1077 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1079 } 1080 if (drawHasse) color = colors[1%numColors]; 1081 else color = colors[rank%numColors]; 1082 for (l = 0; l < numLabels; ++l) { 1083 PetscInt val; 1084 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1085 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1086 } 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1088 } 1089 PetscCall(VecRestoreArray(coordinates, &coords)); 1090 PetscCall(PetscViewerFlush(viewer)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1092 } 1093 /* Plot cells */ 1094 if (dim == 3 || !drawNumbers[1]) { 1095 for (e = eStart; e < eEnd; ++e) { 1096 const PetscInt *cone; 1097 1098 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1099 color = colors[rank%numColors]; 1100 for (l = 0; l < numLabels; ++l) { 1101 PetscInt val; 1102 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1103 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1104 } 1105 PetscCall(DMPlexGetCone(dm, e, &cone)); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1107 } 1108 } else { 1109 DMPolytopeType ct; 1110 1111 /* Drawing a 2D polygon */ 1112 for (c = cStart; c < cEnd; ++c) { 1113 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1115 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1116 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1117 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, e; 1120 1121 PetscCall(DMPlexGetCone(dm, c, &cone)); 1122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1123 for (e = 0; e < coneSize; ++e) { 1124 const PetscInt *econe; 1125 1126 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1127 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1128 } 1129 } else { 1130 PetscInt *closure = NULL; 1131 PetscInt closureSize, Nv = 0, v; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize*2; p += 2) { 1135 const PetscInt point = closure[p]; 1136 1137 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1138 } 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1140 for (v = 0; v <= Nv; ++v) { 1141 const PetscInt vertex = closure[v%Nv]; 1142 1143 if (v > 0) { 1144 if (plotEdges) { 1145 const PetscInt *edge; 1146 PetscInt endpoints[2], ne; 1147 1148 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1149 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1150 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1152 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1153 } else { 1154 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1155 } 1156 } 1157 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1158 } 1159 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 PetscCall(VecGetArray(coordinates, &coords)); 1165 for (c = cStart; c < cEnd; ++c) { 1166 double ccoords[3] = {0.0, 0.0, 0.0}; 1167 PetscBool isLabeled = PETSC_FALSE; 1168 PetscInt *closure = NULL; 1169 PetscInt closureSize, dof, d, n = 0; 1170 1171 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1172 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1174 for (p = 0; p < closureSize*2; p += 2) { 1175 const PetscInt point = closure[p]; 1176 PetscInt off; 1177 1178 if ((point < vStart) || (point >= vEnd)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1181 for (d = 0; d < dof; ++d) { 1182 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1183 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1184 } 1185 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1186 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1187 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1188 ++n; 1189 } 1190 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1191 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1195 } 1196 if (drawHasse) color = colors[depth%numColors]; 1197 else color = colors[rank%numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1201 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1202 } 1203 if (drawNumbers[dim]) { 1204 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1205 } else if (drawColors[dim]) { 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1207 } else { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1209 } 1210 } 1211 PetscCall(VecRestoreArray(coordinates, &coords)); 1212 if (drawHasse) { 1213 color = colors[depth%numColors]; 1214 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1215 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1216 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1217 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1219 1220 color = colors[1%numColors]; 1221 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1226 1227 color = colors[0%numColors]; 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1233 1234 for (p = pStart; p < pEnd; ++p) { 1235 const PetscInt *cone; 1236 PetscInt coneSize, cp; 1237 1238 PetscCall(DMPlexGetCone(dm, p, &cone)); 1239 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1240 for (cp = 0; cp < coneSize; ++cp) { 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1242 } 1243 } 1244 } 1245 PetscCall(PetscViewerFlush(viewer)); 1246 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1249 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1250 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1251 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1252 PetscCall(PetscFree3(names, colors, lcolors)); 1253 PetscCall(PetscBTDestroy(&wp)); 1254 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1255 Vec cown,acown; 1256 VecScatter sct; 1257 ISLocalToGlobalMapping g2l; 1258 IS gid,acis; 1259 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1260 MPI_Group ggroup,ngroup; 1261 PetscScalar *array,nid; 1262 const PetscInt *idxs; 1263 PetscInt *idxs2,*start,*adjacency,*work; 1264 PetscInt64 lm[3],gm[3]; 1265 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1266 PetscMPIInt d1,d2,rank; 1267 1268 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1269 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1270 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1271 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1272 #endif 1273 if (ncomm != MPI_COMM_NULL) { 1274 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1275 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1276 d1 = 0; 1277 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1278 nid = d2; 1279 PetscCallMPI(MPI_Group_free(&ggroup)); 1280 PetscCallMPI(MPI_Group_free(&ngroup)); 1281 PetscCallMPI(MPI_Comm_free(&ncomm)); 1282 } else nid = 0.0; 1283 1284 /* Get connectivity */ 1285 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1286 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1287 1288 /* filter overlapped local cells */ 1289 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1290 PetscCall(ISGetIndices(gid,&idxs)); 1291 PetscCall(ISGetLocalSize(gid,&cum)); 1292 PetscCall(PetscMalloc1(cum,&idxs2)); 1293 for (c = cStart, cum = 0; c < cEnd; c++) { 1294 if (idxs[c-cStart] < 0) continue; 1295 idxs2[cum++] = idxs[c-cStart]; 1296 } 1297 PetscCall(ISRestoreIndices(gid,&idxs)); 1298 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1299 PetscCall(ISDestroy(&gid)); 1300 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1301 1302 /* support for node-aware cell locality */ 1303 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1304 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1305 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1306 PetscCall(VecGetArray(cown,&array)); 1307 for (c = 0; c < numVertices; c++) array[c] = nid; 1308 PetscCall(VecRestoreArray(cown,&array)); 1309 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1310 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1311 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1312 PetscCall(ISDestroy(&acis)); 1313 PetscCall(VecScatterDestroy(&sct)); 1314 PetscCall(VecDestroy(&cown)); 1315 1316 /* compute edgeCut */ 1317 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1318 PetscCall(PetscMalloc1(cum,&work)); 1319 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1320 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1321 PetscCall(ISDestroy(&gid)); 1322 PetscCall(VecGetArray(acown,&array)); 1323 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1324 PetscInt totl; 1325 1326 totl = start[c+1]-start[c]; 1327 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1328 for (i = 0; i < totl; i++) { 1329 if (work[i] < 0) { 1330 ect += 1; 1331 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1332 } 1333 } 1334 } 1335 PetscCall(PetscFree(work)); 1336 PetscCall(VecRestoreArray(acown,&array)); 1337 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1338 lm[1] = -numVertices; 1339 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1340 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1341 lm[0] = ect; /* edgeCut */ 1342 lm[1] = ectn; /* node-aware edgeCut */ 1343 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1344 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1345 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1346 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1347 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1348 #else 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1350 #endif 1351 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1352 PetscCall(PetscFree(start)); 1353 PetscCall(PetscFree(adjacency)); 1354 PetscCall(VecDestroy(&acown)); 1355 } else { 1356 const char *name; 1357 PetscInt *sizes, *hybsizes, *ghostsizes; 1358 PetscInt locDepth, depth, cellHeight, dim, d; 1359 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1360 PetscInt numLabels, l, maxSize = 17; 1361 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1362 MPI_Comm comm; 1363 PetscMPIInt size, rank; 1364 1365 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1366 PetscCallMPI(MPI_Comm_size(comm, &size)); 1367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1368 PetscCall(DMGetDimension(dm, &dim)); 1369 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1370 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1371 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1372 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1373 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1374 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1375 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1376 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1377 gcNum = gcEnd - gcStart; 1378 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1379 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1380 for (d = 0; d <= depth; d++) { 1381 PetscInt Nc[2] = {0, 0}, ict; 1382 1383 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1384 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1385 ict = ct0; 1386 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1387 ct0 = (DMPolytopeType) ict; 1388 for (p = pStart; p < pEnd; ++p) { 1389 DMPolytopeType ct; 1390 1391 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1392 if (ct == ct0) ++Nc[0]; 1393 else ++Nc[1]; 1394 } 1395 if (size < maxSize) { 1396 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1397 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1398 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1400 for (p = 0; p < size; ++p) { 1401 if (rank == 0) { 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1403 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1404 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1405 } 1406 } 1407 } else { 1408 PetscInt locMinMax[2]; 1409 1410 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1411 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1412 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1413 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1414 if (d == depth) { 1415 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1416 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1417 } 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1420 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1421 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1422 } 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1424 } 1425 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1426 { 1427 const PetscReal *maxCell; 1428 const PetscReal *L; 1429 const DMBoundaryType *bd; 1430 PetscBool per, localized; 1431 1432 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1433 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1434 if (per) { 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1436 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1437 for (d = 0; d < dim; ++d) { 1438 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1439 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1440 } 1441 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1442 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1443 } 1444 } 1445 PetscCall(DMGetNumLabels(dm, &numLabels)); 1446 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1447 for (l = 0; l < numLabels; ++l) { 1448 DMLabel label; 1449 const char *name; 1450 IS valueIS; 1451 const PetscInt *values; 1452 PetscInt numValues, v; 1453 1454 PetscCall(DMGetLabelName(dm, l, &name)); 1455 PetscCall(DMGetLabel(dm, name, &label)); 1456 PetscCall(DMLabelGetNumValues(label, &numValues)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1459 PetscCall(ISGetIndices(valueIS, &values)); 1460 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1461 for (v = 0; v < numValues; ++v) { 1462 PetscInt size; 1463 1464 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1465 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1467 } 1468 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1469 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1470 PetscCall(ISRestoreIndices(valueIS, &values)); 1471 PetscCall(ISDestroy(&valueIS)); 1472 } 1473 { 1474 char **labelNames; 1475 PetscInt Nl = numLabels; 1476 PetscBool flg; 1477 1478 PetscCall(PetscMalloc1(Nl, &labelNames)); 1479 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1480 for (l = 0; l < Nl; ++l) { 1481 DMLabel label; 1482 1483 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1484 if (flg) { 1485 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1486 PetscCall(DMLabelView(label, viewer)); 1487 } 1488 PetscCall(PetscFree(labelNames[l])); 1489 } 1490 PetscCall(PetscFree(labelNames)); 1491 } 1492 /* If no fields are specified, people do not want to see adjacency */ 1493 if (dm->Nf) { 1494 PetscInt f; 1495 1496 for (f = 0; f < dm->Nf; ++f) { 1497 const char *name; 1498 1499 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1500 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1501 PetscCall(PetscViewerASCIIPushTab(viewer)); 1502 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1503 if (dm->fields[f].adjacency[0]) { 1504 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1505 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1506 } else { 1507 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1508 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1509 } 1510 PetscCall(PetscViewerASCIIPopTab(viewer)); 1511 } 1512 } 1513 PetscCall(DMGetCoarseDM(dm, &cdm)); 1514 if (cdm) { 1515 PetscCall(PetscViewerASCIIPushTab(viewer)); 1516 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1517 PetscCall(PetscViewerASCIIPopTab(viewer)); 1518 } 1519 } 1520 PetscFunctionReturn(0); 1521 } 1522 1523 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1524 { 1525 DMPolytopeType ct; 1526 PetscMPIInt rank; 1527 PetscInt cdim; 1528 1529 PetscFunctionBegin; 1530 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1531 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1532 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1533 switch (ct) { 1534 case DM_POLYTOPE_SEGMENT: 1535 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1536 switch (cdim) { 1537 case 1: 1538 { 1539 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1540 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1541 1542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1543 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1544 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1545 } 1546 break; 1547 case 2: 1548 { 1549 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1550 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1551 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1556 } 1557 break; 1558 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1559 } 1560 break; 1561 case DM_POLYTOPE_TRIANGLE: 1562 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1563 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1564 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1565 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1569 break; 1570 case DM_POLYTOPE_QUADRILATERAL: 1571 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1572 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1573 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1583 break; 1584 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1585 } 1586 PetscFunctionReturn(0); 1587 } 1588 1589 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1590 { 1591 DMPolytopeType ct; 1592 PetscReal centroid[2] = {0., 0.}; 1593 PetscMPIInt rank; 1594 PetscInt fillColor, v, e, d; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1600 switch (ct) { 1601 case DM_POLYTOPE_TRIANGLE: 1602 { 1603 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1604 1605 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1606 for (e = 0; e < 3; ++e) { 1607 refCoords[0] = refVertices[e*2+0]; 1608 refCoords[1] = refVertices[e*2+1]; 1609 for (d = 1; d <= edgeDiv; ++d) { 1610 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1611 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1612 } 1613 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1614 for (d = 0; d < edgeDiv; ++d) { 1615 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1616 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1617 } 1618 } 1619 } 1620 break; 1621 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1622 } 1623 PetscFunctionReturn(0); 1624 } 1625 1626 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1627 { 1628 PetscDraw draw; 1629 DM cdm; 1630 PetscSection coordSection; 1631 Vec coordinates; 1632 const PetscScalar *coords; 1633 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1634 PetscReal *refCoords, *edgeCoords; 1635 PetscBool isnull, drawAffine = PETSC_TRUE; 1636 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1637 1638 PetscFunctionBegin; 1639 PetscCall(DMGetCoordinateDim(dm, &dim)); 1640 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1641 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1642 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1643 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1644 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1645 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1646 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1647 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1648 1649 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1650 PetscCall(PetscDrawIsNull(draw, &isnull)); 1651 if (isnull) PetscFunctionReturn(0); 1652 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1653 1654 PetscCall(VecGetLocalSize(coordinates, &N)); 1655 PetscCall(VecGetArrayRead(coordinates, &coords)); 1656 for (c = 0; c < N; c += dim) { 1657 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1658 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1659 } 1660 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1661 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1662 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1663 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1664 PetscCall(PetscDrawClear(draw)); 1665 1666 for (c = cStart; c < cEnd; ++c) { 1667 PetscScalar *coords = NULL; 1668 PetscInt numCoords; 1669 1670 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1671 if (drawAffine) { 1672 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1673 } else { 1674 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1675 } 1676 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1677 } 1678 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1679 PetscCall(PetscDrawFlush(draw)); 1680 PetscCall(PetscDrawPause(draw)); 1681 PetscCall(PetscDrawSave(draw)); 1682 PetscFunctionReturn(0); 1683 } 1684 1685 #if defined(PETSC_HAVE_EXODUSII) 1686 #include <exodusII.h> 1687 #include <petscviewerexodusii.h> 1688 #endif 1689 1690 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1691 { 1692 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1693 char name[PETSC_MAX_PATH_LEN]; 1694 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1697 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1698 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1699 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1704 if (iascii) { 1705 PetscViewerFormat format; 1706 PetscCall(PetscViewerGetFormat(viewer, &format)); 1707 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1708 PetscCall(DMPlexView_GLVis(dm, viewer)); 1709 } else { 1710 PetscCall(DMPlexView_Ascii(dm, viewer)); 1711 } 1712 } else if (ishdf5) { 1713 #if defined(PETSC_HAVE_HDF5) 1714 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1715 #else 1716 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1717 #endif 1718 } else if (isvtk) { 1719 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1720 } else if (isdraw) { 1721 PetscCall(DMPlexView_Draw(dm, viewer)); 1722 } else if (isglvis) { 1723 PetscCall(DMPlexView_GLVis(dm, viewer)); 1724 #if defined(PETSC_HAVE_EXODUSII) 1725 } else if (isexodus) { 1726 /* 1727 exodusII requires that all sets be part of exactly one cell set. 1728 If the dm does not have a "Cell Sets" label defined, we create one 1729 with ID 1, containig all cells. 1730 Note that if the Cell Sets label is defined but does not cover all cells, 1731 we may still have a problem. This should probably be checked here or in the viewer; 1732 */ 1733 PetscInt numCS; 1734 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1735 if (!numCS) { 1736 PetscInt cStart, cEnd, c; 1737 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1738 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1739 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1740 } 1741 PetscCall(DMView_PlexExodusII(dm, viewer)); 1742 #endif 1743 } else { 1744 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1745 } 1746 /* Optionally view the partition */ 1747 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1748 if (flg) { 1749 Vec ranks; 1750 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1751 PetscCall(VecView(ranks, viewer)); 1752 PetscCall(VecDestroy(&ranks)); 1753 } 1754 /* Optionally view a label */ 1755 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1756 if (flg) { 1757 DMLabel label; 1758 Vec val; 1759 1760 PetscCall(DMGetLabel(dm, name, &label)); 1761 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1762 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1763 PetscCall(VecView(val, viewer)); 1764 PetscCall(VecDestroy(&val)); 1765 } 1766 PetscFunctionReturn(0); 1767 } 1768 1769 /*@ 1770 DMPlexTopologyView - Saves a DMPlex topology into a file 1771 1772 Collective on DM 1773 1774 Input Parameters: 1775 + dm - The DM whose topology is to be saved 1776 - viewer - The PetscViewer for saving 1777 1778 Level: advanced 1779 1780 .seealso: `DMView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexTopologyLoad()` 1781 @*/ 1782 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1783 { 1784 PetscBool ishdf5; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1790 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 IS globalPointNumbering; 1797 1798 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1799 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1800 PetscCall(ISDestroy(&globalPointNumbering)); 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1802 #else 1803 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1804 #endif 1805 } 1806 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1807 PetscFunctionReturn(0); 1808 } 1809 1810 /*@ 1811 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1812 1813 Collective on DM 1814 1815 Input Parameters: 1816 + dm - The DM whose coordinates are to be saved 1817 - viewer - The PetscViewer for saving 1818 1819 Level: advanced 1820 1821 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexLabelsView()`, `DMPlexCoordinatesLoad()` 1822 @*/ 1823 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1824 { 1825 PetscBool ishdf5; 1826 1827 PetscFunctionBegin; 1828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1829 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1830 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1831 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1832 if (ishdf5) { 1833 #if defined(PETSC_HAVE_HDF5) 1834 PetscViewerFormat format; 1835 PetscCall(PetscViewerGetFormat(viewer, &format)); 1836 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1837 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1838 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1839 #else 1840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1841 #endif 1842 } 1843 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1844 PetscFunctionReturn(0); 1845 } 1846 1847 /*@ 1848 DMPlexLabelsView - Saves DMPlex labels into a file 1849 1850 Collective on DM 1851 1852 Input Parameters: 1853 + dm - The DM whose labels are to be saved 1854 - viewer - The PetscViewer for saving 1855 1856 Level: advanced 1857 1858 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsLoad()` 1859 @*/ 1860 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1861 { 1862 PetscBool ishdf5; 1863 1864 PetscFunctionBegin; 1865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1866 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1867 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1868 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1869 if (ishdf5) { 1870 #if defined(PETSC_HAVE_HDF5) 1871 IS globalPointNumbering; 1872 PetscViewerFormat format; 1873 1874 PetscCall(PetscViewerGetFormat(viewer, &format)); 1875 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1876 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1877 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1878 PetscCall(ISDestroy(&globalPointNumbering)); 1879 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1880 #else 1881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1882 #endif 1883 } 1884 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1885 PetscFunctionReturn(0); 1886 } 1887 1888 /*@ 1889 DMPlexSectionView - Saves a section associated with a DMPlex 1890 1891 Collective on DM 1892 1893 Input Parameters: 1894 + dm - The DM that contains the topology on which the section to be saved is defined 1895 . viewer - The PetscViewer for saving 1896 - sectiondm - The DM that contains the section to be saved 1897 1898 Level: advanced 1899 1900 Notes: 1901 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1902 1903 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1904 1905 .seealso: `DMView()`, `DMPlexTopologyView()`, `DMPlexCoordinatesView()`, `DMPlexLabelsView()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()`, `PetscSectionView()`, `DMPlexSectionLoad()` 1906 @*/ 1907 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1908 { 1909 PetscBool ishdf5; 1910 1911 PetscFunctionBegin; 1912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1913 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1914 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1916 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1917 if (ishdf5) { 1918 #if defined(PETSC_HAVE_HDF5) 1919 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1920 #else 1921 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1922 #endif 1923 } 1924 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@ 1929 DMPlexGlobalVectorView - Saves a global vector 1930 1931 Collective on DM 1932 1933 Input Parameters: 1934 + dm - The DM that represents the topology 1935 . viewer - The PetscViewer to save data with 1936 . sectiondm - The DM that contains the global section on which vec is defined 1937 - vec - The global vector to be saved 1938 1939 Level: advanced 1940 1941 Notes: 1942 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1943 1944 Typical calling sequence 1945 $ DMCreate(PETSC_COMM_WORLD, &dm); 1946 $ DMSetType(dm, DMPLEX); 1947 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1948 $ DMClone(dm, §iondm); 1949 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1950 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1951 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1952 $ PetscSectionSetChart(section, pStart, pEnd); 1953 $ PetscSectionSetUp(section); 1954 $ DMSetLocalSection(sectiondm, section); 1955 $ PetscSectionDestroy(§ion); 1956 $ DMGetGlobalVector(sectiondm, &vec); 1957 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1958 $ DMPlexTopologyView(dm, viewer); 1959 $ DMPlexSectionView(dm, viewer, sectiondm); 1960 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1961 $ DMRestoreGlobalVector(sectiondm, &vec); 1962 $ DMDestroy(§iondm); 1963 $ DMDestroy(&dm); 1964 1965 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexLocalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 1966 @*/ 1967 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1968 { 1969 PetscBool ishdf5; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1975 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1976 /* Check consistency */ 1977 { 1978 PetscSection section; 1979 PetscBool includesConstraints; 1980 PetscInt m, m1; 1981 1982 PetscCall(VecGetLocalSize(vec, &m1)); 1983 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1984 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1985 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1986 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1987 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1988 } 1989 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1990 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1991 if (ishdf5) { 1992 #if defined(PETSC_HAVE_HDF5) 1993 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1999 PetscFunctionReturn(0); 2000 } 2001 2002 /*@ 2003 DMPlexLocalVectorView - Saves a local vector 2004 2005 Collective on DM 2006 2007 Input Parameters: 2008 + dm - The DM that represents the topology 2009 . viewer - The PetscViewer to save data with 2010 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2011 - vec - The local vector to be saved 2012 2013 Level: advanced 2014 2015 Notes: 2016 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2017 2018 Typical calling sequence 2019 $ DMCreate(PETSC_COMM_WORLD, &dm); 2020 $ DMSetType(dm, DMPLEX); 2021 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2022 $ DMClone(dm, §iondm); 2023 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2024 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2025 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2026 $ PetscSectionSetChart(section, pStart, pEnd); 2027 $ PetscSectionSetUp(section); 2028 $ DMSetLocalSection(sectiondm, section); 2029 $ DMGetLocalVector(sectiondm, &vec); 2030 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 $ DMPlexTopologyView(dm, viewer); 2032 $ DMPlexSectionView(dm, viewer, sectiondm); 2033 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2034 $ DMRestoreLocalVector(sectiondm, &vec); 2035 $ DMDestroy(§iondm); 2036 $ DMDestroy(&dm); 2037 2038 .seealso: `DMPlexTopologyView()`, `DMPlexSectionView()`, `DMPlexGlobalVectorView()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()` 2039 @*/ 2040 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2072 PetscFunctionReturn(0); 2073 } 2074 2075 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2076 { 2077 PetscBool ishdf5; 2078 2079 PetscFunctionBegin; 2080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2081 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2082 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2088 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2089 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2090 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2091 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2092 PetscFunctionReturn(0); 2093 #else 2094 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2095 #endif 2096 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2097 } 2098 2099 /*@ 2100 DMPlexTopologyLoad - Loads a topology into a DMPlex 2101 2102 Collective on DM 2103 2104 Input Parameters: 2105 + dm - The DM into which the topology is loaded 2106 - viewer - The PetscViewer for the saved topology 2107 2108 Output Parameters: 2109 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2110 2111 Level: advanced 2112 2113 .seealso: `DMLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2114 @*/ 2115 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2123 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2124 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2125 if (ishdf5) { 2126 #if defined(PETSC_HAVE_HDF5) 2127 PetscViewerFormat format; 2128 PetscCall(PetscViewerGetFormat(viewer, &format)); 2129 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2130 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2131 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2132 #else 2133 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2134 #endif 2135 } 2136 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2137 PetscFunctionReturn(0); 2138 } 2139 2140 /*@ 2141 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2142 2143 Collective on DM 2144 2145 Input Parameters: 2146 + dm - The DM into which the coordinates are loaded 2147 . viewer - The PetscViewer for the saved coordinates 2148 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2149 2150 Level: advanced 2151 2152 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexLabelsLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2153 @*/ 2154 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2155 { 2156 PetscBool ishdf5; 2157 2158 PetscFunctionBegin; 2159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2160 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2161 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2162 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsLoad - Loads labels into a DMPlex 2181 2182 Collective on DM 2183 2184 Input Parameters: 2185 + dm - The DM into which the labels are loaded 2186 . viewer - The PetscViewer for the saved labels 2187 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2188 2189 Level: advanced 2190 2191 Notes: 2192 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2193 2194 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMView()`, `PetscViewerHDF5Open()`, `PetscViewerPushFormat()` 2195 @*/ 2196 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2197 { 2198 PetscBool ishdf5; 2199 2200 PetscFunctionBegin; 2201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2203 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscViewerFormat format; 2209 2210 PetscCall(PetscViewerGetFormat(viewer, &format)); 2211 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2212 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2213 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2214 #else 2215 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2216 #endif 2217 } 2218 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@ 2223 DMPlexSectionLoad - Loads section into a DMPlex 2224 2225 Collective on DM 2226 2227 Input Parameters: 2228 + dm - The DM that represents the topology 2229 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2230 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2231 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2232 2233 Output Parameters 2234 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2235 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2236 2237 Level: advanced 2238 2239 Notes: 2240 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2241 2242 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2243 2244 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2245 2246 Example using 2 processes: 2247 $ NX (number of points on dm): 4 2248 $ sectionA : the on-disk section 2249 $ vecA : a vector associated with sectionA 2250 $ sectionB : sectiondm's local section constructed in this function 2251 $ vecB (local) : a vector associated with sectiondm's local section 2252 $ vecB (global) : a vector associated with sectiondm's global section 2253 $ 2254 $ rank 0 rank 1 2255 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2256 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2257 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2258 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2259 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2260 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2261 $ sectionB->atlasDof : 1 0 1 | 1 3 2262 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2263 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2264 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2265 $ 2266 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2267 2268 .seealso: `DMLoad()`, `DMPlexTopologyLoad()`, `DMPlexCoordinatesLoad()`, `DMPlexLabelsLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexLocalVectorLoad()`, `PetscSectionLoad()`, `DMPlexSectionView()` 2269 @*/ 2270 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2279 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2280 if (localDofSF) PetscValidPointer(localDofSF, 6); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2296 2297 Collective on DM 2298 2299 Input Parameters: 2300 + dm - The DM that represents the topology 2301 . viewer - The PetscViewer that represents the on-disk vector data 2302 . sectiondm - The DM that contains the global section on which vec is defined 2303 . sf - The SF that migrates the on-disk vector data into vec 2304 - vec - The global vector to set values of 2305 2306 Level: advanced 2307 2308 Notes: 2309 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2310 2311 Typical calling sequence 2312 $ DMCreate(PETSC_COMM_WORLD, &dm); 2313 $ DMSetType(dm, DMPLEX); 2314 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2316 $ DMClone(dm, §iondm); 2317 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2319 $ DMGetGlobalVector(sectiondm, &vec); 2320 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2322 $ DMRestoreGlobalVector(sectiondm, &vec); 2323 $ PetscSFDestroy(&gsf); 2324 $ PetscSFDestroy(&sfX); 2325 $ DMDestroy(§iondm); 2326 $ DMDestroy(&dm); 2327 2328 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexLocalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2329 @*/ 2330 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2331 { 2332 PetscBool ishdf5; 2333 2334 PetscFunctionBegin; 2335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2336 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2337 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2338 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2339 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2340 /* Check consistency */ 2341 { 2342 PetscSection section; 2343 PetscBool includesConstraints; 2344 PetscInt m, m1; 2345 2346 PetscCall(VecGetLocalSize(vec, &m1)); 2347 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2348 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2349 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2350 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2351 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2352 } 2353 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2354 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2355 if (ishdf5) { 2356 #if defined(PETSC_HAVE_HDF5) 2357 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2358 #else 2359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2360 #endif 2361 } 2362 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2368 2369 Collective on DM 2370 2371 Input Parameters: 2372 + dm - The DM that represents the topology 2373 . viewer - The PetscViewer that represents the on-disk vector data 2374 . sectiondm - The DM that contains the local section on which vec is defined 2375 . sf - The SF that migrates the on-disk vector data into vec 2376 - vec - The local vector to set values of 2377 2378 Level: advanced 2379 2380 Notes: 2381 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Typical calling sequence 2384 $ DMCreate(PETSC_COMM_WORLD, &dm); 2385 $ DMSetType(dm, DMPLEX); 2386 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2387 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2388 $ DMClone(dm, §iondm); 2389 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2391 $ DMGetLocalVector(sectiondm, &vec); 2392 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2393 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2394 $ DMRestoreLocalVector(sectiondm, &vec); 2395 $ PetscSFDestroy(&lsf); 2396 $ PetscSFDestroy(&sfX); 2397 $ DMDestroy(§iondm); 2398 $ DMDestroy(&dm); 2399 2400 .seealso: `DMPlexTopologyLoad()`, `DMPlexSectionLoad()`, `DMPlexGlobalVectorLoad()`, `DMPlexGlobalVectorView()`, `DMPlexLocalVectorView()` 2401 @*/ 2402 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2403 { 2404 PetscBool ishdf5; 2405 2406 PetscFunctionBegin; 2407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2408 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2409 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2410 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2411 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2412 /* Check consistency */ 2413 { 2414 PetscSection section; 2415 PetscBool includesConstraints; 2416 PetscInt m, m1; 2417 2418 PetscCall(VecGetLocalSize(vec, &m1)); 2419 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2420 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2421 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2422 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2423 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2424 } 2425 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2426 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2427 if (ishdf5) { 2428 #if defined(PETSC_HAVE_HDF5) 2429 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2435 PetscFunctionReturn(0); 2436 } 2437 2438 PetscErrorCode DMDestroy_Plex(DM dm) 2439 { 2440 DM_Plex *mesh = (DM_Plex*) dm->data; 2441 2442 PetscFunctionBegin; 2443 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2444 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2445 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2446 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2447 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertTimeDerviativeBoundaryValues_C", NULL)); 2448 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C", NULL)); 2449 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeGetDefault_C", NULL)); 2450 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexDistributeSetDefault_C", NULL)); 2451 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 2452 if (--mesh->refct > 0) PetscFunctionReturn(0); 2453 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2454 PetscCall(PetscFree(mesh->cones)); 2455 PetscCall(PetscFree(mesh->coneOrientations)); 2456 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2457 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2458 PetscCall(PetscFree(mesh->supports)); 2459 PetscCall(PetscFree(mesh->facesTmp)); 2460 PetscCall(PetscFree(mesh->tetgenOpts)); 2461 PetscCall(PetscFree(mesh->triangleOpts)); 2462 PetscCall(PetscFree(mesh->transformType)); 2463 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2464 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2465 PetscCall(ISDestroy(&mesh->subpointIS)); 2466 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2467 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2468 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2469 PetscCall(ISDestroy(&mesh->anchorIS)); 2470 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2471 PetscCall(PetscFree(mesh->parents)); 2472 PetscCall(PetscFree(mesh->childIDs)); 2473 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2474 PetscCall(PetscFree(mesh->children)); 2475 PetscCall(DMDestroy(&mesh->referenceTree)); 2476 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2477 PetscCall(PetscFree(mesh->neighbors)); 2478 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2479 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2480 PetscCall(PetscFree(mesh)); 2481 PetscFunctionReturn(0); 2482 } 2483 2484 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2485 { 2486 PetscSection sectionGlobal; 2487 PetscInt bs = -1, mbs; 2488 PetscInt localSize; 2489 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2490 MatType mtype; 2491 ISLocalToGlobalMapping ltog; 2492 2493 PetscFunctionBegin; 2494 PetscCall(MatInitializePackage()); 2495 mtype = dm->mattype; 2496 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2497 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2498 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2499 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2500 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2501 PetscCall(MatSetType(*J, mtype)); 2502 PetscCall(MatSetFromOptions(*J)); 2503 PetscCall(MatGetBlockSize(*J, &mbs)); 2504 if (mbs > 1) bs = mbs; 2505 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2506 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2507 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2508 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2509 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2510 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2511 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2512 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2513 if (!isShell) { 2514 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2515 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2]; 2516 PetscInt pStart, pEnd, p, dof, cdof; 2517 2518 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2519 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2520 for (p = pStart; p < pEnd; ++p) { 2521 PetscInt bdof; 2522 2523 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2524 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2525 dof = dof < 0 ? -(dof+1) : dof; 2526 bdof = cdof && (dof-cdof) ? 1 : dof; 2527 if (dof) { 2528 if (bs < 0) {bs = bdof;} 2529 else if (bs != bdof) {bs = 1; break;} 2530 } 2531 } 2532 /* Must have same blocksize on all procs (some might have no points) */ 2533 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2534 bsLocal[1] = bs; 2535 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2536 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2537 else bs = bsMinMax[0]; 2538 bs = PetscMax(1,bs); 2539 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2540 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2541 PetscCall(MatSetBlockSize(*J, bs)); 2542 PetscCall(MatSetUp(*J)); 2543 } else { 2544 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2545 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2546 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2547 } 2548 } 2549 PetscCall(MatSetDM(*J, dm)); 2550 PetscFunctionReturn(0); 2551 } 2552 2553 /*@ 2554 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2555 2556 Not collective 2557 2558 Input Parameter: 2559 . mesh - The DMPlex 2560 2561 Output Parameters: 2562 . subsection - The subdomain section 2563 2564 Level: developer 2565 2566 .seealso: 2567 @*/ 2568 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2569 { 2570 DM_Plex *mesh = (DM_Plex*) dm->data; 2571 2572 PetscFunctionBegin; 2573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2574 if (!mesh->subdomainSection) { 2575 PetscSection section; 2576 PetscSF sf; 2577 2578 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2579 PetscCall(DMGetLocalSection(dm,§ion)); 2580 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2581 PetscCall(PetscSFDestroy(&sf)); 2582 } 2583 *subsection = mesh->subdomainSection; 2584 PetscFunctionReturn(0); 2585 } 2586 2587 /*@ 2588 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2589 2590 Not collective 2591 2592 Input Parameter: 2593 . mesh - The DMPlex 2594 2595 Output Parameters: 2596 + pStart - The first mesh point 2597 - pEnd - The upper bound for mesh points 2598 2599 Level: beginner 2600 2601 .seealso: `DMPlexCreate()`, `DMPlexSetChart()` 2602 @*/ 2603 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2604 { 2605 DM_Plex *mesh = (DM_Plex*) dm->data; 2606 2607 PetscFunctionBegin; 2608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2609 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2610 PetscFunctionReturn(0); 2611 } 2612 2613 /*@ 2614 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2615 2616 Not collective 2617 2618 Input Parameters: 2619 + mesh - The DMPlex 2620 . pStart - The first mesh point 2621 - pEnd - The upper bound for mesh points 2622 2623 Output Parameters: 2624 2625 Level: beginner 2626 2627 .seealso: `DMPlexCreate()`, `DMPlexGetChart()` 2628 @*/ 2629 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2630 { 2631 DM_Plex *mesh = (DM_Plex*) dm->data; 2632 2633 PetscFunctionBegin; 2634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2635 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2636 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2637 PetscFunctionReturn(0); 2638 } 2639 2640 /*@ 2641 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2642 2643 Not collective 2644 2645 Input Parameters: 2646 + mesh - The DMPlex 2647 - p - The point, which must lie in the chart set with DMPlexSetChart() 2648 2649 Output Parameter: 2650 . size - The cone size for point p 2651 2652 Level: beginner 2653 2654 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 2655 @*/ 2656 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2657 { 2658 DM_Plex *mesh = (DM_Plex*) dm->data; 2659 2660 PetscFunctionBegin; 2661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2662 PetscValidIntPointer(size, 3); 2663 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2664 PetscFunctionReturn(0); 2665 } 2666 2667 /*@ 2668 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2669 2670 Not collective 2671 2672 Input Parameters: 2673 + mesh - The DMPlex 2674 . p - The point, which must lie in the chart set with DMPlexSetChart() 2675 - size - The cone size for point p 2676 2677 Output Parameter: 2678 2679 Note: 2680 This should be called after DMPlexSetChart(). 2681 2682 Level: beginner 2683 2684 .seealso: `DMPlexCreate()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2685 @*/ 2686 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2687 { 2688 DM_Plex *mesh = (DM_Plex*) dm->data; 2689 2690 PetscFunctionBegin; 2691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2692 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2693 PetscFunctionReturn(0); 2694 } 2695 2696 /*@ 2697 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2698 2699 Not collective 2700 2701 Input Parameters: 2702 + mesh - The DMPlex 2703 . p - The point, which must lie in the chart set with DMPlexSetChart() 2704 - size - The additional cone size for point p 2705 2706 Output Parameter: 2707 2708 Note: 2709 This should be called after DMPlexSetChart(). 2710 2711 Level: beginner 2712 2713 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexGetConeSize()`, `DMPlexSetChart()` 2714 @*/ 2715 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2716 { 2717 DM_Plex *mesh = (DM_Plex*) dm->data; 2718 PetscFunctionBegin; 2719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2720 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2721 PetscFunctionReturn(0); 2722 } 2723 2724 /*@C 2725 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2726 2727 Not collective 2728 2729 Input Parameters: 2730 + dm - The DMPlex 2731 - p - The point, which must lie in the chart set with DMPlexSetChart() 2732 2733 Output Parameter: 2734 . cone - An array of points which are on the in-edges for point p 2735 2736 Level: beginner 2737 2738 Fortran Notes: 2739 Since it returns an array, this routine is only available in Fortran 90, and you must 2740 include petsc.h90 in your code. 2741 You must also call DMPlexRestoreCone() after you finish using the returned array. 2742 DMPlexRestoreCone() is not needed/available in C. 2743 2744 .seealso: `DMPlexGetConeSize()`, `DMPlexSetCone()`, `DMPlexGetConeTuple()`, `DMPlexSetChart()` 2745 @*/ 2746 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2747 { 2748 DM_Plex *mesh = (DM_Plex*) dm->data; 2749 PetscInt off; 2750 2751 PetscFunctionBegin; 2752 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2753 PetscValidPointer(cone, 3); 2754 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2755 *cone = &mesh->cones[off]; 2756 PetscFunctionReturn(0); 2757 } 2758 2759 /*@C 2760 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2761 2762 Not collective 2763 2764 Input Parameters: 2765 + dm - The DMPlex 2766 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2767 2768 Output Parameters: 2769 + pConesSection - PetscSection describing the layout of pCones 2770 - pCones - An array of points which are on the in-edges for the point set p 2771 2772 Level: intermediate 2773 2774 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeRecursive()`, `DMPlexSetChart()` 2775 @*/ 2776 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2777 { 2778 PetscSection cs, newcs; 2779 PetscInt *cones; 2780 PetscInt *newarr=NULL; 2781 PetscInt n; 2782 2783 PetscFunctionBegin; 2784 PetscCall(DMPlexGetCones(dm, &cones)); 2785 PetscCall(DMPlexGetConeSection(dm, &cs)); 2786 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2787 if (pConesSection) *pConesSection = newcs; 2788 if (pCones) { 2789 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2790 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2791 } 2792 PetscFunctionReturn(0); 2793 } 2794 2795 /*@ 2796 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2797 2798 Not collective 2799 2800 Input Parameters: 2801 + dm - The DMPlex 2802 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2803 2804 Output Parameter: 2805 . expandedPoints - An array of vertices recursively expanded from input points 2806 2807 Level: advanced 2808 2809 Notes: 2810 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2811 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2812 2813 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetDepth()` 2814 @*/ 2815 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2816 { 2817 IS *expandedPointsAll; 2818 PetscInt depth; 2819 2820 PetscFunctionBegin; 2821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2822 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2823 PetscValidPointer(expandedPoints, 3); 2824 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2825 *expandedPoints = expandedPointsAll[0]; 2826 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2827 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2828 PetscFunctionReturn(0); 2829 } 2830 2831 /*@ 2832 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). 2833 2834 Not collective 2835 2836 Input Parameters: 2837 + dm - The DMPlex 2838 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2839 2840 Output Parameters: 2841 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2842 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2843 - sections - (optional) An array of sections which describe mappings from points to their cone points 2844 2845 Level: advanced 2846 2847 Notes: 2848 Like DMPlexGetConeTuple() but recursive. 2849 2850 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. 2851 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2852 2853 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: 2854 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2855 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2856 2857 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexRestoreConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2858 @*/ 2859 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2860 { 2861 const PetscInt *arr0=NULL, *cone=NULL; 2862 PetscInt *arr=NULL, *newarr=NULL; 2863 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2864 IS *expandedPoints_; 2865 PetscSection *sections_; 2866 2867 PetscFunctionBegin; 2868 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2869 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2870 if (depth) PetscValidIntPointer(depth, 3); 2871 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2872 if (sections) PetscValidPointer(sections, 5); 2873 PetscCall(ISGetLocalSize(points, &n)); 2874 PetscCall(ISGetIndices(points, &arr0)); 2875 PetscCall(DMPlexGetDepth(dm, &depth_)); 2876 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2877 PetscCall(PetscCalloc1(depth_, §ions_)); 2878 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2879 for (d=depth_-1; d>=0; d--) { 2880 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2881 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2882 for (i=0; i<n; i++) { 2883 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2884 if (arr[i] >= start && arr[i] < end) { 2885 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2886 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2887 } else { 2888 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2889 } 2890 } 2891 PetscCall(PetscSectionSetUp(sections_[d])); 2892 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2893 PetscCall(PetscMalloc1(newn, &newarr)); 2894 for (i=0; i<n; i++) { 2895 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2896 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2897 if (cn > 1) { 2898 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2899 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2900 } else { 2901 newarr[co] = arr[i]; 2902 } 2903 } 2904 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2905 arr = newarr; 2906 n = newn; 2907 } 2908 PetscCall(ISRestoreIndices(points, &arr0)); 2909 *depth = depth_; 2910 if (expandedPoints) *expandedPoints = expandedPoints_; 2911 else { 2912 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2913 PetscCall(PetscFree(expandedPoints_)); 2914 } 2915 if (sections) *sections = sections_; 2916 else { 2917 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2918 PetscCall(PetscFree(sections_)); 2919 } 2920 PetscFunctionReturn(0); 2921 } 2922 2923 /*@ 2924 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2925 2926 Not collective 2927 2928 Input Parameters: 2929 + dm - The DMPlex 2930 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2931 2932 Output Parameters: 2933 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2934 . expandedPoints - (optional) An array of recursively expanded cones 2935 - sections - (optional) An array of sections which describe mappings from points to their cone points 2936 2937 Level: advanced 2938 2939 Notes: 2940 See DMPlexGetConeRecursive() for details. 2941 2942 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexGetConeTuple()`, `DMPlexGetConeRecursive()`, `DMPlexGetConeRecursiveVertices()`, `DMPlexGetDepth()` 2943 @*/ 2944 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2945 { 2946 PetscInt d, depth_; 2947 2948 PetscFunctionBegin; 2949 PetscCall(DMPlexGetDepth(dm, &depth_)); 2950 PetscCheck(!depth || *depth == depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2951 if (depth) *depth = 0; 2952 if (expandedPoints) { 2953 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2954 PetscCall(PetscFree(*expandedPoints)); 2955 } 2956 if (sections) { 2957 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2958 PetscCall(PetscFree(*sections)); 2959 } 2960 PetscFunctionReturn(0); 2961 } 2962 2963 /*@ 2964 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 2965 2966 Not collective 2967 2968 Input Parameters: 2969 + mesh - The DMPlex 2970 . p - The point, which must lie in the chart set with DMPlexSetChart() 2971 - cone - An array of points which are on the in-edges for point p 2972 2973 Output Parameter: 2974 2975 Note: 2976 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2977 2978 Level: beginner 2979 2980 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()`, `DMPlexSetSupport()`, `DMPlexSetSupportSize()` 2981 @*/ 2982 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 2983 { 2984 DM_Plex *mesh = (DM_Plex*) dm->data; 2985 PetscInt pStart, pEnd; 2986 PetscInt dof, off, c; 2987 2988 PetscFunctionBegin; 2989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2990 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 2991 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 2992 if (dof) PetscValidIntPointer(cone, 3); 2993 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2994 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); 2995 for (c = 0; c < dof; ++c) { 2996 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); 2997 mesh->cones[off+c] = cone[c]; 2998 } 2999 PetscFunctionReturn(0); 3000 } 3001 3002 /*@C 3003 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 3004 3005 Not collective 3006 3007 Input Parameters: 3008 + mesh - The DMPlex 3009 - p - The point, which must lie in the chart set with DMPlexSetChart() 3010 3011 Output Parameter: 3012 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3013 integer giving the prescription for cone traversal. 3014 3015 Level: beginner 3016 3017 Notes: 3018 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3019 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3020 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3021 with the identity. 3022 3023 Fortran Notes: 3024 Since it returns an array, this routine is only available in Fortran 90, and you must 3025 include petsc.h90 in your code. 3026 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3027 DMPlexRestoreConeOrientation() is not needed/available in C. 3028 3029 .seealso: `DMPolytopeTypeComposeOrientation()`, `DMPolytopeTypeComposeOrientationInv()`, `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetCone()`, `DMPlexSetChart()` 3030 @*/ 3031 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3032 { 3033 DM_Plex *mesh = (DM_Plex*) dm->data; 3034 PetscInt off; 3035 3036 PetscFunctionBegin; 3037 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3038 if (PetscDefined(USE_DEBUG)) { 3039 PetscInt dof; 3040 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3041 if (dof) PetscValidPointer(coneOrientation, 3); 3042 } 3043 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3044 3045 *coneOrientation = &mesh->coneOrientations[off]; 3046 PetscFunctionReturn(0); 3047 } 3048 3049 /*@ 3050 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3051 3052 Not collective 3053 3054 Input Parameters: 3055 + mesh - The DMPlex 3056 . p - The point, which must lie in the chart set with DMPlexSetChart() 3057 - coneOrientation - An array of orientations 3058 Output Parameter: 3059 3060 Notes: 3061 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3062 3063 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3064 3065 Level: beginner 3066 3067 .seealso: `DMPlexCreate()`, `DMPlexGetConeOrientation()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3068 @*/ 3069 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3070 { 3071 DM_Plex *mesh = (DM_Plex*) dm->data; 3072 PetscInt pStart, pEnd; 3073 PetscInt dof, off, c; 3074 3075 PetscFunctionBegin; 3076 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3077 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3078 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3079 if (dof) PetscValidIntPointer(coneOrientation, 3); 3080 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3081 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); 3082 for (c = 0; c < dof; ++c) { 3083 PetscInt cdof, o = coneOrientation[c]; 3084 3085 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3086 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); 3087 mesh->coneOrientations[off+c] = o; 3088 } 3089 PetscFunctionReturn(0); 3090 } 3091 3092 /*@ 3093 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3094 3095 Not collective 3096 3097 Input Parameters: 3098 + mesh - The DMPlex 3099 . p - The point, which must lie in the chart set with DMPlexSetChart() 3100 . conePos - The local index in the cone where the point should be put 3101 - conePoint - The mesh point to insert 3102 3103 Level: beginner 3104 3105 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3106 @*/ 3107 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3108 { 3109 DM_Plex *mesh = (DM_Plex*) dm->data; 3110 PetscInt pStart, pEnd; 3111 PetscInt dof, off; 3112 3113 PetscFunctionBegin; 3114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3115 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3116 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); 3117 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); 3118 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3119 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3120 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); 3121 mesh->cones[off+conePos] = conePoint; 3122 PetscFunctionReturn(0); 3123 } 3124 3125 /*@ 3126 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3127 3128 Not collective 3129 3130 Input Parameters: 3131 + mesh - The DMPlex 3132 . p - The point, which must lie in the chart set with DMPlexSetChart() 3133 . conePos - The local index in the cone where the point should be put 3134 - coneOrientation - The point orientation to insert 3135 3136 Level: beginner 3137 3138 Notes: 3139 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3140 3141 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3142 @*/ 3143 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3144 { 3145 DM_Plex *mesh = (DM_Plex*) dm->data; 3146 PetscInt pStart, pEnd; 3147 PetscInt dof, off; 3148 3149 PetscFunctionBegin; 3150 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3151 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3152 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); 3153 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3154 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3155 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); 3156 mesh->coneOrientations[off+conePos] = coneOrientation; 3157 PetscFunctionReturn(0); 3158 } 3159 3160 /*@ 3161 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3162 3163 Not collective 3164 3165 Input Parameters: 3166 + mesh - The DMPlex 3167 - p - The point, which must lie in the chart set with DMPlexSetChart() 3168 3169 Output Parameter: 3170 . size - The support size for point p 3171 3172 Level: beginner 3173 3174 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()`, `DMPlexGetConeSize()` 3175 @*/ 3176 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3177 { 3178 DM_Plex *mesh = (DM_Plex*) dm->data; 3179 3180 PetscFunctionBegin; 3181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3182 PetscValidIntPointer(size, 3); 3183 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3184 PetscFunctionReturn(0); 3185 } 3186 3187 /*@ 3188 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3189 3190 Not collective 3191 3192 Input Parameters: 3193 + mesh - The DMPlex 3194 . p - The point, which must lie in the chart set with DMPlexSetChart() 3195 - size - The support size for point p 3196 3197 Output Parameter: 3198 3199 Note: 3200 This should be called after DMPlexSetChart(). 3201 3202 Level: beginner 3203 3204 .seealso: `DMPlexCreate()`, `DMPlexGetSupportSize()`, `DMPlexSetChart()` 3205 @*/ 3206 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3207 { 3208 DM_Plex *mesh = (DM_Plex*) dm->data; 3209 3210 PetscFunctionBegin; 3211 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3212 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3213 PetscFunctionReturn(0); 3214 } 3215 3216 /*@C 3217 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3218 3219 Not collective 3220 3221 Input Parameters: 3222 + mesh - The DMPlex 3223 - p - The point, which must lie in the chart set with DMPlexSetChart() 3224 3225 Output Parameter: 3226 . support - An array of points which are on the out-edges for point p 3227 3228 Level: beginner 3229 3230 Fortran Notes: 3231 Since it returns an array, this routine is only available in Fortran 90, and you must 3232 include petsc.h90 in your code. 3233 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3234 DMPlexRestoreSupport() is not needed/available in C. 3235 3236 .seealso: `DMPlexGetSupportSize()`, `DMPlexSetSupport()`, `DMPlexGetCone()`, `DMPlexSetChart()` 3237 @*/ 3238 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3239 { 3240 DM_Plex *mesh = (DM_Plex*) dm->data; 3241 PetscInt off; 3242 3243 PetscFunctionBegin; 3244 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3245 PetscValidPointer(support, 3); 3246 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3247 *support = &mesh->supports[off]; 3248 PetscFunctionReturn(0); 3249 } 3250 3251 /*@ 3252 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3253 3254 Not collective 3255 3256 Input Parameters: 3257 + mesh - The DMPlex 3258 . p - The point, which must lie in the chart set with DMPlexSetChart() 3259 - support - An array of points which are on the out-edges for point p 3260 3261 Output Parameter: 3262 3263 Note: 3264 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3265 3266 Level: beginner 3267 3268 .seealso: `DMPlexSetCone()`, `DMPlexSetConeSize()`, `DMPlexCreate()`, `DMPlexGetSupport()`, `DMPlexSetChart()`, `DMPlexSetSupportSize()`, `DMSetUp()` 3269 @*/ 3270 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3271 { 3272 DM_Plex *mesh = (DM_Plex*) dm->data; 3273 PetscInt pStart, pEnd; 3274 PetscInt dof, off, c; 3275 3276 PetscFunctionBegin; 3277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3278 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3279 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3280 if (dof) PetscValidIntPointer(support, 3); 3281 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3282 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); 3283 for (c = 0; c < dof; ++c) { 3284 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); 3285 mesh->supports[off+c] = support[c]; 3286 } 3287 PetscFunctionReturn(0); 3288 } 3289 3290 /*@ 3291 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3292 3293 Not collective 3294 3295 Input Parameters: 3296 + mesh - The DMPlex 3297 . p - The point, which must lie in the chart set with DMPlexSetChart() 3298 . supportPos - The local index in the cone where the point should be put 3299 - supportPoint - The mesh point to insert 3300 3301 Level: beginner 3302 3303 .seealso: `DMPlexCreate()`, `DMPlexGetCone()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMSetUp()` 3304 @*/ 3305 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3306 { 3307 DM_Plex *mesh = (DM_Plex*) dm->data; 3308 PetscInt pStart, pEnd; 3309 PetscInt dof, off; 3310 3311 PetscFunctionBegin; 3312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3313 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3314 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3315 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3316 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); 3317 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); 3318 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); 3319 mesh->supports[off+supportPos] = supportPoint; 3320 PetscFunctionReturn(0); 3321 } 3322 3323 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3324 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3325 { 3326 switch (ct) { 3327 case DM_POLYTOPE_SEGMENT: 3328 if (o == -1) return -2; 3329 break; 3330 case DM_POLYTOPE_TRIANGLE: 3331 if (o == -3) return -1; 3332 if (o == -2) return -3; 3333 if (o == -1) return -2; 3334 break; 3335 case DM_POLYTOPE_QUADRILATERAL: 3336 if (o == -4) return -2; 3337 if (o == -3) return -1; 3338 if (o == -2) return -4; 3339 if (o == -1) return -3; 3340 break; 3341 default: return o; 3342 } 3343 return o; 3344 } 3345 3346 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3347 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3348 { 3349 switch (ct) { 3350 case DM_POLYTOPE_SEGMENT: 3351 if ((o == -2) || (o == 1)) return -1; 3352 if (o == -1) return 0; 3353 break; 3354 case DM_POLYTOPE_TRIANGLE: 3355 if (o == -3) return -2; 3356 if (o == -2) return -1; 3357 if (o == -1) return -3; 3358 break; 3359 case DM_POLYTOPE_QUADRILATERAL: 3360 if (o == -4) return -2; 3361 if (o == -3) return -1; 3362 if (o == -2) return -4; 3363 if (o == -1) return -3; 3364 break; 3365 default: return o; 3366 } 3367 return o; 3368 } 3369 3370 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3371 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3372 { 3373 PetscInt pStart, pEnd, p; 3374 3375 PetscFunctionBegin; 3376 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3377 for (p = pStart; p < pEnd; ++p) { 3378 const PetscInt *cone, *ornt; 3379 PetscInt coneSize, c; 3380 3381 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3382 PetscCall(DMPlexGetCone(dm, p, &cone)); 3383 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3384 for (c = 0; c < coneSize; ++c) { 3385 DMPolytopeType ct; 3386 const PetscInt o = ornt[c]; 3387 3388 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3389 switch (ct) { 3390 case DM_POLYTOPE_SEGMENT: 3391 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3392 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3393 break; 3394 case DM_POLYTOPE_TRIANGLE: 3395 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3396 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3397 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3398 break; 3399 case DM_POLYTOPE_QUADRILATERAL: 3400 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3401 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3402 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3403 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3404 break; 3405 default: break; 3406 } 3407 } 3408 } 3409 PetscFunctionReturn(0); 3410 } 3411 3412 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3413 { 3414 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3415 PetscInt *closure; 3416 const PetscInt *tmp = NULL, *tmpO = NULL; 3417 PetscInt off = 0, tmpSize, t; 3418 3419 PetscFunctionBeginHot; 3420 if (ornt) { 3421 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3422 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3423 } 3424 if (*points) { 3425 closure = *points; 3426 } else { 3427 PetscInt maxConeSize, maxSupportSize; 3428 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3429 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3430 } 3431 if (useCone) { 3432 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3433 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3434 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3435 } else { 3436 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3437 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3438 } 3439 if (ct == DM_POLYTOPE_UNKNOWN) { 3440 closure[off++] = p; 3441 closure[off++] = 0; 3442 for (t = 0; t < tmpSize; ++t) { 3443 closure[off++] = tmp[t]; 3444 closure[off++] = tmpO ? tmpO[t] : 0; 3445 } 3446 } else { 3447 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3448 3449 /* We assume that cells with a valid type have faces with a valid type */ 3450 closure[off++] = p; 3451 closure[off++] = ornt; 3452 for (t = 0; t < tmpSize; ++t) { 3453 DMPolytopeType ft; 3454 3455 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3456 closure[off++] = tmp[arr[t]]; 3457 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3458 } 3459 } 3460 if (numPoints) *numPoints = tmpSize+1; 3461 if (points) *points = closure; 3462 PetscFunctionReturn(0); 3463 } 3464 3465 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3466 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3467 { 3468 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3469 const PetscInt *cone, *ornt; 3470 PetscInt *pts, *closure = NULL; 3471 DMPolytopeType ft; 3472 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3473 PetscInt dim, coneSize, c, d, clSize, cl; 3474 3475 PetscFunctionBeginHot; 3476 PetscCall(DMGetDimension(dm, &dim)); 3477 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3478 PetscCall(DMPlexGetCone(dm, point, &cone)); 3479 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3480 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3481 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3482 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3483 maxSize = PetscMax(coneSeries, supportSeries); 3484 if (*points) {pts = *points;} 3485 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3486 c = 0; 3487 pts[c++] = point; 3488 pts[c++] = o; 3489 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3490 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3491 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3492 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3493 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3494 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3495 for (d = 2; d < coneSize; ++d) { 3496 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3497 pts[c++] = cone[arr[d*2+0]]; 3498 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3499 } 3500 if (dim >= 3) { 3501 for (d = 2; d < coneSize; ++d) { 3502 const PetscInt fpoint = cone[arr[d*2+0]]; 3503 const PetscInt *fcone, *fornt; 3504 PetscInt fconeSize, fc, i; 3505 3506 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3507 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3508 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3509 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3510 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3511 for (fc = 0; fc < fconeSize; ++fc) { 3512 const PetscInt cp = fcone[farr[fc*2+0]]; 3513 const PetscInt co = farr[fc*2+1]; 3514 3515 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3516 if (i == c) { 3517 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3518 pts[c++] = cp; 3519 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3520 } 3521 } 3522 } 3523 } 3524 *numPoints = c/2; 3525 *points = pts; 3526 PetscFunctionReturn(0); 3527 } 3528 3529 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3530 { 3531 DMPolytopeType ct; 3532 PetscInt *closure, *fifo; 3533 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3534 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3535 PetscInt depth, maxSize; 3536 3537 PetscFunctionBeginHot; 3538 PetscCall(DMPlexGetDepth(dm, &depth)); 3539 if (depth == 1) { 3540 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3541 PetscFunctionReturn(0); 3542 } 3543 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3544 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3545 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3546 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3547 PetscFunctionReturn(0); 3548 } 3549 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3550 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3551 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3552 maxSize = PetscMax(coneSeries, supportSeries); 3553 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3554 if (*points) {closure = *points;} 3555 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3556 closure[closureSize++] = p; 3557 closure[closureSize++] = ornt; 3558 fifo[fifoSize++] = p; 3559 fifo[fifoSize++] = ornt; 3560 fifo[fifoSize++] = ct; 3561 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3562 while (fifoSize - fifoStart) { 3563 const PetscInt q = fifo[fifoStart++]; 3564 const PetscInt o = fifo[fifoStart++]; 3565 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3566 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3567 const PetscInt *tmp, *tmpO; 3568 PetscInt tmpSize, t; 3569 3570 if (PetscDefined(USE_DEBUG)) { 3571 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3572 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); 3573 } 3574 if (useCone) { 3575 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3576 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3577 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3578 } else { 3579 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3580 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3581 tmpO = NULL; 3582 } 3583 for (t = 0; t < tmpSize; ++t) { 3584 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3585 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3586 const PetscInt cp = tmp[ip]; 3587 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3588 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3589 PetscInt c; 3590 3591 /* Check for duplicate */ 3592 for (c = 0; c < closureSize; c += 2) { 3593 if (closure[c] == cp) break; 3594 } 3595 if (c == closureSize) { 3596 closure[closureSize++] = cp; 3597 closure[closureSize++] = co; 3598 fifo[fifoSize++] = cp; 3599 fifo[fifoSize++] = co; 3600 fifo[fifoSize++] = ct; 3601 } 3602 } 3603 } 3604 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3605 if (numPoints) *numPoints = closureSize/2; 3606 if (points) *points = closure; 3607 PetscFunctionReturn(0); 3608 } 3609 3610 /*@C 3611 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3612 3613 Not collective 3614 3615 Input Parameters: 3616 + dm - The DMPlex 3617 . p - The mesh point 3618 - useCone - PETSC_TRUE for the closure, otherwise return the star 3619 3620 Input/Output Parameter: 3621 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3622 if NULL on input, internal storage will be returned, otherwise the provided array is used 3623 3624 Output Parameter: 3625 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3626 3627 Note: 3628 If using internal storage (points is NULL on input), each call overwrites the last output. 3629 3630 Fortran Notes: 3631 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3632 3633 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3634 3635 Level: beginner 3636 3637 .seealso: `DMPlexRestoreTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3638 @*/ 3639 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3640 { 3641 PetscFunctionBeginHot; 3642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3643 if (numPoints) PetscValidIntPointer(numPoints, 4); 3644 if (points) PetscValidPointer(points, 5); 3645 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3646 PetscFunctionReturn(0); 3647 } 3648 3649 /*@C 3650 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3651 3652 Not collective 3653 3654 Input Parameters: 3655 + dm - The DMPlex 3656 . p - The mesh point 3657 . useCone - PETSC_TRUE for the closure, otherwise return the star 3658 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3659 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3660 3661 Note: 3662 If not using internal storage (points is not NULL on input), this call is unnecessary 3663 3664 Fortran Notes: 3665 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3666 3667 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3668 3669 Level: beginner 3670 3671 .seealso: `DMPlexGetTransitiveClosure()`, `DMPlexCreate()`, `DMPlexSetCone()`, `DMPlexSetChart()`, `DMPlexGetCone()` 3672 @*/ 3673 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3674 { 3675 PetscFunctionBeginHot; 3676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3677 if (numPoints) *numPoints = 0; 3678 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3679 PetscFunctionReturn(0); 3680 } 3681 3682 /*@ 3683 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3684 3685 Not collective 3686 3687 Input Parameter: 3688 . mesh - The DMPlex 3689 3690 Output Parameters: 3691 + maxConeSize - The maximum number of in-edges 3692 - maxSupportSize - The maximum number of out-edges 3693 3694 Level: beginner 3695 3696 .seealso: `DMPlexCreate()`, `DMPlexSetConeSize()`, `DMPlexSetChart()` 3697 @*/ 3698 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3699 { 3700 DM_Plex *mesh = (DM_Plex*) dm->data; 3701 3702 PetscFunctionBegin; 3703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3704 if (maxConeSize) { 3705 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3706 } 3707 if (maxSupportSize) { 3708 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3709 } 3710 PetscFunctionReturn(0); 3711 } 3712 3713 PetscErrorCode DMSetUp_Plex(DM dm) 3714 { 3715 DM_Plex *mesh = (DM_Plex*) dm->data; 3716 PetscInt size, maxSupportSize; 3717 3718 PetscFunctionBegin; 3719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3720 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3721 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3722 PetscCall(PetscMalloc1(size, &mesh->cones)); 3723 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3724 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3725 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3726 if (maxSupportSize) { 3727 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3728 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3729 PetscCall(PetscMalloc1(size, &mesh->supports)); 3730 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3731 } 3732 PetscFunctionReturn(0); 3733 } 3734 3735 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3736 { 3737 PetscFunctionBegin; 3738 if (subdm) PetscCall(DMClone(dm, subdm)); 3739 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3740 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3741 if (dm->useNatural && dm->sfMigration) { 3742 PetscSF sfMigrationInv,sfNatural; 3743 PetscSection section, sectionSeq; 3744 3745 (*subdm)->sfMigration = dm->sfMigration; 3746 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3747 PetscCall(DMGetLocalSection((*subdm), §ion)); 3748 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3749 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3750 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3751 3752 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3753 (*subdm)->sfNatural = sfNatural; 3754 PetscCall(PetscSectionDestroy(§ionSeq)); 3755 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3756 } 3757 PetscFunctionReturn(0); 3758 } 3759 3760 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3761 { 3762 PetscInt i = 0; 3763 3764 PetscFunctionBegin; 3765 PetscCall(DMClone(dms[0], superdm)); 3766 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3767 (*superdm)->useNatural = PETSC_FALSE; 3768 for (i = 0; i < len; i++) { 3769 if (dms[i]->useNatural && dms[i]->sfMigration) { 3770 PetscSF sfMigrationInv,sfNatural; 3771 PetscSection section, sectionSeq; 3772 3773 (*superdm)->sfMigration = dms[i]->sfMigration; 3774 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3775 (*superdm)->useNatural = PETSC_TRUE; 3776 PetscCall(DMGetLocalSection((*superdm), §ion)); 3777 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3778 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3779 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3780 3781 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3782 (*superdm)->sfNatural = sfNatural; 3783 PetscCall(PetscSectionDestroy(§ionSeq)); 3784 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3785 break; 3786 } 3787 } 3788 PetscFunctionReturn(0); 3789 } 3790 3791 /*@ 3792 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3793 3794 Not collective 3795 3796 Input Parameter: 3797 . mesh - The DMPlex 3798 3799 Output Parameter: 3800 3801 Note: 3802 This should be called after all calls to DMPlexSetCone() 3803 3804 Level: beginner 3805 3806 .seealso: `DMPlexCreate()`, `DMPlexSetChart()`, `DMPlexSetConeSize()`, `DMPlexSetCone()` 3807 @*/ 3808 PetscErrorCode DMPlexSymmetrize(DM dm) 3809 { 3810 DM_Plex *mesh = (DM_Plex*) dm->data; 3811 PetscInt *offsets; 3812 PetscInt supportSize; 3813 PetscInt pStart, pEnd, p; 3814 3815 PetscFunctionBegin; 3816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3817 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3818 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3819 /* Calculate support sizes */ 3820 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3821 for (p = pStart; p < pEnd; ++p) { 3822 PetscInt dof, off, c; 3823 3824 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3825 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3826 for (c = off; c < off+dof; ++c) { 3827 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3828 } 3829 } 3830 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3831 /* Calculate supports */ 3832 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3833 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3834 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3835 for (p = pStart; p < pEnd; ++p) { 3836 PetscInt dof, off, c; 3837 3838 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3839 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3840 for (c = off; c < off+dof; ++c) { 3841 const PetscInt q = mesh->cones[c]; 3842 PetscInt offS; 3843 3844 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3845 3846 mesh->supports[offS+offsets[q]] = p; 3847 ++offsets[q]; 3848 } 3849 } 3850 PetscCall(PetscFree(offsets)); 3851 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3852 PetscFunctionReturn(0); 3853 } 3854 3855 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3856 { 3857 IS stratumIS; 3858 3859 PetscFunctionBegin; 3860 if (pStart >= pEnd) PetscFunctionReturn(0); 3861 if (PetscDefined(USE_DEBUG)) { 3862 PetscInt qStart, qEnd, numLevels, level; 3863 PetscBool overlap = PETSC_FALSE; 3864 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3865 for (level = 0; level < numLevels; level++) { 3866 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3867 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3868 } 3869 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); 3870 } 3871 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3872 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3873 PetscCall(ISDestroy(&stratumIS)); 3874 PetscFunctionReturn(0); 3875 } 3876 3877 /*@ 3878 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3879 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3880 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3881 the DAG. 3882 3883 Collective on dm 3884 3885 Input Parameter: 3886 . mesh - The DMPlex 3887 3888 Output Parameter: 3889 3890 Notes: 3891 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3892 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3893 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3894 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3895 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3896 3897 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3898 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3899 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 3900 to interpolate only that one (e0), so that 3901 $ cone(c0) = {e0, v2} 3902 $ cone(e0) = {v0, v1} 3903 If DMPlexStratify() is run on this mesh, it will give depths 3904 $ depth 0 = {v0, v1, v2} 3905 $ depth 1 = {e0, c0} 3906 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3907 3908 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3909 3910 Level: beginner 3911 3912 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexComputeCellTypes()` 3913 @*/ 3914 PetscErrorCode DMPlexStratify(DM dm) 3915 { 3916 DM_Plex *mesh = (DM_Plex*) dm->data; 3917 DMLabel label; 3918 PetscInt pStart, pEnd, p; 3919 PetscInt numRoots = 0, numLeaves = 0; 3920 3921 PetscFunctionBegin; 3922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3923 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3924 3925 /* Create depth label */ 3926 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3927 PetscCall(DMCreateLabel(dm, "depth")); 3928 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3929 3930 { 3931 /* Initialize roots and count leaves */ 3932 PetscInt sMin = PETSC_MAX_INT; 3933 PetscInt sMax = PETSC_MIN_INT; 3934 PetscInt coneSize, supportSize; 3935 3936 for (p = pStart; p < pEnd; ++p) { 3937 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3938 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3939 if (!coneSize && supportSize) { 3940 sMin = PetscMin(p, sMin); 3941 sMax = PetscMax(p, sMax); 3942 ++numRoots; 3943 } else if (!supportSize && coneSize) { 3944 ++numLeaves; 3945 } else if (!supportSize && !coneSize) { 3946 /* Isolated points */ 3947 sMin = PetscMin(p, sMin); 3948 sMax = PetscMax(p, sMax); 3949 } 3950 } 3951 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3952 } 3953 3954 if (numRoots + numLeaves == (pEnd - pStart)) { 3955 PetscInt sMin = PETSC_MAX_INT; 3956 PetscInt sMax = PETSC_MIN_INT; 3957 PetscInt coneSize, supportSize; 3958 3959 for (p = pStart; p < pEnd; ++p) { 3960 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3961 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3962 if (!supportSize && coneSize) { 3963 sMin = PetscMin(p, sMin); 3964 sMax = PetscMax(p, sMax); 3965 } 3966 } 3967 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3968 } else { 3969 PetscInt level = 0; 3970 PetscInt qStart, qEnd, q; 3971 3972 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3973 while (qEnd > qStart) { 3974 PetscInt sMin = PETSC_MAX_INT; 3975 PetscInt sMax = PETSC_MIN_INT; 3976 3977 for (q = qStart; q < qEnd; ++q) { 3978 const PetscInt *support; 3979 PetscInt supportSize, s; 3980 3981 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3982 PetscCall(DMPlexGetSupport(dm, q, &support)); 3983 for (s = 0; s < supportSize; ++s) { 3984 sMin = PetscMin(support[s], sMin); 3985 sMax = PetscMax(support[s], sMax); 3986 } 3987 } 3988 PetscCall(DMLabelGetNumValues(label, &level)); 3989 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 3990 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3991 } 3992 } 3993 { /* just in case there is an empty process */ 3994 PetscInt numValues, maxValues = 0, v; 3995 3996 PetscCall(DMLabelGetNumValues(label, &numValues)); 3997 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 3998 for (v = numValues; v < maxValues; v++) { 3999 PetscCall(DMLabelAddStratum(label, v)); 4000 } 4001 } 4002 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 4003 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 4004 PetscFunctionReturn(0); 4005 } 4006 4007 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4008 { 4009 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4010 PetscInt dim, depth, pheight, coneSize; 4011 4012 PetscFunctionBeginHot; 4013 PetscCall(DMGetDimension(dm, &dim)); 4014 PetscCall(DMPlexGetDepth(dm, &depth)); 4015 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4016 pheight = depth - pdepth; 4017 if (depth <= 1) { 4018 switch (pdepth) { 4019 case 0: ct = DM_POLYTOPE_POINT;break; 4020 case 1: 4021 switch (coneSize) { 4022 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4023 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4024 case 4: 4025 switch (dim) { 4026 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4027 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4028 default: break; 4029 } 4030 break; 4031 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4032 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4033 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4034 default: break; 4035 } 4036 } 4037 } else { 4038 if (pdepth == 0) { 4039 ct = DM_POLYTOPE_POINT; 4040 } else if (pheight == 0) { 4041 switch (dim) { 4042 case 1: 4043 switch (coneSize) { 4044 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4045 default: break; 4046 } 4047 break; 4048 case 2: 4049 switch (coneSize) { 4050 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4051 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4052 default: break; 4053 } 4054 break; 4055 case 3: 4056 switch (coneSize) { 4057 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4058 case 5: 4059 { 4060 const PetscInt *cone; 4061 PetscInt faceConeSize; 4062 4063 PetscCall(DMPlexGetCone(dm, p, &cone)); 4064 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4065 switch (faceConeSize) { 4066 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4067 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4068 } 4069 } 4070 break; 4071 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4072 default: break; 4073 } 4074 break; 4075 default: break; 4076 } 4077 } else if (pheight > 0) { 4078 switch (coneSize) { 4079 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4080 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4081 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4082 default: break; 4083 } 4084 } 4085 } 4086 *pt = ct; 4087 PetscFunctionReturn(0); 4088 } 4089 4090 /*@ 4091 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4092 4093 Collective on dm 4094 4095 Input Parameter: 4096 . mesh - The DMPlex 4097 4098 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4099 4100 Level: developer 4101 4102 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4103 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4104 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4105 4106 .seealso: `DMPlexCreate()`, `DMPlexSymmetrize()`, `DMPlexStratify()`, `DMGetLabel()`, `DMCreateLabel()` 4107 @*/ 4108 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4109 { 4110 DM_Plex *mesh; 4111 DMLabel ctLabel; 4112 PetscInt pStart, pEnd, p; 4113 4114 PetscFunctionBegin; 4115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4116 mesh = (DM_Plex *) dm->data; 4117 PetscCall(DMCreateLabel(dm, "celltype")); 4118 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4119 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4120 for (p = pStart; p < pEnd; ++p) { 4121 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4122 PetscInt pdepth; 4123 4124 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4125 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4126 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4127 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4128 } 4129 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4130 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4131 PetscFunctionReturn(0); 4132 } 4133 4134 /*@C 4135 DMPlexGetJoin - Get an array for the join of the set of points 4136 4137 Not Collective 4138 4139 Input Parameters: 4140 + dm - The DMPlex object 4141 . numPoints - The number of input points for the join 4142 - points - The input points 4143 4144 Output Parameters: 4145 + numCoveredPoints - The number of points in the join 4146 - coveredPoints - The points in the join 4147 4148 Level: intermediate 4149 4150 Note: Currently, this is restricted to a single level join 4151 4152 Fortran Notes: 4153 Since it returns an array, this routine is only available in Fortran 90, and you must 4154 include petsc.h90 in your code. 4155 4156 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4157 4158 .seealso: `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4159 @*/ 4160 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4161 { 4162 DM_Plex *mesh = (DM_Plex*) dm->data; 4163 PetscInt *join[2]; 4164 PetscInt joinSize, i = 0; 4165 PetscInt dof, off, p, c, m; 4166 PetscInt maxSupportSize; 4167 4168 PetscFunctionBegin; 4169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4170 PetscValidIntPointer(points, 3); 4171 PetscValidIntPointer(numCoveredPoints, 4); 4172 PetscValidPointer(coveredPoints, 5); 4173 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4174 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4175 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4176 /* Copy in support of first point */ 4177 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4178 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4179 for (joinSize = 0; joinSize < dof; ++joinSize) { 4180 join[i][joinSize] = mesh->supports[off+joinSize]; 4181 } 4182 /* Check each successive support */ 4183 for (p = 1; p < numPoints; ++p) { 4184 PetscInt newJoinSize = 0; 4185 4186 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4187 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4188 for (c = 0; c < dof; ++c) { 4189 const PetscInt point = mesh->supports[off+c]; 4190 4191 for (m = 0; m < joinSize; ++m) { 4192 if (point == join[i][m]) { 4193 join[1-i][newJoinSize++] = point; 4194 break; 4195 } 4196 } 4197 } 4198 joinSize = newJoinSize; 4199 i = 1-i; 4200 } 4201 *numCoveredPoints = joinSize; 4202 *coveredPoints = join[i]; 4203 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4204 PetscFunctionReturn(0); 4205 } 4206 4207 /*@C 4208 DMPlexRestoreJoin - Restore an array for the join of the set of points 4209 4210 Not Collective 4211 4212 Input Parameters: 4213 + dm - The DMPlex object 4214 . numPoints - The number of input points for the join 4215 - points - The input points 4216 4217 Output Parameters: 4218 + numCoveredPoints - The number of points in the join 4219 - coveredPoints - The points in the join 4220 4221 Fortran Notes: 4222 Since it returns an array, this routine is only available in Fortran 90, and you must 4223 include petsc.h90 in your code. 4224 4225 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4226 4227 Level: intermediate 4228 4229 .seealso: `DMPlexGetJoin()`, `DMPlexGetFullJoin()`, `DMPlexGetMeet()` 4230 @*/ 4231 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4232 { 4233 PetscFunctionBegin; 4234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4235 if (points) PetscValidIntPointer(points,3); 4236 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4237 PetscValidPointer(coveredPoints, 5); 4238 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4239 if (numCoveredPoints) *numCoveredPoints = 0; 4240 PetscFunctionReturn(0); 4241 } 4242 4243 /*@C 4244 DMPlexGetFullJoin - Get an array for the join of the set of points 4245 4246 Not Collective 4247 4248 Input Parameters: 4249 + dm - The DMPlex object 4250 . numPoints - The number of input points for the join 4251 - points - The input points 4252 4253 Output Parameters: 4254 + numCoveredPoints - The number of points in the join 4255 - coveredPoints - The points in the join 4256 4257 Fortran Notes: 4258 Since it returns an array, this routine is only available in Fortran 90, and you must 4259 include petsc.h90 in your code. 4260 4261 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4262 4263 Level: intermediate 4264 4265 .seealso: `DMPlexGetJoin()`, `DMPlexRestoreJoin()`, `DMPlexGetMeet()` 4266 @*/ 4267 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4268 { 4269 PetscInt *offsets, **closures; 4270 PetscInt *join[2]; 4271 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4272 PetscInt p, d, c, m, ms; 4273 4274 PetscFunctionBegin; 4275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4276 PetscValidIntPointer(points, 3); 4277 PetscValidIntPointer(numCoveredPoints, 4); 4278 PetscValidPointer(coveredPoints, 5); 4279 4280 PetscCall(DMPlexGetDepth(dm, &depth)); 4281 PetscCall(PetscCalloc1(numPoints, &closures)); 4282 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4283 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4284 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4285 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4286 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4287 4288 for (p = 0; p < numPoints; ++p) { 4289 PetscInt closureSize; 4290 4291 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4292 4293 offsets[p*(depth+2)+0] = 0; 4294 for (d = 0; d < depth+1; ++d) { 4295 PetscInt pStart, pEnd, i; 4296 4297 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4298 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4299 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4300 offsets[p*(depth+2)+d+1] = i; 4301 break; 4302 } 4303 } 4304 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4305 } 4306 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); 4307 } 4308 for (d = 0; d < depth+1; ++d) { 4309 PetscInt dof; 4310 4311 /* Copy in support of first point */ 4312 dof = offsets[d+1] - offsets[d]; 4313 for (joinSize = 0; joinSize < dof; ++joinSize) { 4314 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4315 } 4316 /* Check each successive cone */ 4317 for (p = 1; p < numPoints && joinSize; ++p) { 4318 PetscInt newJoinSize = 0; 4319 4320 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4321 for (c = 0; c < dof; ++c) { 4322 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4323 4324 for (m = 0; m < joinSize; ++m) { 4325 if (point == join[i][m]) { 4326 join[1-i][newJoinSize++] = point; 4327 break; 4328 } 4329 } 4330 } 4331 joinSize = newJoinSize; 4332 i = 1-i; 4333 } 4334 if (joinSize) break; 4335 } 4336 *numCoveredPoints = joinSize; 4337 *coveredPoints = join[i]; 4338 for (p = 0; p < numPoints; ++p) { 4339 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4340 } 4341 PetscCall(PetscFree(closures)); 4342 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4343 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4344 PetscFunctionReturn(0); 4345 } 4346 4347 /*@C 4348 DMPlexGetMeet - Get an array for the meet of the set of points 4349 4350 Not Collective 4351 4352 Input Parameters: 4353 + dm - The DMPlex object 4354 . numPoints - The number of input points for the meet 4355 - points - The input points 4356 4357 Output Parameters: 4358 + numCoveredPoints - The number of points in the meet 4359 - coveredPoints - The points in the meet 4360 4361 Level: intermediate 4362 4363 Note: Currently, this is restricted to a single level meet 4364 4365 Fortran Notes: 4366 Since it returns an array, this routine is only available in Fortran 90, and you must 4367 include petsc.h90 in your code. 4368 4369 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4370 4371 .seealso: `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4372 @*/ 4373 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4374 { 4375 DM_Plex *mesh = (DM_Plex*) dm->data; 4376 PetscInt *meet[2]; 4377 PetscInt meetSize, i = 0; 4378 PetscInt dof, off, p, c, m; 4379 PetscInt maxConeSize; 4380 4381 PetscFunctionBegin; 4382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4383 PetscValidIntPointer(points, 3); 4384 PetscValidIntPointer(numCoveringPoints, 4); 4385 PetscValidPointer(coveringPoints, 5); 4386 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4387 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4388 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4389 /* Copy in cone of first point */ 4390 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4391 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4392 for (meetSize = 0; meetSize < dof; ++meetSize) { 4393 meet[i][meetSize] = mesh->cones[off+meetSize]; 4394 } 4395 /* Check each successive cone */ 4396 for (p = 1; p < numPoints; ++p) { 4397 PetscInt newMeetSize = 0; 4398 4399 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4400 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4401 for (c = 0; c < dof; ++c) { 4402 const PetscInt point = mesh->cones[off+c]; 4403 4404 for (m = 0; m < meetSize; ++m) { 4405 if (point == meet[i][m]) { 4406 meet[1-i][newMeetSize++] = point; 4407 break; 4408 } 4409 } 4410 } 4411 meetSize = newMeetSize; 4412 i = 1-i; 4413 } 4414 *numCoveringPoints = meetSize; 4415 *coveringPoints = meet[i]; 4416 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4417 PetscFunctionReturn(0); 4418 } 4419 4420 /*@C 4421 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4422 4423 Not Collective 4424 4425 Input Parameters: 4426 + dm - The DMPlex object 4427 . numPoints - The number of input points for the meet 4428 - points - The input points 4429 4430 Output Parameters: 4431 + numCoveredPoints - The number of points in the meet 4432 - coveredPoints - The points in the meet 4433 4434 Level: intermediate 4435 4436 Fortran Notes: 4437 Since it returns an array, this routine is only available in Fortran 90, and you must 4438 include petsc.h90 in your code. 4439 4440 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4441 4442 .seealso: `DMPlexGetMeet()`, `DMPlexGetFullMeet()`, `DMPlexGetJoin()` 4443 @*/ 4444 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4445 { 4446 PetscFunctionBegin; 4447 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4448 if (points) PetscValidIntPointer(points,3); 4449 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4450 PetscValidPointer(coveredPoints,5); 4451 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4452 if (numCoveredPoints) *numCoveredPoints = 0; 4453 PetscFunctionReturn(0); 4454 } 4455 4456 /*@C 4457 DMPlexGetFullMeet - Get an array for the meet of the set of points 4458 4459 Not Collective 4460 4461 Input Parameters: 4462 + dm - The DMPlex object 4463 . numPoints - The number of input points for the meet 4464 - points - The input points 4465 4466 Output Parameters: 4467 + numCoveredPoints - The number of points in the meet 4468 - coveredPoints - The points in the meet 4469 4470 Level: intermediate 4471 4472 Fortran Notes: 4473 Since it returns an array, this routine is only available in Fortran 90, and you must 4474 include petsc.h90 in your code. 4475 4476 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4477 4478 .seealso: `DMPlexGetMeet()`, `DMPlexRestoreMeet()`, `DMPlexGetJoin()` 4479 @*/ 4480 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4481 { 4482 PetscInt *offsets, **closures; 4483 PetscInt *meet[2]; 4484 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4485 PetscInt p, h, c, m, mc; 4486 4487 PetscFunctionBegin; 4488 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4489 PetscValidIntPointer(points, 3); 4490 PetscValidIntPointer(numCoveredPoints, 4); 4491 PetscValidPointer(coveredPoints, 5); 4492 4493 PetscCall(DMPlexGetDepth(dm, &height)); 4494 PetscCall(PetscMalloc1(numPoints, &closures)); 4495 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4496 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4497 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4498 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4499 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4500 4501 for (p = 0; p < numPoints; ++p) { 4502 PetscInt closureSize; 4503 4504 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4505 4506 offsets[p*(height+2)+0] = 0; 4507 for (h = 0; h < height+1; ++h) { 4508 PetscInt pStart, pEnd, i; 4509 4510 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4511 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4512 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4513 offsets[p*(height+2)+h+1] = i; 4514 break; 4515 } 4516 } 4517 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4518 } 4519 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); 4520 } 4521 for (h = 0; h < height+1; ++h) { 4522 PetscInt dof; 4523 4524 /* Copy in cone of first point */ 4525 dof = offsets[h+1] - offsets[h]; 4526 for (meetSize = 0; meetSize < dof; ++meetSize) { 4527 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4528 } 4529 /* Check each successive cone */ 4530 for (p = 1; p < numPoints && meetSize; ++p) { 4531 PetscInt newMeetSize = 0; 4532 4533 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4534 for (c = 0; c < dof; ++c) { 4535 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4536 4537 for (m = 0; m < meetSize; ++m) { 4538 if (point == meet[i][m]) { 4539 meet[1-i][newMeetSize++] = point; 4540 break; 4541 } 4542 } 4543 } 4544 meetSize = newMeetSize; 4545 i = 1-i; 4546 } 4547 if (meetSize) break; 4548 } 4549 *numCoveredPoints = meetSize; 4550 *coveredPoints = meet[i]; 4551 for (p = 0; p < numPoints; ++p) { 4552 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4553 } 4554 PetscCall(PetscFree(closures)); 4555 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4556 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4557 PetscFunctionReturn(0); 4558 } 4559 4560 /*@C 4561 DMPlexEqual - Determine if two DMs have the same topology 4562 4563 Not Collective 4564 4565 Input Parameters: 4566 + dmA - A DMPlex object 4567 - dmB - A DMPlex object 4568 4569 Output Parameters: 4570 . equal - PETSC_TRUE if the topologies are identical 4571 4572 Level: intermediate 4573 4574 Notes: 4575 We are not solving graph isomorphism, so we do not permutation. 4576 4577 .seealso: `DMPlexGetCone()` 4578 @*/ 4579 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4580 { 4581 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4582 4583 PetscFunctionBegin; 4584 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4585 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4586 PetscValidBoolPointer(equal, 3); 4587 4588 *equal = PETSC_FALSE; 4589 PetscCall(DMPlexGetDepth(dmA, &depth)); 4590 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4591 if (depth != depthB) PetscFunctionReturn(0); 4592 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4593 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4594 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4595 for (p = pStart; p < pEnd; ++p) { 4596 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4597 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4598 4599 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4600 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4601 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4602 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4603 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4604 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4605 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4606 for (c = 0; c < coneSize; ++c) { 4607 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4608 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4609 } 4610 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4611 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4612 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4613 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4614 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4615 for (s = 0; s < supportSize; ++s) { 4616 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4617 } 4618 } 4619 *equal = PETSC_TRUE; 4620 PetscFunctionReturn(0); 4621 } 4622 4623 /*@C 4624 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4625 4626 Not Collective 4627 4628 Input Parameters: 4629 + dm - The DMPlex 4630 . cellDim - The cell dimension 4631 - numCorners - The number of vertices on a cell 4632 4633 Output Parameters: 4634 . numFaceVertices - The number of vertices on a face 4635 4636 Level: developer 4637 4638 Notes: 4639 Of course this can only work for a restricted set of symmetric shapes 4640 4641 .seealso: `DMPlexGetCone()` 4642 @*/ 4643 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4644 { 4645 MPI_Comm comm; 4646 4647 PetscFunctionBegin; 4648 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4649 PetscValidIntPointer(numFaceVertices,4); 4650 switch (cellDim) { 4651 case 0: 4652 *numFaceVertices = 0; 4653 break; 4654 case 1: 4655 *numFaceVertices = 1; 4656 break; 4657 case 2: 4658 switch (numCorners) { 4659 case 3: /* triangle */ 4660 *numFaceVertices = 2; /* Edge has 2 vertices */ 4661 break; 4662 case 4: /* quadrilateral */ 4663 *numFaceVertices = 2; /* Edge has 2 vertices */ 4664 break; 4665 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4666 *numFaceVertices = 3; /* Edge has 3 vertices */ 4667 break; 4668 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4669 *numFaceVertices = 3; /* Edge has 3 vertices */ 4670 break; 4671 default: 4672 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4673 } 4674 break; 4675 case 3: 4676 switch (numCorners) { 4677 case 4: /* tetradehdron */ 4678 *numFaceVertices = 3; /* Face has 3 vertices */ 4679 break; 4680 case 6: /* tet cohesive cells */ 4681 *numFaceVertices = 4; /* Face has 4 vertices */ 4682 break; 4683 case 8: /* hexahedron */ 4684 *numFaceVertices = 4; /* Face has 4 vertices */ 4685 break; 4686 case 9: /* tet cohesive Lagrange cells */ 4687 *numFaceVertices = 6; /* Face has 6 vertices */ 4688 break; 4689 case 10: /* quadratic tetrahedron */ 4690 *numFaceVertices = 6; /* Face has 6 vertices */ 4691 break; 4692 case 12: /* hex cohesive Lagrange cells */ 4693 *numFaceVertices = 6; /* Face has 6 vertices */ 4694 break; 4695 case 18: /* quadratic tet cohesive Lagrange cells */ 4696 *numFaceVertices = 6; /* Face has 6 vertices */ 4697 break; 4698 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4699 *numFaceVertices = 9; /* Face has 9 vertices */ 4700 break; 4701 default: 4702 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4703 } 4704 break; 4705 default: 4706 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4707 } 4708 PetscFunctionReturn(0); 4709 } 4710 4711 /*@ 4712 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4713 4714 Not Collective 4715 4716 Input Parameter: 4717 . dm - The DMPlex object 4718 4719 Output Parameter: 4720 . depthLabel - The DMLabel recording point depth 4721 4722 Level: developer 4723 4724 .seealso: `DMPlexGetDepth()`, `DMPlexGetHeightStratum()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, 4725 @*/ 4726 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4727 { 4728 PetscFunctionBegin; 4729 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4730 PetscValidPointer(depthLabel, 2); 4731 *depthLabel = dm->depthLabel; 4732 PetscFunctionReturn(0); 4733 } 4734 4735 /*@ 4736 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4737 4738 Not Collective 4739 4740 Input Parameter: 4741 . dm - The DMPlex object 4742 4743 Output Parameter: 4744 . depth - The number of strata (breadth first levels) in the DAG 4745 4746 Level: developer 4747 4748 Notes: 4749 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4750 The point depth is described more in detail in DMPlexGetDepthStratum(). 4751 An empty mesh gives -1. 4752 4753 .seealso: `DMPlexGetDepthLabel()`, `DMPlexGetDepthStratum()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()` 4754 @*/ 4755 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4756 { 4757 DMLabel label; 4758 PetscInt d = 0; 4759 4760 PetscFunctionBegin; 4761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4762 PetscValidIntPointer(depth, 2); 4763 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4764 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4765 *depth = d-1; 4766 PetscFunctionReturn(0); 4767 } 4768 4769 /*@ 4770 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4771 4772 Not Collective 4773 4774 Input Parameters: 4775 + dm - The DMPlex object 4776 - depth - The requested depth 4777 4778 Output Parameters: 4779 + start - The first point at this depth 4780 - end - One beyond the last point at this depth 4781 4782 Notes: 4783 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4784 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4785 higher dimension, e.g., "edges". 4786 4787 Level: developer 4788 4789 .seealso: `DMPlexGetHeightStratum()`, `DMPlexGetDepth()`, `DMPlexGetDepthLabel()`, `DMPlexGetPointDepth()`, `DMPlexSymmetrize()`, `DMPlexInterpolate()` 4790 @*/ 4791 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt depth, PetscInt *start, PetscInt *end) 4792 { 4793 DMLabel label; 4794 PetscInt pStart, pEnd; 4795 4796 PetscFunctionBegin; 4797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4798 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4799 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4800 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4801 if (pStart == pEnd) PetscFunctionReturn(0); 4802 if (depth < 0) { 4803 if (start) *start = pStart; 4804 if (end) *end = pEnd; 4805 PetscFunctionReturn(0); 4806 } 4807 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4808 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4809 PetscCall(DMLabelGetStratumBounds(label, depth, start, end)); 4810 PetscFunctionReturn(0); 4811 } 4812 4813 /*@ 4814 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4815 4816 Not Collective 4817 4818 Input Parameters: 4819 + dm - The DMPlex object 4820 - height - The requested height 4821 4822 Output Parameters: 4823 + start - The first point at this height 4824 - end - One beyond the last point at this height 4825 4826 Notes: 4827 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4828 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4829 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4830 4831 Level: developer 4832 4833 .seealso: `DMPlexGetDepthStratum()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4834 @*/ 4835 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt height, PetscInt *start, PetscInt *end) 4836 { 4837 DMLabel label; 4838 PetscInt depth, pStart, pEnd; 4839 4840 PetscFunctionBegin; 4841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4842 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4843 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4844 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4845 if (pStart == pEnd) PetscFunctionReturn(0); 4846 if (height < 0) { 4847 if (start) *start = pStart; 4848 if (end) *end = pEnd; 4849 PetscFunctionReturn(0); 4850 } 4851 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4852 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4853 PetscCall(DMLabelGetNumValues(label, &depth)); 4854 PetscCall(DMLabelGetStratumBounds(label, depth-1-height, start, end)); 4855 PetscFunctionReturn(0); 4856 } 4857 4858 /*@ 4859 DMPlexGetPointDepth - Get the depth of a given point 4860 4861 Not Collective 4862 4863 Input Parameters: 4864 + dm - The DMPlex object 4865 - point - The point 4866 4867 Output Parameter: 4868 . depth - The depth of the point 4869 4870 Level: intermediate 4871 4872 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointHeight()` 4873 @*/ 4874 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4875 { 4876 PetscFunctionBegin; 4877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4878 PetscValidIntPointer(depth, 3); 4879 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4880 PetscFunctionReturn(0); 4881 } 4882 4883 /*@ 4884 DMPlexGetPointHeight - Get the height of a given point 4885 4886 Not Collective 4887 4888 Input Parameters: 4889 + dm - The DMPlex object 4890 - point - The point 4891 4892 Output Parameter: 4893 . height - The height of the point 4894 4895 Level: intermediate 4896 4897 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexGetPointDepth()` 4898 @*/ 4899 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4900 { 4901 PetscInt n, pDepth; 4902 4903 PetscFunctionBegin; 4904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4905 PetscValidIntPointer(height, 3); 4906 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4907 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4908 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4909 PetscFunctionReturn(0); 4910 } 4911 4912 /*@ 4913 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4914 4915 Not Collective 4916 4917 Input Parameter: 4918 . dm - The DMPlex object 4919 4920 Output Parameter: 4921 . celltypeLabel - The DMLabel recording cell polytope type 4922 4923 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4924 DMCreateLabel(dm, "celltype") beforehand. 4925 4926 Level: developer 4927 4928 .seealso: `DMPlexGetCellType()`, `DMPlexGetDepthLabel()`, `DMCreateLabel()` 4929 @*/ 4930 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4931 { 4932 PetscFunctionBegin; 4933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4934 PetscValidPointer(celltypeLabel, 2); 4935 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4936 *celltypeLabel = dm->celltypeLabel; 4937 PetscFunctionReturn(0); 4938 } 4939 4940 /*@ 4941 DMPlexGetCellType - Get the polytope type of a given cell 4942 4943 Not Collective 4944 4945 Input Parameters: 4946 + dm - The DMPlex object 4947 - cell - The cell 4948 4949 Output Parameter: 4950 . celltype - The polytope type of the cell 4951 4952 Level: intermediate 4953 4954 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()` 4955 @*/ 4956 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4957 { 4958 DMLabel label; 4959 PetscInt ct; 4960 4961 PetscFunctionBegin; 4962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4963 PetscValidPointer(celltype, 3); 4964 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4965 PetscCall(DMLabelGetValue(label, cell, &ct)); 4966 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4967 *celltype = (DMPolytopeType) ct; 4968 PetscFunctionReturn(0); 4969 } 4970 4971 /*@ 4972 DMPlexSetCellType - Set the polytope type of a given cell 4973 4974 Not Collective 4975 4976 Input Parameters: 4977 + dm - The DMPlex object 4978 . cell - The cell 4979 - celltype - The polytope type of the cell 4980 4981 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4982 is executed. This function will override the computed type. However, if automatic classification will not succeed 4983 and a user wants to manually specify all types, the classification must be disabled by calling 4984 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4985 4986 Level: advanced 4987 4988 .seealso: `DMPlexGetCellTypeLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetDepth()`, `DMPlexComputeCellTypes()`, `DMCreateLabel()` 4989 @*/ 4990 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 4991 { 4992 DMLabel label; 4993 4994 PetscFunctionBegin; 4995 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4996 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4997 PetscCall(DMLabelSetValue(label, cell, celltype)); 4998 PetscFunctionReturn(0); 4999 } 5000 5001 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 5002 { 5003 PetscSection section, s; 5004 Mat m; 5005 PetscInt maxHeight; 5006 5007 PetscFunctionBegin; 5008 PetscCall(DMClone(dm, cdm)); 5009 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5010 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5011 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5012 PetscCall(DMSetLocalSection(*cdm, section)); 5013 PetscCall(PetscSectionDestroy(§ion)); 5014 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5015 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5016 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5017 PetscCall(PetscSectionDestroy(&s)); 5018 PetscCall(MatDestroy(&m)); 5019 5020 PetscCall(DMSetNumFields(*cdm, 1)); 5021 PetscCall(DMCreateDS(*cdm)); 5022 PetscFunctionReturn(0); 5023 } 5024 5025 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5026 { 5027 Vec coordsLocal; 5028 DM coordsDM; 5029 5030 PetscFunctionBegin; 5031 *field = NULL; 5032 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5033 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5034 if (coordsLocal && coordsDM) { 5035 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5036 } 5037 PetscFunctionReturn(0); 5038 } 5039 5040 /*@C 5041 DMPlexGetConeSection - Return a section which describes the layout of cone data 5042 5043 Not Collective 5044 5045 Input Parameters: 5046 . dm - The DMPlex object 5047 5048 Output Parameter: 5049 . section - The PetscSection object 5050 5051 Level: developer 5052 5053 .seealso: `DMPlexGetSupportSection()`, `DMPlexGetCones()`, `DMPlexGetConeOrientations()` 5054 @*/ 5055 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5056 { 5057 DM_Plex *mesh = (DM_Plex*) dm->data; 5058 5059 PetscFunctionBegin; 5060 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5061 if (section) *section = mesh->coneSection; 5062 PetscFunctionReturn(0); 5063 } 5064 5065 /*@C 5066 DMPlexGetSupportSection - Return a section which describes the layout of support data 5067 5068 Not Collective 5069 5070 Input Parameters: 5071 . dm - The DMPlex object 5072 5073 Output Parameter: 5074 . section - The PetscSection object 5075 5076 Level: developer 5077 5078 .seealso: `DMPlexGetConeSection()` 5079 @*/ 5080 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5081 { 5082 DM_Plex *mesh = (DM_Plex*) dm->data; 5083 5084 PetscFunctionBegin; 5085 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5086 if (section) *section = mesh->supportSection; 5087 PetscFunctionReturn(0); 5088 } 5089 5090 /*@C 5091 DMPlexGetCones - Return cone data 5092 5093 Not Collective 5094 5095 Input Parameters: 5096 . dm - The DMPlex object 5097 5098 Output Parameter: 5099 . cones - The cone for each point 5100 5101 Level: developer 5102 5103 .seealso: `DMPlexGetConeSection()` 5104 @*/ 5105 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5106 { 5107 DM_Plex *mesh = (DM_Plex*) dm->data; 5108 5109 PetscFunctionBegin; 5110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5111 if (cones) *cones = mesh->cones; 5112 PetscFunctionReturn(0); 5113 } 5114 5115 /*@C 5116 DMPlexGetConeOrientations - Return cone orientation data 5117 5118 Not Collective 5119 5120 Input Parameters: 5121 . dm - The DMPlex object 5122 5123 Output Parameter: 5124 . coneOrientations - The array of cone orientations for all points 5125 5126 Level: developer 5127 5128 Notes: 5129 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5130 5131 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5132 5133 .seealso: `DMPlexGetConeSection()`, `DMPlexGetConeOrientation()` 5134 @*/ 5135 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5136 { 5137 DM_Plex *mesh = (DM_Plex*) dm->data; 5138 5139 PetscFunctionBegin; 5140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5141 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5142 PetscFunctionReturn(0); 5143 } 5144 5145 /******************************** FEM Support **********************************/ 5146 5147 /* 5148 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5149 representing a line in the section. 5150 */ 5151 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5152 { 5153 PetscFunctionBeginHot; 5154 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5155 if (line < 0) { 5156 *k = 0; 5157 *Nc = 0; 5158 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5159 *k = 1; 5160 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5161 /* An order k SEM disc has k-1 dofs on an edge */ 5162 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5163 *k = *k / *Nc + 1; 5164 } 5165 PetscFunctionReturn(0); 5166 } 5167 5168 /*@ 5169 5170 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5171 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5172 section provided (or the section of the DM). 5173 5174 Input Parameters: 5175 + dm - The DM 5176 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5177 - section - The PetscSection to reorder, or NULL for the default section 5178 5179 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5180 degree of the basis. 5181 5182 Example: 5183 A typical interpolated single-quad mesh might order points as 5184 .vb 5185 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5186 5187 v4 -- e6 -- v3 5188 | | 5189 e7 c0 e8 5190 | | 5191 v1 -- e5 -- v2 5192 .ve 5193 5194 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5195 dofs in the order of points, e.g., 5196 .vb 5197 c0 -> [0,1,2,3] 5198 v1 -> [4] 5199 ... 5200 e5 -> [8, 9] 5201 .ve 5202 5203 which corresponds to the dofs 5204 .vb 5205 6 10 11 7 5206 13 2 3 15 5207 12 0 1 14 5208 4 8 9 5 5209 .ve 5210 5211 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5212 .vb 5213 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5214 .ve 5215 5216 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5217 .vb 5218 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5219 .ve 5220 5221 Level: developer 5222 5223 .seealso: `DMGetLocalSection()`, `PetscSectionSetClosurePermutation()`, `DMSetGlobalSection()` 5224 @*/ 5225 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5226 { 5227 DMLabel label; 5228 PetscInt dim, depth = -1, eStart = -1, Nf; 5229 PetscBool vertexchart; 5230 5231 PetscFunctionBegin; 5232 PetscCall(DMGetDimension(dm, &dim)); 5233 if (dim < 1) PetscFunctionReturn(0); 5234 if (point < 0) { 5235 PetscInt sStart,sEnd; 5236 5237 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5238 point = sEnd-sStart ? sStart : point; 5239 } 5240 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5241 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5242 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5243 if (depth == 1) {eStart = point;} 5244 else if (depth == dim) { 5245 const PetscInt *cone; 5246 5247 PetscCall(DMPlexGetCone(dm, point, &cone)); 5248 if (dim == 2) eStart = cone[0]; 5249 else if (dim == 3) { 5250 const PetscInt *cone2; 5251 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5252 eStart = cone2[0]; 5253 } 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); 5254 } 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); 5255 { /* Determine whether the chart covers all points or just vertices. */ 5256 PetscInt pStart,pEnd,cStart,cEnd; 5257 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5258 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5259 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5260 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5261 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5262 } 5263 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5264 for (PetscInt d=1; d<=dim; d++) { 5265 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5266 PetscInt *perm; 5267 5268 for (f = 0; f < Nf; ++f) { 5269 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5270 size += PetscPowInt(k+1, d)*Nc; 5271 } 5272 PetscCall(PetscMalloc1(size, &perm)); 5273 for (f = 0; f < Nf; ++f) { 5274 switch (d) { 5275 case 1: 5276 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5277 /* 5278 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5279 We want [ vtx0; edge of length k-1; vtx1 ] 5280 */ 5281 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5282 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5283 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5284 foffset = offset; 5285 break; 5286 case 2: 5287 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5288 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5289 /* The SEM order is 5290 5291 v_lb, {e_b}, v_rb, 5292 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5293 v_lt, reverse {e_t}, v_rt 5294 */ 5295 { 5296 const PetscInt of = 0; 5297 const PetscInt oeb = of + PetscSqr(k-1); 5298 const PetscInt oer = oeb + (k-1); 5299 const PetscInt oet = oer + (k-1); 5300 const PetscInt oel = oet + (k-1); 5301 const PetscInt ovlb = oel + (k-1); 5302 const PetscInt ovrb = ovlb + 1; 5303 const PetscInt ovrt = ovrb + 1; 5304 const PetscInt ovlt = ovrt + 1; 5305 PetscInt o; 5306 5307 /* bottom */ 5308 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5309 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5310 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5311 /* middle */ 5312 for (i = 0; i < k-1; ++i) { 5313 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5314 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; 5315 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5316 } 5317 /* top */ 5318 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5319 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5320 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5321 foffset = offset; 5322 } 5323 break; 5324 case 3: 5325 /* The original hex closure is 5326 5327 {c, 5328 f_b, f_t, f_f, f_b, f_r, f_l, 5329 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5330 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5331 */ 5332 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5333 /* The SEM order is 5334 Bottom Slice 5335 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5336 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5337 v_blb, {e_bb}, v_brb, 5338 5339 Middle Slice (j) 5340 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5341 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5342 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5343 5344 Top Slice 5345 v_tlf, {e_tf}, v_trf, 5346 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5347 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5348 */ 5349 { 5350 const PetscInt oc = 0; 5351 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5352 const PetscInt oft = ofb + PetscSqr(k-1); 5353 const PetscInt off = oft + PetscSqr(k-1); 5354 const PetscInt ofk = off + PetscSqr(k-1); 5355 const PetscInt ofr = ofk + PetscSqr(k-1); 5356 const PetscInt ofl = ofr + PetscSqr(k-1); 5357 const PetscInt oebl = ofl + PetscSqr(k-1); 5358 const PetscInt oebb = oebl + (k-1); 5359 const PetscInt oebr = oebb + (k-1); 5360 const PetscInt oebf = oebr + (k-1); 5361 const PetscInt oetf = oebf + (k-1); 5362 const PetscInt oetr = oetf + (k-1); 5363 const PetscInt oetb = oetr + (k-1); 5364 const PetscInt oetl = oetb + (k-1); 5365 const PetscInt oerf = oetl + (k-1); 5366 const PetscInt oelf = oerf + (k-1); 5367 const PetscInt oelb = oelf + (k-1); 5368 const PetscInt oerb = oelb + (k-1); 5369 const PetscInt ovblf = oerb + (k-1); 5370 const PetscInt ovblb = ovblf + 1; 5371 const PetscInt ovbrb = ovblb + 1; 5372 const PetscInt ovbrf = ovbrb + 1; 5373 const PetscInt ovtlf = ovbrf + 1; 5374 const PetscInt ovtrf = ovtlf + 1; 5375 const PetscInt ovtrb = ovtrf + 1; 5376 const PetscInt ovtlb = ovtrb + 1; 5377 PetscInt o, n; 5378 5379 /* Bottom Slice */ 5380 /* bottom */ 5381 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5382 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5383 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5384 /* middle */ 5385 for (i = 0; i < k-1; ++i) { 5386 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5387 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;} 5388 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5389 } 5390 /* top */ 5391 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5392 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5393 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5394 5395 /* Middle Slice */ 5396 for (j = 0; j < k-1; ++j) { 5397 /* bottom */ 5398 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5399 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; 5400 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5401 /* middle */ 5402 for (i = 0; i < k-1; ++i) { 5403 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5404 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; 5405 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5406 } 5407 /* top */ 5408 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5409 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; 5410 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5411 } 5412 5413 /* Top Slice */ 5414 /* bottom */ 5415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5416 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5417 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5418 /* middle */ 5419 for (i = 0; i < k-1; ++i) { 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5421 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5422 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5423 } 5424 /* top */ 5425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5426 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5427 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5428 5429 foffset = offset; 5430 } 5431 break; 5432 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5433 } 5434 } 5435 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5436 /* Check permutation */ 5437 { 5438 PetscInt *check; 5439 5440 PetscCall(PetscMalloc1(size, &check)); 5441 for (i = 0; i < size; ++i) { 5442 check[i] = -1; 5443 PetscCheck(perm[i] >= 0 && perm[i] < size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]); 5444 } 5445 for (i = 0; i < size; ++i) check[perm[i]] = i; 5446 for (i = 0; i < size; ++i) PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i); 5447 PetscCall(PetscFree(check)); 5448 } 5449 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5450 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5451 PetscInt *loc_perm; 5452 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5453 for (PetscInt i=0; i<size; i++) { 5454 loc_perm[i] = perm[i]; 5455 loc_perm[size+i] = size + perm[i]; 5456 } 5457 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5458 } 5459 } 5460 PetscFunctionReturn(0); 5461 } 5462 5463 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5464 { 5465 PetscDS prob; 5466 PetscInt depth, Nf, h; 5467 DMLabel label; 5468 5469 PetscFunctionBeginHot; 5470 PetscCall(DMGetDS(dm, &prob)); 5471 Nf = prob->Nf; 5472 label = dm->depthLabel; 5473 *dspace = NULL; 5474 if (field < Nf) { 5475 PetscObject disc = prob->disc[field]; 5476 5477 if (disc->classid == PETSCFE_CLASSID) { 5478 PetscDualSpace dsp; 5479 5480 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5481 PetscCall(DMLabelGetNumValues(label,&depth)); 5482 PetscCall(DMLabelGetValue(label,point,&h)); 5483 h = depth - 1 - h; 5484 if (h) { 5485 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5486 } else { 5487 *dspace = dsp; 5488 } 5489 } 5490 } 5491 PetscFunctionReturn(0); 5492 } 5493 5494 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5495 { 5496 PetscScalar *array, *vArray; 5497 const PetscInt *cone, *coneO; 5498 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5499 5500 PetscFunctionBeginHot; 5501 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5502 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5503 PetscCall(DMPlexGetCone(dm, point, &cone)); 5504 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5505 if (!values || !*values) { 5506 if ((point >= pStart) && (point < pEnd)) { 5507 PetscInt dof; 5508 5509 PetscCall(PetscSectionGetDof(section, point, &dof)); 5510 size += dof; 5511 } 5512 for (p = 0; p < numPoints; ++p) { 5513 const PetscInt cp = cone[p]; 5514 PetscInt dof; 5515 5516 if ((cp < pStart) || (cp >= pEnd)) continue; 5517 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5518 size += dof; 5519 } 5520 if (!values) { 5521 if (csize) *csize = size; 5522 PetscFunctionReturn(0); 5523 } 5524 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5525 } else { 5526 array = *values; 5527 } 5528 size = 0; 5529 PetscCall(VecGetArray(v, &vArray)); 5530 if ((point >= pStart) && (point < pEnd)) { 5531 PetscInt dof, off, d; 5532 PetscScalar *varr; 5533 5534 PetscCall(PetscSectionGetDof(section, point, &dof)); 5535 PetscCall(PetscSectionGetOffset(section, point, &off)); 5536 varr = &vArray[off]; 5537 for (d = 0; d < dof; ++d, ++offset) { 5538 array[offset] = varr[d]; 5539 } 5540 size += dof; 5541 } 5542 for (p = 0; p < numPoints; ++p) { 5543 const PetscInt cp = cone[p]; 5544 PetscInt o = coneO[p]; 5545 PetscInt dof, off, d; 5546 PetscScalar *varr; 5547 5548 if ((cp < pStart) || (cp >= pEnd)) continue; 5549 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5550 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5551 varr = &vArray[off]; 5552 if (o >= 0) { 5553 for (d = 0; d < dof; ++d, ++offset) { 5554 array[offset] = varr[d]; 5555 } 5556 } else { 5557 for (d = dof-1; d >= 0; --d, ++offset) { 5558 array[offset] = varr[d]; 5559 } 5560 } 5561 size += dof; 5562 } 5563 PetscCall(VecRestoreArray(v, &vArray)); 5564 if (!*values) { 5565 if (csize) *csize = size; 5566 *values = array; 5567 } else { 5568 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5569 *csize = size; 5570 } 5571 PetscFunctionReturn(0); 5572 } 5573 5574 /* Compress out points not in the section */ 5575 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5576 { 5577 const PetscInt np = *numPoints; 5578 PetscInt pStart, pEnd, p, q; 5579 5580 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5581 for (p = 0, q = 0; p < np; ++p) { 5582 const PetscInt r = points[p*2]; 5583 if ((r >= pStart) && (r < pEnd)) { 5584 points[q*2] = r; 5585 points[q*2+1] = points[p*2+1]; 5586 ++q; 5587 } 5588 } 5589 *numPoints = q; 5590 return 0; 5591 } 5592 5593 /* Compressed closure does not apply closure permutation */ 5594 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5595 { 5596 const PetscInt *cla = NULL; 5597 PetscInt np, *pts = NULL; 5598 5599 PetscFunctionBeginHot; 5600 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5601 if (*clPoints) { 5602 PetscInt dof, off; 5603 5604 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5605 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5606 PetscCall(ISGetIndices(*clPoints, &cla)); 5607 np = dof/2; 5608 pts = (PetscInt *) &cla[off]; 5609 } else { 5610 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5611 PetscCall(CompressPoints_Private(section, &np, pts)); 5612 } 5613 *numPoints = np; 5614 *points = pts; 5615 *clp = cla; 5616 PetscFunctionReturn(0); 5617 } 5618 5619 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5620 { 5621 PetscFunctionBeginHot; 5622 if (!*clPoints) { 5623 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5624 } else { 5625 PetscCall(ISRestoreIndices(*clPoints, clp)); 5626 } 5627 *numPoints = 0; 5628 *points = NULL; 5629 *clSec = NULL; 5630 *clPoints = NULL; 5631 *clp = NULL; 5632 PetscFunctionReturn(0); 5633 } 5634 5635 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5636 { 5637 PetscInt offset = 0, p; 5638 const PetscInt **perms = NULL; 5639 const PetscScalar **flips = NULL; 5640 5641 PetscFunctionBeginHot; 5642 *size = 0; 5643 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5644 for (p = 0; p < numPoints; p++) { 5645 const PetscInt point = points[2*p]; 5646 const PetscInt *perm = perms ? perms[p] : NULL; 5647 const PetscScalar *flip = flips ? flips[p] : NULL; 5648 PetscInt dof, off, d; 5649 const PetscScalar *varr; 5650 5651 PetscCall(PetscSectionGetDof(section, point, &dof)); 5652 PetscCall(PetscSectionGetOffset(section, point, &off)); 5653 varr = &vArray[off]; 5654 if (clperm) { 5655 if (perm) { 5656 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5657 } else { 5658 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5659 } 5660 if (flip) { 5661 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5662 } 5663 } else { 5664 if (perm) { 5665 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5666 } else { 5667 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5668 } 5669 if (flip) { 5670 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5671 } 5672 } 5673 offset += dof; 5674 } 5675 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5676 *size = offset; 5677 PetscFunctionReturn(0); 5678 } 5679 5680 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[]) 5681 { 5682 PetscInt offset = 0, f; 5683 5684 PetscFunctionBeginHot; 5685 *size = 0; 5686 for (f = 0; f < numFields; ++f) { 5687 PetscInt p; 5688 const PetscInt **perms = NULL; 5689 const PetscScalar **flips = NULL; 5690 5691 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5692 for (p = 0; p < numPoints; p++) { 5693 const PetscInt point = points[2*p]; 5694 PetscInt fdof, foff, b; 5695 const PetscScalar *varr; 5696 const PetscInt *perm = perms ? perms[p] : NULL; 5697 const PetscScalar *flip = flips ? flips[p] : NULL; 5698 5699 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5700 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5701 varr = &vArray[foff]; 5702 if (clperm) { 5703 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5704 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5705 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5706 } else { 5707 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5708 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5709 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5710 } 5711 offset += fdof; 5712 } 5713 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5714 } 5715 *size = offset; 5716 PetscFunctionReturn(0); 5717 } 5718 5719 /*@C 5720 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5721 5722 Not collective 5723 5724 Input Parameters: 5725 + dm - The DM 5726 . section - The section describing the layout in v, or NULL to use the default section 5727 . v - The local vector 5728 - point - The point in the DM 5729 5730 Input/Output Parameters: 5731 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5732 - values - An array to use for the values, or NULL to have it allocated automatically; 5733 if the user provided NULL, it is a borrowed array and should not be freed 5734 5735 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5736 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5737 $ assembly function, and a user may already have allocated storage for this operation. 5738 $ 5739 $ A typical use could be 5740 $ 5741 $ values = NULL; 5742 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5743 $ for (cl = 0; cl < clSize; ++cl) { 5744 $ <Compute on closure> 5745 $ } 5746 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5747 $ 5748 $ or 5749 $ 5750 $ PetscMalloc1(clMaxSize, &values); 5751 $ for (p = pStart; p < pEnd; ++p) { 5752 $ clSize = clMaxSize; 5753 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5754 $ for (cl = 0; cl < clSize; ++cl) { 5755 $ <Compute on closure> 5756 $ } 5757 $ } 5758 $ PetscFree(values); 5759 5760 Fortran Notes: 5761 Since it returns an array, this routine is only available in Fortran 90, and you must 5762 include petsc.h90 in your code. 5763 5764 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5765 5766 Level: intermediate 5767 5768 .seealso `DMPlexVecRestoreClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5769 @*/ 5770 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5771 { 5772 PetscSection clSection; 5773 IS clPoints; 5774 PetscInt *points = NULL; 5775 const PetscInt *clp, *perm; 5776 PetscInt depth, numFields, numPoints, asize; 5777 5778 PetscFunctionBeginHot; 5779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5780 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5781 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5782 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5783 PetscCall(DMPlexGetDepth(dm, &depth)); 5784 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5785 if (depth == 1 && numFields < 2) { 5786 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5787 PetscFunctionReturn(0); 5788 } 5789 /* Get points */ 5790 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5791 /* Get sizes */ 5792 asize = 0; 5793 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5794 PetscInt dof; 5795 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5796 asize += dof; 5797 } 5798 if (values) { 5799 const PetscScalar *vArray; 5800 PetscInt size; 5801 5802 if (*values) { 5803 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); 5804 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5805 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5806 PetscCall(VecGetArrayRead(v, &vArray)); 5807 /* Get values */ 5808 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5809 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5810 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5811 /* Cleanup array */ 5812 PetscCall(VecRestoreArrayRead(v, &vArray)); 5813 } 5814 if (csize) *csize = asize; 5815 /* Cleanup points */ 5816 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5817 PetscFunctionReturn(0); 5818 } 5819 5820 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5821 { 5822 DMLabel depthLabel; 5823 PetscSection clSection; 5824 IS clPoints; 5825 PetscScalar *array; 5826 const PetscScalar *vArray; 5827 PetscInt *points = NULL; 5828 const PetscInt *clp, *perm = NULL; 5829 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5830 5831 PetscFunctionBeginHot; 5832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5833 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5834 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5835 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5836 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5837 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5838 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5839 if (mdepth == 1 && numFields < 2) { 5840 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5841 PetscFunctionReturn(0); 5842 } 5843 /* Get points */ 5844 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5845 for (clsize=0,p=0; p<Np; p++) { 5846 PetscInt dof; 5847 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5848 clsize += dof; 5849 } 5850 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5851 /* Filter points */ 5852 for (p = 0; p < numPoints*2; p += 2) { 5853 PetscInt dep; 5854 5855 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5856 if (dep != depth) continue; 5857 points[Np*2+0] = points[p]; 5858 points[Np*2+1] = points[p+1]; 5859 ++Np; 5860 } 5861 /* Get array */ 5862 if (!values || !*values) { 5863 PetscInt asize = 0, dof; 5864 5865 for (p = 0; p < Np*2; p += 2) { 5866 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5867 asize += dof; 5868 } 5869 if (!values) { 5870 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5871 if (csize) *csize = asize; 5872 PetscFunctionReturn(0); 5873 } 5874 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5875 } else { 5876 array = *values; 5877 } 5878 PetscCall(VecGetArrayRead(v, &vArray)); 5879 /* Get values */ 5880 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5881 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5882 /* Cleanup points */ 5883 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5884 /* Cleanup array */ 5885 PetscCall(VecRestoreArrayRead(v, &vArray)); 5886 if (!*values) { 5887 if (csize) *csize = size; 5888 *values = array; 5889 } else { 5890 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5891 *csize = size; 5892 } 5893 PetscFunctionReturn(0); 5894 } 5895 5896 /*@C 5897 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5898 5899 Not collective 5900 5901 Input Parameters: 5902 + dm - The DM 5903 . section - The section describing the layout in v, or NULL to use the default section 5904 . v - The local vector 5905 . point - The point in the DM 5906 . csize - The number of values in the closure, or NULL 5907 - values - The array of values, which is a borrowed array and should not be freed 5908 5909 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5910 5911 Fortran Notes: 5912 Since it returns an array, this routine is only available in Fortran 90, and you must 5913 include petsc.h90 in your code. 5914 5915 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5916 5917 Level: intermediate 5918 5919 .seealso `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()`, `DMPlexMatSetClosure()` 5920 @*/ 5921 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5922 { 5923 PetscInt size = 0; 5924 5925 PetscFunctionBegin; 5926 /* Should work without recalculating size */ 5927 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5928 *values = NULL; 5929 PetscFunctionReturn(0); 5930 } 5931 5932 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5933 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5934 5935 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[]) 5936 { 5937 PetscInt cdof; /* The number of constraints on this point */ 5938 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5939 PetscScalar *a; 5940 PetscInt off, cind = 0, k; 5941 5942 PetscFunctionBegin; 5943 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5944 PetscCall(PetscSectionGetOffset(section, point, &off)); 5945 a = &array[off]; 5946 if (!cdof || setBC) { 5947 if (clperm) { 5948 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5949 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5950 } else { 5951 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5952 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5953 } 5954 } else { 5955 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5956 if (clperm) { 5957 if (perm) {for (k = 0; k < dof; ++k) { 5958 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5959 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5960 } 5961 } else { 5962 for (k = 0; k < dof; ++k) { 5963 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5964 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5965 } 5966 } 5967 } else { 5968 if (perm) { 5969 for (k = 0; k < dof; ++k) { 5970 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5971 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5972 } 5973 } else { 5974 for (k = 0; k < dof; ++k) { 5975 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5976 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5977 } 5978 } 5979 } 5980 } 5981 PetscFunctionReturn(0); 5982 } 5983 5984 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[]) 5985 { 5986 PetscInt cdof; /* The number of constraints on this point */ 5987 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5988 PetscScalar *a; 5989 PetscInt off, cind = 0, k; 5990 5991 PetscFunctionBegin; 5992 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5993 PetscCall(PetscSectionGetOffset(section, point, &off)); 5994 a = &array[off]; 5995 if (cdof) { 5996 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5997 if (clperm) { 5998 if (perm) { 5999 for (k = 0; k < dof; ++k) { 6000 if ((cind < cdof) && (k == cdofs[cind])) { 6001 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 6002 cind++; 6003 } 6004 } 6005 } else { 6006 for (k = 0; k < dof; ++k) { 6007 if ((cind < cdof) && (k == cdofs[cind])) { 6008 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6009 cind++; 6010 } 6011 } 6012 } 6013 } else { 6014 if (perm) { 6015 for (k = 0; k < dof; ++k) { 6016 if ((cind < cdof) && (k == cdofs[cind])) { 6017 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6018 cind++; 6019 } 6020 } 6021 } else { 6022 for (k = 0; k < dof; ++k) { 6023 if ((cind < cdof) && (k == cdofs[cind])) { 6024 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6025 cind++; 6026 } 6027 } 6028 } 6029 } 6030 } 6031 PetscFunctionReturn(0); 6032 } 6033 6034 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[]) 6035 { 6036 PetscScalar *a; 6037 PetscInt fdof, foff, fcdof, foffset = *offset; 6038 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6039 PetscInt cind = 0, b; 6040 6041 PetscFunctionBegin; 6042 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6043 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6044 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6045 a = &array[foff]; 6046 if (!fcdof || setBC) { 6047 if (clperm) { 6048 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6049 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6050 } else { 6051 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6052 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6053 } 6054 } else { 6055 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6056 if (clperm) { 6057 if (perm) { 6058 for (b = 0; b < fdof; b++) { 6059 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6060 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6061 } 6062 } else { 6063 for (b = 0; b < fdof; b++) { 6064 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6065 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6066 } 6067 } 6068 } else { 6069 if (perm) { 6070 for (b = 0; b < fdof; b++) { 6071 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6072 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6073 } 6074 } else { 6075 for (b = 0; b < fdof; b++) { 6076 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6077 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6078 } 6079 } 6080 } 6081 } 6082 *offset += fdof; 6083 PetscFunctionReturn(0); 6084 } 6085 6086 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[]) 6087 { 6088 PetscScalar *a; 6089 PetscInt fdof, foff, fcdof, foffset = *offset; 6090 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6091 PetscInt Nc, cind = 0, ncind = 0, b; 6092 PetscBool ncSet, fcSet; 6093 6094 PetscFunctionBegin; 6095 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6096 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6097 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6098 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6099 a = &array[foff]; 6100 if (fcdof) { 6101 /* We just override fcdof and fcdofs with Ncc and comps */ 6102 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6103 if (clperm) { 6104 if (perm) { 6105 if (comps) { 6106 for (b = 0; b < fdof; b++) { 6107 ncSet = fcSet = PETSC_FALSE; 6108 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6109 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6110 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6111 } 6112 } else { 6113 for (b = 0; b < fdof; b++) { 6114 if ((cind < fcdof) && (b == fcdofs[cind])) { 6115 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6116 ++cind; 6117 } 6118 } 6119 } 6120 } else { 6121 if (comps) { 6122 for (b = 0; b < fdof; b++) { 6123 ncSet = fcSet = PETSC_FALSE; 6124 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6125 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6126 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6127 } 6128 } else { 6129 for (b = 0; b < fdof; b++) { 6130 if ((cind < fcdof) && (b == fcdofs[cind])) { 6131 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6132 ++cind; 6133 } 6134 } 6135 } 6136 } 6137 } else { 6138 if (perm) { 6139 if (comps) { 6140 for (b = 0; b < fdof; b++) { 6141 ncSet = fcSet = PETSC_FALSE; 6142 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6143 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6144 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6145 } 6146 } else { 6147 for (b = 0; b < fdof; b++) { 6148 if ((cind < fcdof) && (b == fcdofs[cind])) { 6149 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6150 ++cind; 6151 } 6152 } 6153 } 6154 } else { 6155 if (comps) { 6156 for (b = 0; b < fdof; b++) { 6157 ncSet = fcSet = PETSC_FALSE; 6158 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6159 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6160 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6161 } 6162 } else { 6163 for (b = 0; b < fdof; b++) { 6164 if ((cind < fcdof) && (b == fcdofs[cind])) { 6165 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6166 ++cind; 6167 } 6168 } 6169 } 6170 } 6171 } 6172 } 6173 *offset += fdof; 6174 PetscFunctionReturn(0); 6175 } 6176 6177 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6178 { 6179 PetscScalar *array; 6180 const PetscInt *cone, *coneO; 6181 PetscInt pStart, pEnd, p, numPoints, off, dof; 6182 6183 PetscFunctionBeginHot; 6184 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6185 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6186 PetscCall(DMPlexGetCone(dm, point, &cone)); 6187 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6188 PetscCall(VecGetArray(v, &array)); 6189 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6190 const PetscInt cp = !p ? point : cone[p-1]; 6191 const PetscInt o = !p ? 0 : coneO[p-1]; 6192 6193 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6194 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6195 /* ADD_VALUES */ 6196 { 6197 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6198 PetscScalar *a; 6199 PetscInt cdof, coff, cind = 0, k; 6200 6201 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6202 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6203 a = &array[coff]; 6204 if (!cdof) { 6205 if (o >= 0) { 6206 for (k = 0; k < dof; ++k) { 6207 a[k] += values[off+k]; 6208 } 6209 } else { 6210 for (k = 0; k < dof; ++k) { 6211 a[k] += values[off+dof-k-1]; 6212 } 6213 } 6214 } else { 6215 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6216 if (o >= 0) { 6217 for (k = 0; k < dof; ++k) { 6218 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6219 a[k] += values[off+k]; 6220 } 6221 } else { 6222 for (k = 0; k < dof; ++k) { 6223 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6224 a[k] += values[off+dof-k-1]; 6225 } 6226 } 6227 } 6228 } 6229 } 6230 PetscCall(VecRestoreArray(v, &array)); 6231 PetscFunctionReturn(0); 6232 } 6233 6234 /*@C 6235 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6236 6237 Not collective 6238 6239 Input Parameters: 6240 + dm - The DM 6241 . section - The section describing the layout in v, or NULL to use the default section 6242 . v - The local vector 6243 . point - The point in the DM 6244 . values - The array of values 6245 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6246 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6247 6248 Fortran Notes: 6249 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6250 6251 Level: intermediate 6252 6253 .seealso `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()` 6254 @*/ 6255 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6256 { 6257 PetscSection clSection; 6258 IS clPoints; 6259 PetscScalar *array; 6260 PetscInt *points = NULL; 6261 const PetscInt *clp, *clperm = NULL; 6262 PetscInt depth, numFields, numPoints, p, clsize; 6263 6264 PetscFunctionBeginHot; 6265 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6266 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6267 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6268 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6269 PetscCall(DMPlexGetDepth(dm, &depth)); 6270 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6271 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6272 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6273 PetscFunctionReturn(0); 6274 } 6275 /* Get points */ 6276 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6277 for (clsize=0,p=0; p<numPoints; p++) { 6278 PetscInt dof; 6279 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6280 clsize += dof; 6281 } 6282 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6283 /* Get array */ 6284 PetscCall(VecGetArray(v, &array)); 6285 /* Get values */ 6286 if (numFields > 0) { 6287 PetscInt offset = 0, f; 6288 for (f = 0; f < numFields; ++f) { 6289 const PetscInt **perms = NULL; 6290 const PetscScalar **flips = NULL; 6291 6292 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6293 switch (mode) { 6294 case INSERT_VALUES: 6295 for (p = 0; p < numPoints; p++) { 6296 const PetscInt point = points[2*p]; 6297 const PetscInt *perm = perms ? perms[p] : NULL; 6298 const PetscScalar *flip = flips ? flips[p] : NULL; 6299 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6300 } break; 6301 case INSERT_ALL_VALUES: 6302 for (p = 0; p < numPoints; p++) { 6303 const PetscInt point = points[2*p]; 6304 const PetscInt *perm = perms ? perms[p] : NULL; 6305 const PetscScalar *flip = flips ? flips[p] : NULL; 6306 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6307 } break; 6308 case INSERT_BC_VALUES: 6309 for (p = 0; p < numPoints; p++) { 6310 const PetscInt point = points[2*p]; 6311 const PetscInt *perm = perms ? perms[p] : NULL; 6312 const PetscScalar *flip = flips ? flips[p] : NULL; 6313 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6314 } break; 6315 case ADD_VALUES: 6316 for (p = 0; p < numPoints; p++) { 6317 const PetscInt point = points[2*p]; 6318 const PetscInt *perm = perms ? perms[p] : NULL; 6319 const PetscScalar *flip = flips ? flips[p] : NULL; 6320 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6321 } break; 6322 case ADD_ALL_VALUES: 6323 for (p = 0; p < numPoints; p++) { 6324 const PetscInt point = points[2*p]; 6325 const PetscInt *perm = perms ? perms[p] : NULL; 6326 const PetscScalar *flip = flips ? flips[p] : NULL; 6327 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6328 } break; 6329 case ADD_BC_VALUES: 6330 for (p = 0; p < numPoints; p++) { 6331 const PetscInt point = points[2*p]; 6332 const PetscInt *perm = perms ? perms[p] : NULL; 6333 const PetscScalar *flip = flips ? flips[p] : NULL; 6334 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6335 } break; 6336 default: 6337 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6338 } 6339 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6340 } 6341 } else { 6342 PetscInt dof, off; 6343 const PetscInt **perms = NULL; 6344 const PetscScalar **flips = NULL; 6345 6346 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6347 switch (mode) { 6348 case INSERT_VALUES: 6349 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6350 const PetscInt point = points[2*p]; 6351 const PetscInt *perm = perms ? perms[p] : NULL; 6352 const PetscScalar *flip = flips ? flips[p] : NULL; 6353 PetscCall(PetscSectionGetDof(section, point, &dof)); 6354 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6355 } break; 6356 case INSERT_ALL_VALUES: 6357 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6358 const PetscInt point = points[2*p]; 6359 const PetscInt *perm = perms ? perms[p] : NULL; 6360 const PetscScalar *flip = flips ? flips[p] : NULL; 6361 PetscCall(PetscSectionGetDof(section, point, &dof)); 6362 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6363 } break; 6364 case INSERT_BC_VALUES: 6365 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6366 const PetscInt point = points[2*p]; 6367 const PetscInt *perm = perms ? perms[p] : NULL; 6368 const PetscScalar *flip = flips ? flips[p] : NULL; 6369 PetscCall(PetscSectionGetDof(section, point, &dof)); 6370 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6371 } break; 6372 case ADD_VALUES: 6373 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6374 const PetscInt point = points[2*p]; 6375 const PetscInt *perm = perms ? perms[p] : NULL; 6376 const PetscScalar *flip = flips ? flips[p] : NULL; 6377 PetscCall(PetscSectionGetDof(section, point, &dof)); 6378 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6379 } break; 6380 case ADD_ALL_VALUES: 6381 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6382 const PetscInt point = points[2*p]; 6383 const PetscInt *perm = perms ? perms[p] : NULL; 6384 const PetscScalar *flip = flips ? flips[p] : NULL; 6385 PetscCall(PetscSectionGetDof(section, point, &dof)); 6386 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6387 } break; 6388 case ADD_BC_VALUES: 6389 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6390 const PetscInt point = points[2*p]; 6391 const PetscInt *perm = perms ? perms[p] : NULL; 6392 const PetscScalar *flip = flips ? flips[p] : NULL; 6393 PetscCall(PetscSectionGetDof(section, point, &dof)); 6394 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6395 } break; 6396 default: 6397 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6398 } 6399 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6400 } 6401 /* Cleanup points */ 6402 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6403 /* Cleanup array */ 6404 PetscCall(VecRestoreArray(v, &array)); 6405 PetscFunctionReturn(0); 6406 } 6407 6408 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6409 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6410 { 6411 PetscFunctionBegin; 6412 if (label) { 6413 PetscInt val, fdof; 6414 6415 /* There is a problem with this: 6416 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6417 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6418 Thus I am only going to check val != -1, not val != labelId 6419 */ 6420 PetscCall(DMLabelGetValue(label, point, &val)); 6421 if (val < 0) { 6422 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6423 *offset += fdof; 6424 PetscFunctionReturn(1); 6425 } 6426 } 6427 PetscFunctionReturn(0); 6428 } 6429 6430 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6431 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) 6432 { 6433 PetscSection clSection; 6434 IS clPoints; 6435 PetscScalar *array; 6436 PetscInt *points = NULL; 6437 const PetscInt *clp; 6438 PetscInt numFields, numPoints, p; 6439 PetscInt offset = 0, f; 6440 6441 PetscFunctionBeginHot; 6442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6443 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6444 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6445 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6446 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6447 /* Get points */ 6448 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6449 /* Get array */ 6450 PetscCall(VecGetArray(v, &array)); 6451 /* Get values */ 6452 for (f = 0; f < numFields; ++f) { 6453 const PetscInt **perms = NULL; 6454 const PetscScalar **flips = NULL; 6455 6456 if (!fieldActive[f]) { 6457 for (p = 0; p < numPoints*2; p += 2) { 6458 PetscInt fdof; 6459 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6460 offset += fdof; 6461 } 6462 continue; 6463 } 6464 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6465 switch (mode) { 6466 case INSERT_VALUES: 6467 for (p = 0; p < numPoints; p++) { 6468 const PetscInt point = points[2*p]; 6469 const PetscInt *perm = perms ? perms[p] : NULL; 6470 const PetscScalar *flip = flips ? flips[p] : NULL; 6471 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6472 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6473 } break; 6474 case INSERT_ALL_VALUES: 6475 for (p = 0; p < numPoints; p++) { 6476 const PetscInt point = points[2*p]; 6477 const PetscInt *perm = perms ? perms[p] : NULL; 6478 const PetscScalar *flip = flips ? flips[p] : NULL; 6479 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6480 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6481 } break; 6482 case INSERT_BC_VALUES: 6483 for (p = 0; p < numPoints; p++) { 6484 const PetscInt point = points[2*p]; 6485 const PetscInt *perm = perms ? perms[p] : NULL; 6486 const PetscScalar *flip = flips ? flips[p] : NULL; 6487 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6488 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6489 } break; 6490 case ADD_VALUES: 6491 for (p = 0; p < numPoints; p++) { 6492 const PetscInt point = points[2*p]; 6493 const PetscInt *perm = perms ? perms[p] : NULL; 6494 const PetscScalar *flip = flips ? flips[p] : NULL; 6495 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6496 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6497 } break; 6498 case ADD_ALL_VALUES: 6499 for (p = 0; p < numPoints; p++) { 6500 const PetscInt point = points[2*p]; 6501 const PetscInt *perm = perms ? perms[p] : NULL; 6502 const PetscScalar *flip = flips ? flips[p] : NULL; 6503 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6504 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6505 } break; 6506 default: 6507 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6508 } 6509 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6510 } 6511 /* Cleanup points */ 6512 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6513 /* Cleanup array */ 6514 PetscCall(VecRestoreArray(v, &array)); 6515 PetscFunctionReturn(0); 6516 } 6517 6518 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6519 { 6520 PetscMPIInt rank; 6521 PetscInt i, j; 6522 6523 PetscFunctionBegin; 6524 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6525 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6526 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6527 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6528 numCIndices = numCIndices ? numCIndices : numRIndices; 6529 if (!values) PetscFunctionReturn(0); 6530 for (i = 0; i < numRIndices; i++) { 6531 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6532 for (j = 0; j < numCIndices; j++) { 6533 #if defined(PETSC_USE_COMPLEX) 6534 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6535 #else 6536 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6537 #endif 6538 } 6539 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6540 } 6541 PetscFunctionReturn(0); 6542 } 6543 6544 /* 6545 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6546 6547 Input Parameters: 6548 + section - The section for this data layout 6549 . islocal - Is the section (and thus indices being requested) local or global? 6550 . point - The point contributing dofs with these indices 6551 . off - The global offset of this point 6552 . loff - The local offset of each field 6553 . setBC - The flag determining whether to include indices of boundary values 6554 . perm - A permutation of the dofs on this point, or NULL 6555 - indperm - A permutation of the entire indices array, or NULL 6556 6557 Output Parameter: 6558 . indices - Indices for dofs on this point 6559 6560 Level: developer 6561 6562 Note: The indices could be local or global, depending on the value of 'off'. 6563 */ 6564 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6565 { 6566 PetscInt dof; /* The number of unknowns on this point */ 6567 PetscInt cdof; /* The number of constraints on this point */ 6568 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6569 PetscInt cind = 0, k; 6570 6571 PetscFunctionBegin; 6572 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6573 PetscCall(PetscSectionGetDof(section, point, &dof)); 6574 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6575 if (!cdof || setBC) { 6576 for (k = 0; k < dof; ++k) { 6577 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6578 const PetscInt ind = indperm ? indperm[preind] : preind; 6579 6580 indices[ind] = off + k; 6581 } 6582 } else { 6583 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6584 for (k = 0; k < dof; ++k) { 6585 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6586 const PetscInt ind = indperm ? indperm[preind] : preind; 6587 6588 if ((cind < cdof) && (k == cdofs[cind])) { 6589 /* Insert check for returning constrained indices */ 6590 indices[ind] = -(off+k+1); 6591 ++cind; 6592 } else { 6593 indices[ind] = off + k - (islocal ? 0 : cind); 6594 } 6595 } 6596 } 6597 *loff += dof; 6598 PetscFunctionReturn(0); 6599 } 6600 6601 /* 6602 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6603 6604 Input Parameters: 6605 + section - a section (global or local) 6606 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6607 . point - point within section 6608 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6609 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6610 . setBC - identify constrained (boundary condition) points via involution. 6611 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6612 . permsoff - offset 6613 - indperm - index permutation 6614 6615 Output Parameter: 6616 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6617 . indices - array to hold indices (as defined by section) of each dof associated with point 6618 6619 Notes: 6620 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6621 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6622 in the local vector. 6623 6624 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6625 significant). It is invalid to call with a global section and setBC=true. 6626 6627 Developer Note: 6628 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6629 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6630 offset could be obtained from the section instead of passing it explicitly as we do now. 6631 6632 Example: 6633 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6634 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6635 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6636 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. 6637 6638 Level: developer 6639 */ 6640 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[]) 6641 { 6642 PetscInt numFields, foff, f; 6643 6644 PetscFunctionBegin; 6645 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6646 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6647 for (f = 0, foff = 0; f < numFields; ++f) { 6648 PetscInt fdof, cfdof; 6649 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6650 PetscInt cind = 0, b; 6651 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6652 6653 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6654 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6655 if (!cfdof || setBC) { 6656 for (b = 0; b < fdof; ++b) { 6657 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6658 const PetscInt ind = indperm ? indperm[preind] : preind; 6659 6660 indices[ind] = off+foff+b; 6661 } 6662 } else { 6663 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6664 for (b = 0; b < fdof; ++b) { 6665 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6666 const PetscInt ind = indperm ? indperm[preind] : preind; 6667 6668 if ((cind < cfdof) && (b == fcdofs[cind])) { 6669 indices[ind] = -(off+foff+b+1); 6670 ++cind; 6671 } else { 6672 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6673 } 6674 } 6675 } 6676 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6677 foffs[f] += fdof; 6678 } 6679 PetscFunctionReturn(0); 6680 } 6681 6682 /* 6683 This version believes the globalSection offsets for each field, rather than just the point offset 6684 6685 . foffs - The offset into 'indices' for each field, since it is segregated by field 6686 6687 Notes: 6688 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6689 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6690 */ 6691 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6692 { 6693 PetscInt numFields, foff, f; 6694 6695 PetscFunctionBegin; 6696 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6697 for (f = 0; f < numFields; ++f) { 6698 PetscInt fdof, cfdof; 6699 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6700 PetscInt cind = 0, b; 6701 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6702 6703 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6704 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6705 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6706 if (!cfdof) { 6707 for (b = 0; b < fdof; ++b) { 6708 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6709 const PetscInt ind = indperm ? indperm[preind] : preind; 6710 6711 indices[ind] = foff+b; 6712 } 6713 } else { 6714 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6715 for (b = 0; b < fdof; ++b) { 6716 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6717 const PetscInt ind = indperm ? indperm[preind] : preind; 6718 6719 if ((cind < cfdof) && (b == fcdofs[cind])) { 6720 indices[ind] = -(foff+b+1); 6721 ++cind; 6722 } else { 6723 indices[ind] = foff+b-cind; 6724 } 6725 } 6726 } 6727 foffs[f] += fdof; 6728 } 6729 PetscFunctionReturn(0); 6730 } 6731 6732 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) 6733 { 6734 Mat cMat; 6735 PetscSection aSec, cSec; 6736 IS aIS; 6737 PetscInt aStart = -1, aEnd = -1; 6738 const PetscInt *anchors; 6739 PetscInt numFields, f, p, q, newP = 0; 6740 PetscInt newNumPoints = 0, newNumIndices = 0; 6741 PetscInt *newPoints, *indices, *newIndices; 6742 PetscInt maxAnchor, maxDof; 6743 PetscInt newOffsets[32]; 6744 PetscInt *pointMatOffsets[32]; 6745 PetscInt *newPointOffsets[32]; 6746 PetscScalar *pointMat[32]; 6747 PetscScalar *newValues=NULL,*tmpValues; 6748 PetscBool anyConstrained = PETSC_FALSE; 6749 6750 PetscFunctionBegin; 6751 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6752 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6753 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6754 6755 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6756 /* if there are point-to-point constraints */ 6757 if (aSec) { 6758 PetscCall(PetscArrayzero(newOffsets, 32)); 6759 PetscCall(ISGetIndices(aIS,&anchors)); 6760 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6761 /* figure out how many points are going to be in the new element matrix 6762 * (we allow double counting, because it's all just going to be summed 6763 * into the global matrix anyway) */ 6764 for (p = 0; p < 2*numPoints; p+=2) { 6765 PetscInt b = points[p]; 6766 PetscInt bDof = 0, bSecDof; 6767 6768 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6769 if (!bSecDof) { 6770 continue; 6771 } 6772 if (b >= aStart && b < aEnd) { 6773 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6774 } 6775 if (bDof) { 6776 /* this point is constrained */ 6777 /* it is going to be replaced by its anchors */ 6778 PetscInt bOff, q; 6779 6780 anyConstrained = PETSC_TRUE; 6781 newNumPoints += bDof; 6782 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6783 for (q = 0; q < bDof; q++) { 6784 PetscInt a = anchors[bOff + q]; 6785 PetscInt aDof; 6786 6787 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6788 newNumIndices += aDof; 6789 for (f = 0; f < numFields; ++f) { 6790 PetscInt fDof; 6791 6792 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6793 newOffsets[f+1] += fDof; 6794 } 6795 } 6796 } 6797 else { 6798 /* this point is not constrained */ 6799 newNumPoints++; 6800 newNumIndices += bSecDof; 6801 for (f = 0; f < numFields; ++f) { 6802 PetscInt fDof; 6803 6804 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6805 newOffsets[f+1] += fDof; 6806 } 6807 } 6808 } 6809 } 6810 if (!anyConstrained) { 6811 if (outNumPoints) *outNumPoints = 0; 6812 if (outNumIndices) *outNumIndices = 0; 6813 if (outPoints) *outPoints = NULL; 6814 if (outValues) *outValues = NULL; 6815 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6816 PetscFunctionReturn(0); 6817 } 6818 6819 if (outNumPoints) *outNumPoints = newNumPoints; 6820 if (outNumIndices) *outNumIndices = newNumIndices; 6821 6822 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6823 6824 if (!outPoints && !outValues) { 6825 if (offsets) { 6826 for (f = 0; f <= numFields; f++) { 6827 offsets[f] = newOffsets[f]; 6828 } 6829 } 6830 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6831 PetscFunctionReturn(0); 6832 } 6833 6834 PetscCheck(!numFields || newOffsets[numFields] == newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6835 6836 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6837 6838 /* workspaces */ 6839 if (numFields) { 6840 for (f = 0; f < numFields; f++) { 6841 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6842 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6843 } 6844 } 6845 else { 6846 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6847 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6848 } 6849 6850 /* get workspaces for the point-to-point matrices */ 6851 if (numFields) { 6852 PetscInt totalOffset, totalMatOffset; 6853 6854 for (p = 0; p < numPoints; p++) { 6855 PetscInt b = points[2*p]; 6856 PetscInt bDof = 0, bSecDof; 6857 6858 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6859 if (!bSecDof) { 6860 for (f = 0; f < numFields; f++) { 6861 newPointOffsets[f][p + 1] = 0; 6862 pointMatOffsets[f][p + 1] = 0; 6863 } 6864 continue; 6865 } 6866 if (b >= aStart && b < aEnd) { 6867 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6868 } 6869 if (bDof) { 6870 for (f = 0; f < numFields; f++) { 6871 PetscInt fDof, q, bOff, allFDof = 0; 6872 6873 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6874 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6875 for (q = 0; q < bDof; q++) { 6876 PetscInt a = anchors[bOff + q]; 6877 PetscInt aFDof; 6878 6879 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6880 allFDof += aFDof; 6881 } 6882 newPointOffsets[f][p+1] = allFDof; 6883 pointMatOffsets[f][p+1] = fDof * allFDof; 6884 } 6885 } 6886 else { 6887 for (f = 0; f < numFields; f++) { 6888 PetscInt fDof; 6889 6890 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6891 newPointOffsets[f][p+1] = fDof; 6892 pointMatOffsets[f][p+1] = 0; 6893 } 6894 } 6895 } 6896 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6897 newPointOffsets[f][0] = totalOffset; 6898 pointMatOffsets[f][0] = totalMatOffset; 6899 for (p = 0; p < numPoints; p++) { 6900 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6901 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6902 } 6903 totalOffset = newPointOffsets[f][numPoints]; 6904 totalMatOffset = pointMatOffsets[f][numPoints]; 6905 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6906 } 6907 } 6908 else { 6909 for (p = 0; p < numPoints; p++) { 6910 PetscInt b = points[2*p]; 6911 PetscInt bDof = 0, bSecDof; 6912 6913 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6914 if (!bSecDof) { 6915 newPointOffsets[0][p + 1] = 0; 6916 pointMatOffsets[0][p + 1] = 0; 6917 continue; 6918 } 6919 if (b >= aStart && b < aEnd) { 6920 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6921 } 6922 if (bDof) { 6923 PetscInt bOff, q, allDof = 0; 6924 6925 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6926 for (q = 0; q < bDof; q++) { 6927 PetscInt a = anchors[bOff + q], aDof; 6928 6929 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6930 allDof += aDof; 6931 } 6932 newPointOffsets[0][p+1] = allDof; 6933 pointMatOffsets[0][p+1] = bSecDof * allDof; 6934 } 6935 else { 6936 newPointOffsets[0][p+1] = bSecDof; 6937 pointMatOffsets[0][p+1] = 0; 6938 } 6939 } 6940 newPointOffsets[0][0] = 0; 6941 pointMatOffsets[0][0] = 0; 6942 for (p = 0; p < numPoints; p++) { 6943 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6944 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6945 } 6946 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6947 } 6948 6949 /* output arrays */ 6950 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6951 6952 /* get the point-to-point matrices; construct newPoints */ 6953 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6954 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6955 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6956 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6957 if (numFields) { 6958 for (p = 0, newP = 0; p < numPoints; p++) { 6959 PetscInt b = points[2*p]; 6960 PetscInt o = points[2*p+1]; 6961 PetscInt bDof = 0, bSecDof; 6962 6963 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6964 if (!bSecDof) { 6965 continue; 6966 } 6967 if (b >= aStart && b < aEnd) { 6968 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6969 } 6970 if (bDof) { 6971 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6972 6973 fStart[0] = 0; 6974 fEnd[0] = 0; 6975 for (f = 0; f < numFields; f++) { 6976 PetscInt fDof; 6977 6978 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6979 fStart[f+1] = fStart[f] + fDof; 6980 fEnd[f+1] = fStart[f+1]; 6981 } 6982 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6983 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6984 6985 fAnchorStart[0] = 0; 6986 fAnchorEnd[0] = 0; 6987 for (f = 0; f < numFields; f++) { 6988 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6989 6990 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 6991 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 6992 } 6993 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6994 for (q = 0; q < bDof; q++) { 6995 PetscInt a = anchors[bOff + q], aOff; 6996 6997 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6998 newPoints[2*(newP + q)] = a; 6999 newPoints[2*(newP + q) + 1] = 0; 7000 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7001 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 7002 } 7003 newP += bDof; 7004 7005 if (outValues) { 7006 /* get the point-to-point submatrix */ 7007 for (f = 0; f < numFields; f++) { 7008 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7009 } 7010 } 7011 } 7012 else { 7013 newPoints[2 * newP] = b; 7014 newPoints[2 * newP + 1] = o; 7015 newP++; 7016 } 7017 } 7018 } else { 7019 for (p = 0; p < numPoints; p++) { 7020 PetscInt b = points[2*p]; 7021 PetscInt o = points[2*p+1]; 7022 PetscInt bDof = 0, bSecDof; 7023 7024 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7025 if (!bSecDof) { 7026 continue; 7027 } 7028 if (b >= aStart && b < aEnd) { 7029 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7030 } 7031 if (bDof) { 7032 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7033 7034 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7035 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7036 7037 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7038 for (q = 0; q < bDof; q++) { 7039 PetscInt a = anchors[bOff + q], aOff; 7040 7041 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7042 7043 newPoints[2*(newP + q)] = a; 7044 newPoints[2*(newP + q) + 1] = 0; 7045 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7046 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7047 } 7048 newP += bDof; 7049 7050 /* get the point-to-point submatrix */ 7051 if (outValues) { 7052 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7053 } 7054 } 7055 else { 7056 newPoints[2 * newP] = b; 7057 newPoints[2 * newP + 1] = o; 7058 newP++; 7059 } 7060 } 7061 } 7062 7063 if (outValues) { 7064 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7065 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7066 /* multiply constraints on the right */ 7067 if (numFields) { 7068 for (f = 0; f < numFields; f++) { 7069 PetscInt oldOff = offsets[f]; 7070 7071 for (p = 0; p < numPoints; p++) { 7072 PetscInt cStart = newPointOffsets[f][p]; 7073 PetscInt b = points[2 * p]; 7074 PetscInt c, r, k; 7075 PetscInt dof; 7076 7077 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7078 if (!dof) { 7079 continue; 7080 } 7081 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7082 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7083 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7084 7085 for (r = 0; r < numIndices; r++) { 7086 for (c = 0; c < nCols; c++) { 7087 for (k = 0; k < dof; k++) { 7088 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7089 } 7090 } 7091 } 7092 } 7093 else { 7094 /* copy this column as is */ 7095 for (r = 0; r < numIndices; r++) { 7096 for (c = 0; c < dof; c++) { 7097 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7098 } 7099 } 7100 } 7101 oldOff += dof; 7102 } 7103 } 7104 } 7105 else { 7106 PetscInt oldOff = 0; 7107 for (p = 0; p < numPoints; p++) { 7108 PetscInt cStart = newPointOffsets[0][p]; 7109 PetscInt b = points[2 * p]; 7110 PetscInt c, r, k; 7111 PetscInt dof; 7112 7113 PetscCall(PetscSectionGetDof(section,b,&dof)); 7114 if (!dof) { 7115 continue; 7116 } 7117 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7118 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7119 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7120 7121 for (r = 0; r < numIndices; r++) { 7122 for (c = 0; c < nCols; c++) { 7123 for (k = 0; k < dof; k++) { 7124 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7125 } 7126 } 7127 } 7128 } 7129 else { 7130 /* copy this column as is */ 7131 for (r = 0; r < numIndices; r++) { 7132 for (c = 0; c < dof; c++) { 7133 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7134 } 7135 } 7136 } 7137 oldOff += dof; 7138 } 7139 } 7140 7141 if (multiplyLeft) { 7142 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7143 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7144 /* multiply constraints transpose on the left */ 7145 if (numFields) { 7146 for (f = 0; f < numFields; f++) { 7147 PetscInt oldOff = offsets[f]; 7148 7149 for (p = 0; p < numPoints; p++) { 7150 PetscInt rStart = newPointOffsets[f][p]; 7151 PetscInt b = points[2 * p]; 7152 PetscInt c, r, k; 7153 PetscInt dof; 7154 7155 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7156 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7157 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7158 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7159 7160 for (r = 0; r < nRows; r++) { 7161 for (c = 0; c < newNumIndices; c++) { 7162 for (k = 0; k < dof; k++) { 7163 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7164 } 7165 } 7166 } 7167 } 7168 else { 7169 /* copy this row as is */ 7170 for (r = 0; r < dof; r++) { 7171 for (c = 0; c < newNumIndices; c++) { 7172 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7173 } 7174 } 7175 } 7176 oldOff += dof; 7177 } 7178 } 7179 } 7180 else { 7181 PetscInt oldOff = 0; 7182 7183 for (p = 0; p < numPoints; p++) { 7184 PetscInt rStart = newPointOffsets[0][p]; 7185 PetscInt b = points[2 * p]; 7186 PetscInt c, r, k; 7187 PetscInt dof; 7188 7189 PetscCall(PetscSectionGetDof(section,b,&dof)); 7190 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7191 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7192 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7193 7194 for (r = 0; r < nRows; r++) { 7195 for (c = 0; c < newNumIndices; c++) { 7196 for (k = 0; k < dof; k++) { 7197 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7198 } 7199 } 7200 } 7201 } 7202 else { 7203 /* copy this row as is */ 7204 for (r = 0; r < dof; r++) { 7205 for (c = 0; c < newNumIndices; c++) { 7206 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7207 } 7208 } 7209 } 7210 oldOff += dof; 7211 } 7212 } 7213 7214 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7215 } 7216 else { 7217 newValues = tmpValues; 7218 } 7219 } 7220 7221 /* clean up */ 7222 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7223 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7224 7225 if (numFields) { 7226 for (f = 0; f < numFields; f++) { 7227 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7228 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7229 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7230 } 7231 } 7232 else { 7233 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7234 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7235 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7236 } 7237 PetscCall(ISRestoreIndices(aIS,&anchors)); 7238 7239 /* output */ 7240 if (outPoints) { 7241 *outPoints = newPoints; 7242 } 7243 else { 7244 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7245 } 7246 if (outValues) { 7247 *outValues = newValues; 7248 } 7249 for (f = 0; f <= numFields; f++) { 7250 offsets[f] = newOffsets[f]; 7251 } 7252 PetscFunctionReturn(0); 7253 } 7254 7255 /*@C 7256 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7257 7258 Not collective 7259 7260 Input Parameters: 7261 + dm - The DM 7262 . section - The PetscSection describing the points (a local section) 7263 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7264 . point - The point defining the closure 7265 - useClPerm - Use the closure point permutation if available 7266 7267 Output Parameters: 7268 + numIndices - The number of dof indices in the closure of point with the input sections 7269 . indices - The dof indices 7270 . outOffsets - Array to write the field offsets into, or NULL 7271 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7272 7273 Notes: 7274 Must call DMPlexRestoreClosureIndices() to free allocated memory 7275 7276 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7277 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7278 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7279 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7280 indices (with the above semantics) are implied. 7281 7282 Level: advanced 7283 7284 .seealso `DMPlexRestoreClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7285 @*/ 7286 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7287 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7288 { 7289 /* Closure ordering */ 7290 PetscSection clSection; 7291 IS clPoints; 7292 const PetscInt *clp; 7293 PetscInt *points; 7294 const PetscInt *clperm = NULL; 7295 /* Dof permutation and sign flips */ 7296 const PetscInt **perms[32] = {NULL}; 7297 const PetscScalar **flips[32] = {NULL}; 7298 PetscScalar *valCopy = NULL; 7299 /* Hanging node constraints */ 7300 PetscInt *pointsC = NULL; 7301 PetscScalar *valuesC = NULL; 7302 PetscInt NclC, NiC; 7303 7304 PetscInt *idx; 7305 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7306 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7307 7308 PetscFunctionBeginHot; 7309 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7310 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7311 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7312 if (numIndices) PetscValidIntPointer(numIndices, 6); 7313 if (indices) PetscValidPointer(indices, 7); 7314 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7315 if (values) PetscValidPointer(values, 9); 7316 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7317 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7318 PetscCall(PetscArrayzero(offsets, 32)); 7319 /* 1) Get points in closure */ 7320 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7321 if (useClPerm) { 7322 PetscInt depth, clsize; 7323 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7324 for (clsize=0,p=0; p<Ncl; p++) { 7325 PetscInt dof; 7326 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7327 clsize += dof; 7328 } 7329 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7330 } 7331 /* 2) Get number of indices on these points and field offsets from section */ 7332 for (p = 0; p < Ncl*2; p += 2) { 7333 PetscInt dof, fdof; 7334 7335 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7336 for (f = 0; f < Nf; ++f) { 7337 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7338 offsets[f+1] += fdof; 7339 } 7340 Ni += dof; 7341 } 7342 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7343 PetscCheck(!Nf || offsets[Nf] == Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7344 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7345 for (f = 0; f < PetscMax(1, Nf); ++f) { 7346 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7347 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7348 /* may need to apply sign changes to the element matrix */ 7349 if (values && flips[f]) { 7350 PetscInt foffset = offsets[f]; 7351 7352 for (p = 0; p < Ncl; ++p) { 7353 PetscInt pnt = points[2*p], fdof; 7354 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7355 7356 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7357 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7358 if (flip) { 7359 PetscInt i, j, k; 7360 7361 if (!valCopy) { 7362 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7363 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7364 *values = valCopy; 7365 } 7366 for (i = 0; i < fdof; ++i) { 7367 PetscScalar fval = flip[i]; 7368 7369 for (k = 0; k < Ni; ++k) { 7370 valCopy[Ni * (foffset + i) + k] *= fval; 7371 valCopy[Ni * k + (foffset + i)] *= fval; 7372 } 7373 } 7374 } 7375 foffset += fdof; 7376 } 7377 } 7378 } 7379 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7380 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7381 if (NclC) { 7382 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7383 for (f = 0; f < PetscMax(1, Nf); ++f) { 7384 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7385 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7386 } 7387 for (f = 0; f < PetscMax(1, Nf); ++f) { 7388 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7389 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7390 } 7391 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7392 Ncl = NclC; 7393 Ni = NiC; 7394 points = pointsC; 7395 if (values) *values = valuesC; 7396 } 7397 /* 5) Calculate indices */ 7398 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7399 if (Nf) { 7400 PetscInt idxOff; 7401 PetscBool useFieldOffsets; 7402 7403 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7404 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7405 if (useFieldOffsets) { 7406 for (p = 0; p < Ncl; ++p) { 7407 const PetscInt pnt = points[p*2]; 7408 7409 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7410 } 7411 } else { 7412 for (p = 0; p < Ncl; ++p) { 7413 const PetscInt pnt = points[p*2]; 7414 7415 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7416 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7417 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7418 * global section. */ 7419 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7420 } 7421 } 7422 } else { 7423 PetscInt off = 0, idxOff; 7424 7425 for (p = 0; p < Ncl; ++p) { 7426 const PetscInt pnt = points[p*2]; 7427 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7428 7429 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7430 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7431 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7432 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7433 } 7434 } 7435 /* 6) Cleanup */ 7436 for (f = 0; f < PetscMax(1, Nf); ++f) { 7437 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7438 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7439 } 7440 if (NclC) { 7441 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7442 } else { 7443 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7444 } 7445 7446 if (numIndices) *numIndices = Ni; 7447 if (indices) *indices = idx; 7448 PetscFunctionReturn(0); 7449 } 7450 7451 /*@C 7452 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7453 7454 Not collective 7455 7456 Input Parameters: 7457 + dm - The DM 7458 . section - The PetscSection describing the points (a local section) 7459 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7460 . point - The point defining the closure 7461 - useClPerm - Use the closure point permutation if available 7462 7463 Output Parameters: 7464 + numIndices - The number of dof indices in the closure of point with the input sections 7465 . indices - The dof indices 7466 . outOffsets - Array to write the field offsets into, or NULL 7467 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7468 7469 Notes: 7470 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7471 7472 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7473 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7474 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7475 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7476 indices (with the above semantics) are implied. 7477 7478 Level: advanced 7479 7480 .seealso `DMPlexGetClosureIndices()`, `DMPlexVecGetClosure()`, `DMPlexMatSetClosure()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 7481 @*/ 7482 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7483 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7484 { 7485 PetscFunctionBegin; 7486 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7487 PetscValidPointer(indices, 7); 7488 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7489 PetscFunctionReturn(0); 7490 } 7491 7492 /*@C 7493 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7494 7495 Not collective 7496 7497 Input Parameters: 7498 + dm - The DM 7499 . section - The section describing the layout in v, or NULL to use the default section 7500 . globalSection - The section describing the layout in v, or NULL to use the default global section 7501 . A - The matrix 7502 . point - The point in the DM 7503 . values - The array of values 7504 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7505 7506 Fortran Notes: 7507 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7508 7509 Level: intermediate 7510 7511 .seealso `DMPlexMatSetClosureGeneral()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7512 @*/ 7513 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7514 { 7515 DM_Plex *mesh = (DM_Plex*) dm->data; 7516 PetscInt *indices; 7517 PetscInt numIndices; 7518 const PetscScalar *valuesOrig = values; 7519 PetscErrorCode ierr; 7520 7521 PetscFunctionBegin; 7522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7523 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7524 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7525 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7526 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7527 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7528 7529 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7530 7531 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7532 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7533 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7534 if (ierr) { 7535 PetscMPIInt rank; 7536 7537 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7538 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7539 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7540 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7541 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7542 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7543 } 7544 if (mesh->printFEM > 1) { 7545 PetscInt i; 7546 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7547 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7548 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7549 } 7550 7551 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7552 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7553 PetscFunctionReturn(0); 7554 } 7555 7556 /*@C 7557 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7558 7559 Not collective 7560 7561 Input Parameters: 7562 + dmRow - The DM for the row fields 7563 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7564 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7565 . dmCol - The DM for the column fields 7566 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7567 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7568 . A - The matrix 7569 . point - The point in the DMs 7570 . values - The array of values 7571 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7572 7573 Level: intermediate 7574 7575 .seealso `DMPlexMatSetClosure()`, `DMPlexVecGetClosure()`, `DMPlexVecSetClosure()` 7576 @*/ 7577 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7578 { 7579 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7580 PetscInt *indicesRow, *indicesCol; 7581 PetscInt numIndicesRow, numIndicesCol; 7582 const PetscScalar *valuesOrig = values; 7583 PetscErrorCode ierr; 7584 7585 PetscFunctionBegin; 7586 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7587 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7588 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7589 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7590 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7591 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7592 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7593 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7594 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7595 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7596 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7597 7598 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7599 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7600 7601 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7602 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7603 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7604 if (ierr) { 7605 PetscMPIInt rank; 7606 7607 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7608 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7609 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7610 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7611 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7612 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7613 } 7614 7615 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7616 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7617 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7618 PetscFunctionReturn(0); 7619 } 7620 7621 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7622 { 7623 DM_Plex *mesh = (DM_Plex*) dmf->data; 7624 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7625 PetscInt *cpoints = NULL; 7626 PetscInt *findices, *cindices; 7627 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7628 PetscInt foffsets[32], coffsets[32]; 7629 DMPolytopeType ct; 7630 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7631 PetscErrorCode ierr; 7632 7633 PetscFunctionBegin; 7634 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7635 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7636 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7637 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7638 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7639 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7640 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7641 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7642 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7643 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7644 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7645 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7646 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7647 PetscCall(PetscArrayzero(foffsets, 32)); 7648 PetscCall(PetscArrayzero(coffsets, 32)); 7649 /* Column indices */ 7650 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7651 maxFPoints = numCPoints; 7652 /* Compress out points not in the section */ 7653 /* TODO: Squeeze out points with 0 dof as well */ 7654 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7655 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7656 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7657 cpoints[q*2] = cpoints[p]; 7658 cpoints[q*2+1] = cpoints[p+1]; 7659 ++q; 7660 } 7661 } 7662 numCPoints = q; 7663 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7664 PetscInt fdof; 7665 7666 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7667 if (!dof) continue; 7668 for (f = 0; f < numFields; ++f) { 7669 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7670 coffsets[f+1] += fdof; 7671 } 7672 numCIndices += dof; 7673 } 7674 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7675 /* Row indices */ 7676 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7677 { 7678 DMPlexTransform tr; 7679 DMPolytopeType *rct; 7680 PetscInt *rsize, *rcone, *rornt, Nt; 7681 7682 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7683 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7684 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7685 numSubcells = rsize[Nt-1]; 7686 PetscCall(DMPlexTransformDestroy(&tr)); 7687 } 7688 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7689 for (r = 0, q = 0; r < numSubcells; ++r) { 7690 /* TODO Map from coarse to fine cells */ 7691 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7692 /* Compress out points not in the section */ 7693 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7694 for (p = 0; p < numFPoints*2; p += 2) { 7695 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7696 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7697 if (!dof) continue; 7698 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7699 if (s < q) continue; 7700 ftotpoints[q*2] = fpoints[p]; 7701 ftotpoints[q*2+1] = fpoints[p+1]; 7702 ++q; 7703 } 7704 } 7705 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7706 } 7707 numFPoints = q; 7708 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7709 PetscInt fdof; 7710 7711 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7712 if (!dof) continue; 7713 for (f = 0; f < numFields; ++f) { 7714 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7715 foffsets[f+1] += fdof; 7716 } 7717 numFIndices += dof; 7718 } 7719 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7720 7721 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7722 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7723 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7724 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7725 if (numFields) { 7726 const PetscInt **permsF[32] = {NULL}; 7727 const PetscInt **permsC[32] = {NULL}; 7728 7729 for (f = 0; f < numFields; f++) { 7730 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7731 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7732 } 7733 for (p = 0; p < numFPoints; p++) { 7734 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7735 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7736 } 7737 for (p = 0; p < numCPoints; p++) { 7738 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7739 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7740 } 7741 for (f = 0; f < numFields; f++) { 7742 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7743 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7744 } 7745 } else { 7746 const PetscInt **permsF = NULL; 7747 const PetscInt **permsC = NULL; 7748 7749 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7750 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7751 for (p = 0, off = 0; p < numFPoints; p++) { 7752 const PetscInt *perm = permsF ? permsF[p] : NULL; 7753 7754 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7755 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7756 } 7757 for (p = 0, off = 0; p < numCPoints; p++) { 7758 const PetscInt *perm = permsC ? permsC[p] : NULL; 7759 7760 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7761 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7762 } 7763 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7764 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7765 } 7766 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7767 /* TODO: flips */ 7768 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7769 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7770 if (ierr) { 7771 PetscMPIInt rank; 7772 7773 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7774 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7775 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7776 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7777 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7778 } 7779 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7780 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7781 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7782 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7783 PetscFunctionReturn(0); 7784 } 7785 7786 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7787 { 7788 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7789 PetscInt *cpoints = NULL; 7790 PetscInt foffsets[32], coffsets[32]; 7791 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7792 DMPolytopeType ct; 7793 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7794 7795 PetscFunctionBegin; 7796 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7797 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7798 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7799 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7800 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7801 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7802 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7803 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7804 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7805 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7806 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7807 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7808 PetscCall(PetscArrayzero(foffsets, 32)); 7809 PetscCall(PetscArrayzero(coffsets, 32)); 7810 /* Column indices */ 7811 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7812 maxFPoints = numCPoints; 7813 /* Compress out points not in the section */ 7814 /* TODO: Squeeze out points with 0 dof as well */ 7815 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7816 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7817 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7818 cpoints[q*2] = cpoints[p]; 7819 cpoints[q*2+1] = cpoints[p+1]; 7820 ++q; 7821 } 7822 } 7823 numCPoints = q; 7824 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7825 PetscInt fdof; 7826 7827 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7828 if (!dof) continue; 7829 for (f = 0; f < numFields; ++f) { 7830 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7831 coffsets[f+1] += fdof; 7832 } 7833 numCIndices += dof; 7834 } 7835 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7836 /* Row indices */ 7837 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7838 { 7839 DMPlexTransform tr; 7840 DMPolytopeType *rct; 7841 PetscInt *rsize, *rcone, *rornt, Nt; 7842 7843 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7844 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7845 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7846 numSubcells = rsize[Nt-1]; 7847 PetscCall(DMPlexTransformDestroy(&tr)); 7848 } 7849 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7850 for (r = 0, q = 0; r < numSubcells; ++r) { 7851 /* TODO Map from coarse to fine cells */ 7852 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7853 /* Compress out points not in the section */ 7854 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7855 for (p = 0; p < numFPoints*2; p += 2) { 7856 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7857 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7858 if (!dof) continue; 7859 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7860 if (s < q) continue; 7861 ftotpoints[q*2] = fpoints[p]; 7862 ftotpoints[q*2+1] = fpoints[p+1]; 7863 ++q; 7864 } 7865 } 7866 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7867 } 7868 numFPoints = q; 7869 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7870 PetscInt fdof; 7871 7872 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7873 if (!dof) continue; 7874 for (f = 0; f < numFields; ++f) { 7875 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7876 foffsets[f+1] += fdof; 7877 } 7878 numFIndices += dof; 7879 } 7880 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7881 7882 PetscCheck(!numFields || foffsets[numFields] == numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7883 PetscCheck(!numFields || coffsets[numFields] == numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7884 if (numFields) { 7885 const PetscInt **permsF[32] = {NULL}; 7886 const PetscInt **permsC[32] = {NULL}; 7887 7888 for (f = 0; f < numFields; f++) { 7889 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7890 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7891 } 7892 for (p = 0; p < numFPoints; p++) { 7893 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7894 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7895 } 7896 for (p = 0; p < numCPoints; p++) { 7897 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7898 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7899 } 7900 for (f = 0; f < numFields; f++) { 7901 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7902 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7903 } 7904 } else { 7905 const PetscInt **permsF = NULL; 7906 const PetscInt **permsC = NULL; 7907 7908 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7909 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7910 for (p = 0, off = 0; p < numFPoints; p++) { 7911 const PetscInt *perm = permsF ? permsF[p] : NULL; 7912 7913 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7914 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7915 } 7916 for (p = 0, off = 0; p < numCPoints; p++) { 7917 const PetscInt *perm = permsC ? permsC[p] : NULL; 7918 7919 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7920 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7921 } 7922 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7923 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7924 } 7925 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7926 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7927 PetscFunctionReturn(0); 7928 } 7929 7930 /*@C 7931 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7932 7933 Input Parameter: 7934 . dm - The DMPlex object 7935 7936 Output Parameter: 7937 . cellHeight - The height of a cell 7938 7939 Level: developer 7940 7941 .seealso `DMPlexSetVTKCellHeight()` 7942 @*/ 7943 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7944 { 7945 DM_Plex *mesh = (DM_Plex*) dm->data; 7946 7947 PetscFunctionBegin; 7948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7949 PetscValidIntPointer(cellHeight, 2); 7950 *cellHeight = mesh->vtkCellHeight; 7951 PetscFunctionReturn(0); 7952 } 7953 7954 /*@C 7955 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7956 7957 Input Parameters: 7958 + dm - The DMPlex object 7959 - cellHeight - The height of a cell 7960 7961 Level: developer 7962 7963 .seealso `DMPlexGetVTKCellHeight()` 7964 @*/ 7965 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7966 { 7967 DM_Plex *mesh = (DM_Plex*) dm->data; 7968 7969 PetscFunctionBegin; 7970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7971 mesh->vtkCellHeight = cellHeight; 7972 PetscFunctionReturn(0); 7973 } 7974 7975 /*@ 7976 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7977 7978 Input Parameter: 7979 . dm - The DMPlex object 7980 7981 Output Parameters: 7982 + gcStart - The first ghost cell, or NULL 7983 - gcEnd - The upper bound on ghost cells, or NULL 7984 7985 Level: advanced 7986 7987 .seealso `DMPlexConstructGhostCells()`, `DMPlexGetGhostCellStratum()` 7988 @*/ 7989 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7990 { 7991 DMLabel ctLabel; 7992 7993 PetscFunctionBegin; 7994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7995 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7996 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7997 PetscFunctionReturn(0); 7998 } 7999 8000 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 8001 { 8002 PetscSection section, globalSection; 8003 PetscInt *numbers, p; 8004 8005 PetscFunctionBegin; 8006 if (PetscDefined(USE_DEBUG)) PetscCall(DMPlexCheckPointSF(dm, sf)); 8007 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 8008 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8009 for (p = pStart; p < pEnd; ++p) { 8010 PetscCall(PetscSectionSetDof(section, p, 1)); 8011 } 8012 PetscCall(PetscSectionSetUp(section)); 8013 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8014 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8015 for (p = pStart; p < pEnd; ++p) { 8016 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8017 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8018 else numbers[p-pStart] += shift; 8019 } 8020 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8021 if (globalSize) { 8022 PetscLayout layout; 8023 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8024 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8025 PetscCall(PetscLayoutDestroy(&layout)); 8026 } 8027 PetscCall(PetscSectionDestroy(§ion)); 8028 PetscCall(PetscSectionDestroy(&globalSection)); 8029 PetscFunctionReturn(0); 8030 } 8031 8032 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8033 { 8034 PetscInt cellHeight, cStart, cEnd; 8035 8036 PetscFunctionBegin; 8037 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8038 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8039 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8040 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8041 PetscFunctionReturn(0); 8042 } 8043 8044 /*@ 8045 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8046 8047 Input Parameter: 8048 . dm - The DMPlex object 8049 8050 Output Parameter: 8051 . globalCellNumbers - Global cell numbers for all cells on this process 8052 8053 Level: developer 8054 8055 .seealso `DMPlexGetVertexNumbering()` 8056 @*/ 8057 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8058 { 8059 DM_Plex *mesh = (DM_Plex*) dm->data; 8060 8061 PetscFunctionBegin; 8062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8063 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8064 *globalCellNumbers = mesh->globalCellNumbers; 8065 PetscFunctionReturn(0); 8066 } 8067 8068 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8069 { 8070 PetscInt vStart, vEnd; 8071 8072 PetscFunctionBegin; 8073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8074 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8075 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8076 PetscFunctionReturn(0); 8077 } 8078 8079 /*@ 8080 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8081 8082 Input Parameter: 8083 . dm - The DMPlex object 8084 8085 Output Parameter: 8086 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8087 8088 Level: developer 8089 8090 .seealso `DMPlexGetCellNumbering()` 8091 @*/ 8092 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8093 { 8094 DM_Plex *mesh = (DM_Plex*) dm->data; 8095 8096 PetscFunctionBegin; 8097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8098 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8099 *globalVertexNumbers = mesh->globalVertexNumbers; 8100 PetscFunctionReturn(0); 8101 } 8102 8103 /*@ 8104 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8105 8106 Input Parameter: 8107 . dm - The DMPlex object 8108 8109 Output Parameter: 8110 . globalPointNumbers - Global numbers for all points on this process 8111 8112 Level: developer 8113 8114 .seealso `DMPlexGetCellNumbering()` 8115 @*/ 8116 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8117 { 8118 IS nums[4]; 8119 PetscInt depths[4], gdepths[4], starts[4]; 8120 PetscInt depth, d, shift = 0; 8121 8122 PetscFunctionBegin; 8123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8124 PetscCall(DMPlexGetDepth(dm, &depth)); 8125 /* For unstratified meshes use dim instead of depth */ 8126 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8127 for (d = 0; d <= depth; ++d) { 8128 PetscInt end; 8129 8130 depths[d] = depth-d; 8131 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8132 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8133 } 8134 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8135 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8136 for (d = 0; d <= depth; ++d) { 8137 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]); 8138 } 8139 for (d = 0; d <= depth; ++d) { 8140 PetscInt pStart, pEnd, gsize; 8141 8142 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8143 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8144 shift += gsize; 8145 } 8146 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8147 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8148 PetscFunctionReturn(0); 8149 } 8150 8151 /*@ 8152 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8153 8154 Input Parameter: 8155 . dm - The DMPlex object 8156 8157 Output Parameter: 8158 . ranks - The rank field 8159 8160 Options Database Keys: 8161 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8162 8163 Level: intermediate 8164 8165 .seealso: `DMView()` 8166 @*/ 8167 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8168 { 8169 DM rdm; 8170 PetscFE fe; 8171 PetscScalar *r; 8172 PetscMPIInt rank; 8173 DMPolytopeType ct; 8174 PetscInt dim, cStart, cEnd, c; 8175 PetscBool simplex; 8176 8177 PetscFunctionBeginUser; 8178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8179 PetscValidPointer(ranks, 2); 8180 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8181 PetscCall(DMClone(dm, &rdm)); 8182 PetscCall(DMGetDimension(rdm, &dim)); 8183 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8184 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8185 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8186 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8187 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8188 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8189 PetscCall(PetscFEDestroy(&fe)); 8190 PetscCall(DMCreateDS(rdm)); 8191 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8192 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8193 PetscCall(VecGetArray(*ranks, &r)); 8194 for (c = cStart; c < cEnd; ++c) { 8195 PetscScalar *lr; 8196 8197 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8198 if (lr) *lr = rank; 8199 } 8200 PetscCall(VecRestoreArray(*ranks, &r)); 8201 PetscCall(DMDestroy(&rdm)); 8202 PetscFunctionReturn(0); 8203 } 8204 8205 /*@ 8206 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8207 8208 Input Parameters: 8209 + dm - The DMPlex 8210 - label - The DMLabel 8211 8212 Output Parameter: 8213 . val - The label value field 8214 8215 Options Database Keys: 8216 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8217 8218 Level: intermediate 8219 8220 .seealso: `DMView()` 8221 @*/ 8222 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8223 { 8224 DM rdm; 8225 PetscFE fe; 8226 PetscScalar *v; 8227 PetscInt dim, cStart, cEnd, c; 8228 8229 PetscFunctionBeginUser; 8230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8231 PetscValidPointer(label, 2); 8232 PetscValidPointer(val, 3); 8233 PetscCall(DMClone(dm, &rdm)); 8234 PetscCall(DMGetDimension(rdm, &dim)); 8235 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8236 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8237 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8238 PetscCall(PetscFEDestroy(&fe)); 8239 PetscCall(DMCreateDS(rdm)); 8240 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8241 PetscCall(DMCreateGlobalVector(rdm, val)); 8242 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8243 PetscCall(VecGetArray(*val, &v)); 8244 for (c = cStart; c < cEnd; ++c) { 8245 PetscScalar *lv; 8246 PetscInt cval; 8247 8248 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8249 PetscCall(DMLabelGetValue(label, c, &cval)); 8250 *lv = cval; 8251 } 8252 PetscCall(VecRestoreArray(*val, &v)); 8253 PetscCall(DMDestroy(&rdm)); 8254 PetscFunctionReturn(0); 8255 } 8256 8257 /*@ 8258 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8259 8260 Input Parameter: 8261 . dm - The DMPlex object 8262 8263 Notes: 8264 This is a useful diagnostic when creating meshes programmatically. 8265 8266 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8267 8268 Level: developer 8269 8270 .seealso: `DMCreate()`, `DMSetFromOptions()` 8271 @*/ 8272 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8273 { 8274 PetscSection coneSection, supportSection; 8275 const PetscInt *cone, *support; 8276 PetscInt coneSize, c, supportSize, s; 8277 PetscInt pStart, pEnd, p, pp, csize, ssize; 8278 PetscBool storagecheck = PETSC_TRUE; 8279 8280 PetscFunctionBegin; 8281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8282 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8283 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8284 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8285 /* Check that point p is found in the support of its cone points, and vice versa */ 8286 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8287 for (p = pStart; p < pEnd; ++p) { 8288 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8289 PetscCall(DMPlexGetCone(dm, p, &cone)); 8290 for (c = 0; c < coneSize; ++c) { 8291 PetscBool dup = PETSC_FALSE; 8292 PetscInt d; 8293 for (d = c-1; d >= 0; --d) { 8294 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8295 } 8296 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8297 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8298 for (s = 0; s < supportSize; ++s) { 8299 if (support[s] == p) break; 8300 } 8301 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8303 for (s = 0; s < coneSize; ++s) { 8304 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8305 } 8306 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8307 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8308 for (s = 0; s < supportSize; ++s) { 8309 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8310 } 8311 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8312 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]); 8313 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8314 } 8315 } 8316 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8317 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8318 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8319 PetscCall(DMPlexGetSupport(dm, p, &support)); 8320 for (s = 0; s < supportSize; ++s) { 8321 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8322 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8323 for (c = 0; c < coneSize; ++c) { 8324 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8325 if (cone[c] != pp) { c = 0; break; } 8326 if (cone[c] == p) break; 8327 } 8328 if (c >= coneSize) { 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8330 for (c = 0; c < supportSize; ++c) { 8331 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8332 } 8333 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8334 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8335 for (c = 0; c < coneSize; ++c) { 8336 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8337 } 8338 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8339 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8340 } 8341 } 8342 } 8343 if (storagecheck) { 8344 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8345 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8346 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8347 } 8348 PetscFunctionReturn(0); 8349 } 8350 8351 /* 8352 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. 8353 */ 8354 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8355 { 8356 DMPolytopeType cct; 8357 PetscInt ptpoints[4]; 8358 const PetscInt *cone, *ccone, *ptcone; 8359 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8360 8361 PetscFunctionBegin; 8362 *unsplit = 0; 8363 switch (ct) { 8364 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8365 ptpoints[npt++] = c; 8366 break; 8367 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8368 PetscCall(DMPlexGetCone(dm, c, &cone)); 8369 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8370 for (cp = 0; cp < coneSize; ++cp) { 8371 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8372 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8373 } 8374 break; 8375 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8376 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8377 PetscCall(DMPlexGetCone(dm, c, &cone)); 8378 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8379 for (cp = 0; cp < coneSize; ++cp) { 8380 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8381 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8382 for (ccp = 0; ccp < cconeSize; ++ccp) { 8383 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8384 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8385 PetscInt p; 8386 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8387 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8388 } 8389 } 8390 } 8391 break; 8392 default: break; 8393 } 8394 for (pt = 0; pt < npt; ++pt) { 8395 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8396 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8397 } 8398 PetscFunctionReturn(0); 8399 } 8400 8401 /*@ 8402 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8403 8404 Input Parameters: 8405 + dm - The DMPlex object 8406 - cellHeight - Normally 0 8407 8408 Notes: 8409 This is a useful diagnostic when creating meshes programmatically. 8410 Currently applicable only to homogeneous simplex or tensor meshes. 8411 8412 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8413 8414 Level: developer 8415 8416 .seealso: `DMCreate()`, `DMSetFromOptions()` 8417 @*/ 8418 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8419 { 8420 DMPlexInterpolatedFlag interp; 8421 DMPolytopeType ct; 8422 PetscInt vStart, vEnd, cStart, cEnd, c; 8423 8424 PetscFunctionBegin; 8425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8426 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8427 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8428 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8429 for (c = cStart; c < cEnd; ++c) { 8430 PetscInt *closure = NULL; 8431 PetscInt coneSize, closureSize, cl, Nv = 0; 8432 8433 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8434 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8435 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8436 if (interp == DMPLEX_INTERPOLATED_FULL) { 8437 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8438 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)); 8439 } 8440 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8441 for (cl = 0; cl < closureSize*2; cl += 2) { 8442 const PetscInt p = closure[cl]; 8443 if ((p >= vStart) && (p < vEnd)) ++Nv; 8444 } 8445 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8446 /* Special Case: Tensor faces with identified vertices */ 8447 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8448 PetscInt unsplit; 8449 8450 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8451 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8452 } 8453 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)); 8454 } 8455 PetscFunctionReturn(0); 8456 } 8457 8458 /*@ 8459 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8460 8461 Collective 8462 8463 Input Parameters: 8464 + dm - The DMPlex object 8465 - cellHeight - Normally 0 8466 8467 Notes: 8468 This is a useful diagnostic when creating meshes programmatically. 8469 This routine is only relevant for meshes that are fully interpolated across all ranks. 8470 It will error out if a partially interpolated mesh is given on some rank. 8471 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8472 8473 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8474 8475 Level: developer 8476 8477 .seealso: `DMCreate()`, `DMPlexGetVTKCellHeight()`, `DMSetFromOptions()` 8478 @*/ 8479 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8480 { 8481 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8482 DMPlexInterpolatedFlag interpEnum; 8483 8484 PetscFunctionBegin; 8485 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8486 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpEnum)); 8487 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8488 if (interpEnum != DMPLEX_INTERPOLATED_FULL) { 8489 PetscPrintf(PetscObjectComm((PetscObject)dm), "DMPlexCheckFaces() warning: Mesh is only partially interpolated, this is currently not supported"); 8490 PetscFunctionReturn(0); 8491 } 8492 8493 PetscCall(DMGetDimension(dm, &dim)); 8494 PetscCall(DMPlexGetDepth(dm, &depth)); 8495 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8496 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8497 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8498 for (c = cStart; c < cEnd; ++c) { 8499 const PetscInt *cone, *ornt, *faceSizes, *faces; 8500 const DMPolytopeType *faceTypes; 8501 DMPolytopeType ct; 8502 PetscInt numFaces, coneSize, f; 8503 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8504 8505 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8506 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8507 if (unsplit) continue; 8508 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8509 PetscCall(DMPlexGetCone(dm, c, &cone)); 8510 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8511 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8512 for (cl = 0; cl < closureSize*2; cl += 2) { 8513 const PetscInt p = closure[cl]; 8514 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8515 } 8516 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8517 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); 8518 for (f = 0; f < numFaces; ++f) { 8519 DMPolytopeType fct; 8520 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8521 8522 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8523 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8524 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8525 const PetscInt p = fclosure[cl]; 8526 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8527 } 8528 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]); 8529 for (v = 0; v < fnumCorners; ++v) { 8530 if (fclosure[v] != faces[fOff+v]) { 8531 PetscInt v1; 8532 8533 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8534 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8535 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8536 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8537 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8538 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]); 8539 } 8540 } 8541 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8542 fOff += faceSizes[f]; 8543 } 8544 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8545 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8546 } 8547 } 8548 PetscFunctionReturn(0); 8549 } 8550 8551 /*@ 8552 DMPlexCheckGeometry - Check the geometry of mesh cells 8553 8554 Input Parameter: 8555 . dm - The DMPlex object 8556 8557 Notes: 8558 This is a useful diagnostic when creating meshes programmatically. 8559 8560 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8561 8562 Level: developer 8563 8564 .seealso: `DMCreate()`, `DMSetFromOptions()` 8565 @*/ 8566 PetscErrorCode DMPlexCheckGeometry(DM dm) 8567 { 8568 Vec coordinates; 8569 PetscReal detJ, J[9], refVol = 1.0; 8570 PetscReal vol; 8571 PetscBool periodic; 8572 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8573 8574 PetscFunctionBegin; 8575 PetscCall(DMGetDimension(dm, &dim)); 8576 PetscCall(DMGetCoordinateDim(dm, &dE)); 8577 if (dim != dE) PetscFunctionReturn(0); 8578 PetscCall(DMPlexGetDepth(dm, &depth)); 8579 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8580 for (d = 0; d < dim; ++d) refVol *= 2.0; 8581 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8582 /* Make sure local coordinates are created, because that step is collective */ 8583 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8584 for (c = cStart; c < cEnd; ++c) { 8585 DMPolytopeType ct; 8586 PetscInt unsplit; 8587 PetscBool ignoreZeroVol = PETSC_FALSE; 8588 8589 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8590 switch (ct) { 8591 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8592 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8593 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8594 ignoreZeroVol = PETSC_TRUE; break; 8595 default: break; 8596 } 8597 switch (ct) { 8598 case DM_POLYTOPE_TRI_PRISM: 8599 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8600 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8601 case DM_POLYTOPE_PYRAMID: 8602 continue; 8603 default: break; 8604 } 8605 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8606 if (unsplit) continue; 8607 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8608 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); 8609 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8610 if (depth > 1 && !periodic) { 8611 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8612 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); 8613 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8614 } 8615 } 8616 PetscFunctionReturn(0); 8617 } 8618 8619 /*@ 8620 DMPlexCheckPointSF - Check that several necessary conditions are met for the Point SF of this plex. 8621 8622 Collective 8623 8624 Input Parameters: 8625 + dm - The DMPlex object 8626 - pointSF - The Point SF, or NULL for Point SF attached to DM 8627 8628 Notes: 8629 This is mainly intended for debugging/testing purposes. 8630 8631 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8632 8633 Level: developer 8634 8635 .seealso: `DMGetPointSF()`, `DMSetFromOptions()` 8636 @*/ 8637 PetscErrorCode DMPlexCheckPointSF(DM dm, PetscSF pointSF) 8638 { 8639 PetscInt l, nleaves, nroots, overlap; 8640 const PetscInt *locals; 8641 const PetscSFNode *remotes; 8642 PetscBool distributed; 8643 MPI_Comm comm; 8644 PetscMPIInt rank; 8645 8646 PetscFunctionBegin; 8647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8648 if (pointSF) PetscValidHeaderSpecific(pointSF, PETSCSF_CLASSID, 2); 8649 else pointSF = dm->sf; 8650 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 8651 PetscCheck(pointSF, comm, PETSC_ERR_ARG_WRONGSTATE, "DMPlex must have Point SF attached"); 8652 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8653 { 8654 PetscMPIInt mpiFlag; 8655 8656 PetscCallMPI(MPI_Comm_compare(comm, PetscObjectComm((PetscObject)pointSF),&mpiFlag)); 8657 PetscCheck(mpiFlag == MPI_CONGRUENT || mpiFlag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "DM and Point SF have different communicators (flag %d)",mpiFlag); 8658 } 8659 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, &remotes)); 8660 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8661 if (!distributed) { 8662 PetscCheck(nroots < 0 || nleaves == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Undistributed DMPlex cannot have non-empty PointSF (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8663 PetscFunctionReturn(0); 8664 } 8665 PetscCheck(nroots >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set (has %" PetscInt_FMT " roots, %" PetscInt_FMT " leaves)", nroots, nleaves); 8666 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8667 8668 /* Check SF graph is compatible with DMPlex chart */ 8669 { 8670 PetscInt pStart, pEnd, maxLeaf; 8671 8672 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8673 PetscCall(PetscSFGetLeafRange(pointSF, NULL, &maxLeaf)); 8674 PetscCheck(pEnd - pStart == nroots, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pEnd - pStart = %" PetscInt_FMT " != nroots = %" PetscInt_FMT, pEnd-pStart, nroots); 8675 PetscCheck(maxLeaf < pEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "maxLeaf = %" PetscInt_FMT " >= pEnd = %" PetscInt_FMT, maxLeaf, pEnd); 8676 } 8677 8678 /* Check Point SF has no local points referenced */ 8679 for (l = 0; l < nleaves; l++) { 8680 PetscAssert(remotes[l].rank != (PetscInt) rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains local point %" PetscInt_FMT " <- (%" PetscInt_FMT ",%" PetscInt_FMT ")", locals ? locals[l] : l, remotes[l].rank, remotes[l].index); 8681 } 8682 8683 /* Check there are no cells in interface */ 8684 if (!overlap) { 8685 PetscInt cellHeight, cStart, cEnd; 8686 8687 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8688 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8689 for (l = 0; l < nleaves; ++l) { 8690 const PetscInt point = locals ? locals[l] : l; 8691 8692 PetscCheck(point < cStart || point >= cEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8693 } 8694 } 8695 8696 /* If some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8697 { 8698 const PetscInt *rootdegree; 8699 8700 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8701 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8702 for (l = 0; l < nleaves; ++l) { 8703 const PetscInt point = locals ? locals[l] : l; 8704 const PetscInt *cone; 8705 PetscInt coneSize, c, idx; 8706 8707 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8708 PetscCall(DMPlexGetCone(dm, point, &cone)); 8709 for (c = 0; c < coneSize; ++c) { 8710 if (!rootdegree[cone[c]]) { 8711 if (locals) { 8712 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8713 } else { 8714 idx = (cone[c] < nleaves) ? cone[c] : -1; 8715 } 8716 PetscCheck(idx >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8717 } 8718 } 8719 } 8720 } 8721 PetscFunctionReturn(0); 8722 } 8723 8724 /*@ 8725 DMPlexCheck - Perform various checks of Plex sanity 8726 8727 Input Parameter: 8728 . dm - The DMPlex object 8729 8730 Notes: 8731 This is a useful diagnostic when creating meshes programmatically. 8732 8733 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8734 8735 Currently does not include DMPlexCheckCellShape(). 8736 8737 Level: developer 8738 8739 .seealso: DMCreate(), DMSetFromOptions() 8740 @*/ 8741 PetscErrorCode DMPlexCheck(DM dm) 8742 { 8743 PetscInt cellHeight; 8744 8745 PetscFunctionBegin; 8746 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8747 PetscCall(DMPlexCheckSymmetry(dm)); 8748 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8749 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8750 PetscCall(DMPlexCheckGeometry(dm)); 8751 PetscCall(DMPlexCheckPointSF(dm, NULL)); 8752 PetscCall(DMPlexCheckInterfaceCones(dm)); 8753 PetscFunctionReturn(0); 8754 } 8755 8756 typedef struct cell_stats 8757 { 8758 PetscReal min, max, sum, squaresum; 8759 PetscInt count; 8760 } cell_stats_t; 8761 8762 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8763 { 8764 PetscInt i, N = *len; 8765 8766 for (i = 0; i < N; i++) { 8767 cell_stats_t *A = (cell_stats_t *) a; 8768 cell_stats_t *B = (cell_stats_t *) b; 8769 8770 B->min = PetscMin(A->min,B->min); 8771 B->max = PetscMax(A->max,B->max); 8772 B->sum += A->sum; 8773 B->squaresum += A->squaresum; 8774 B->count += A->count; 8775 } 8776 } 8777 8778 /*@ 8779 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8780 8781 Collective on dm 8782 8783 Input Parameters: 8784 + dm - The DMPlex object 8785 . output - If true, statistics will be displayed on stdout 8786 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8787 8788 Notes: 8789 This is mainly intended for debugging/testing purposes. 8790 8791 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8792 8793 Level: developer 8794 8795 .seealso: `DMSetFromOptions()`, `DMPlexComputeOrthogonalQuality()` 8796 @*/ 8797 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8798 { 8799 DM dmCoarse; 8800 cell_stats_t stats, globalStats; 8801 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8802 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8803 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8804 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8805 PetscMPIInt rank,size; 8806 8807 PetscFunctionBegin; 8808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8809 stats.min = PETSC_MAX_REAL; 8810 stats.max = PETSC_MIN_REAL; 8811 stats.sum = stats.squaresum = 0.; 8812 stats.count = 0; 8813 8814 PetscCallMPI(MPI_Comm_size(comm, &size)); 8815 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8816 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8817 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8818 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8819 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8820 for (c = cStart; c < cEnd; c++) { 8821 PetscInt i; 8822 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8823 8824 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8825 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8826 for (i = 0; i < PetscSqr(cdim); ++i) { 8827 frobJ += J[i] * J[i]; 8828 frobInvJ += invJ[i] * invJ[i]; 8829 } 8830 cond2 = frobJ * frobInvJ; 8831 cond = PetscSqrtReal(cond2); 8832 8833 stats.min = PetscMin(stats.min,cond); 8834 stats.max = PetscMax(stats.max,cond); 8835 stats.sum += cond; 8836 stats.squaresum += cond2; 8837 stats.count++; 8838 if (output && cond > limit) { 8839 PetscSection coordSection; 8840 Vec coordsLocal; 8841 PetscScalar *coords = NULL; 8842 PetscInt Nv, d, clSize, cl, *closure = NULL; 8843 8844 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8845 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8846 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8847 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8848 for (i = 0; i < Nv/cdim; ++i) { 8849 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8850 for (d = 0; d < cdim; ++d) { 8851 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8852 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8853 } 8854 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8855 } 8856 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8857 for (cl = 0; cl < clSize*2; cl += 2) { 8858 const PetscInt edge = closure[cl]; 8859 8860 if ((edge >= eStart) && (edge < eEnd)) { 8861 PetscReal len; 8862 8863 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8864 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8865 } 8866 } 8867 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8868 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8869 } 8870 } 8871 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8872 8873 if (size > 1) { 8874 PetscMPIInt blockLengths[2] = {4,1}; 8875 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8876 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8877 MPI_Op statReduce; 8878 8879 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8880 PetscCallMPI(MPI_Type_commit(&statType)); 8881 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8882 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8883 PetscCallMPI(MPI_Op_free(&statReduce)); 8884 PetscCallMPI(MPI_Type_free(&statType)); 8885 } else { 8886 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8887 } 8888 if (rank == 0) { 8889 count = globalStats.count; 8890 min = globalStats.min; 8891 max = globalStats.max; 8892 mean = globalStats.sum / globalStats.count; 8893 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8894 } 8895 8896 if (output) { 8897 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)); 8898 } 8899 PetscCall(PetscFree2(J,invJ)); 8900 8901 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8902 if (dmCoarse) { 8903 PetscBool isplex; 8904 8905 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8906 if (isplex) { 8907 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8908 } 8909 } 8910 PetscFunctionReturn(0); 8911 } 8912 8913 /*@ 8914 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8915 orthogonal quality below given tolerance. 8916 8917 Collective on dm 8918 8919 Input Parameters: 8920 + dm - The DMPlex object 8921 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8922 - atol - [0, 1] Absolute tolerance for tagging cells. 8923 8924 Output Parameters: 8925 + OrthQual - Vec containing orthogonal quality per cell 8926 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8927 8928 Options Database Keys: 8929 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8930 supported. 8931 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8932 8933 Notes: 8934 Orthogonal quality is given by the following formula: 8935 8936 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8937 8938 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 8939 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8940 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8941 calculating the cosine of the angle between these vectors. 8942 8943 Orthogonal quality ranges from 1 (best) to 0 (worst). 8944 8945 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8946 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8947 8948 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8949 8950 Level: intermediate 8951 8952 .seealso: `DMPlexCheckCellShape()`, `DMCreateLabel()` 8953 @*/ 8954 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8955 { 8956 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8957 PetscInt *idx; 8958 PetscScalar *oqVals; 8959 const PetscScalar *cellGeomArr, *faceGeomArr; 8960 PetscReal *ci, *fi, *Ai; 8961 MPI_Comm comm; 8962 Vec cellgeom, facegeom; 8963 DM dmFace, dmCell; 8964 IS glob; 8965 ISLocalToGlobalMapping ltog; 8966 PetscViewer vwr; 8967 8968 PetscFunctionBegin; 8969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8970 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8971 PetscValidPointer(OrthQual, 4); 8972 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8973 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8974 PetscCall(DMGetDimension(dm, &nc)); 8975 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8976 { 8977 DMPlexInterpolatedFlag interpFlag; 8978 8979 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8980 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8981 PetscMPIInt rank; 8982 8983 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8984 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8985 } 8986 } 8987 if (OrthQualLabel) { 8988 PetscValidPointer(OrthQualLabel, 5); 8989 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8990 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8991 } else {*OrthQualLabel = NULL;} 8992 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8993 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8994 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8995 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8996 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8997 PetscCall(VecCreate(comm, OrthQual)); 8998 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8999 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 9000 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 9001 PetscCall(VecSetUp(*OrthQual)); 9002 PetscCall(ISDestroy(&glob)); 9003 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 9004 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 9005 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 9006 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 9007 PetscCall(VecGetDM(cellgeom, &dmCell)); 9008 PetscCall(VecGetDM(facegeom, &dmFace)); 9009 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 9010 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 9011 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 9012 PetscInt cellarr[2], *adj = NULL; 9013 PetscScalar *cArr, *fArr; 9014 PetscReal minvalc = 1.0, minvalf = 1.0; 9015 PetscFVCellGeom *cg; 9016 9017 idx[cellIter] = cell-cStart; 9018 cellarr[0] = cell; 9019 /* Make indexing into cellGeom easier */ 9020 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 9021 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 9022 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 9023 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 9024 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 9025 PetscInt i; 9026 const PetscInt neigh = adj[cellneigh]; 9027 PetscReal normci = 0, normfi = 0, normai = 0; 9028 PetscFVCellGeom *cgneigh; 9029 PetscFVFaceGeom *fg; 9030 9031 /* Don't count ourselves in the neighbor list */ 9032 if (neigh == cell) continue; 9033 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 9034 cellarr[1] = neigh; 9035 { 9036 PetscInt numcovpts; 9037 const PetscInt *covpts; 9038 9039 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9040 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 9041 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 9042 } 9043 9044 /* Compute c_i, f_i and their norms */ 9045 for (i = 0; i < nc; i++) { 9046 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 9047 fi[i] = fg->centroid[i] - cg->centroid[i]; 9048 Ai[i] = fg->normal[i]; 9049 normci += PetscPowReal(ci[i], 2); 9050 normfi += PetscPowReal(fi[i], 2); 9051 normai += PetscPowReal(Ai[i], 2); 9052 } 9053 normci = PetscSqrtReal(normci); 9054 normfi = PetscSqrtReal(normfi); 9055 normai = PetscSqrtReal(normai); 9056 9057 /* Normalize and compute for each face-cell-normal pair */ 9058 for (i = 0; i < nc; i++) { 9059 ci[i] = ci[i]/normci; 9060 fi[i] = fi[i]/normfi; 9061 Ai[i] = Ai[i]/normai; 9062 /* PetscAbs because I don't know if normals are guaranteed to point out */ 9063 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9064 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9065 } 9066 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9067 minvalc = PetscRealPart(cArr[cellneighiter]); 9068 } 9069 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9070 minvalf = PetscRealPart(fArr[cellneighiter]); 9071 } 9072 } 9073 PetscCall(PetscFree(adj)); 9074 PetscCall(PetscFree2(cArr, fArr)); 9075 /* Defer to cell if they're equal */ 9076 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9077 if (OrthQualLabel) { 9078 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9079 } 9080 } 9081 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9082 PetscCall(VecAssemblyBegin(*OrthQual)); 9083 PetscCall(VecAssemblyEnd(*OrthQual)); 9084 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9085 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9086 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9087 if (OrthQualLabel) { 9088 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9089 } 9090 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9091 PetscCall(PetscViewerDestroy(&vwr)); 9092 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9093 PetscFunctionReturn(0); 9094 } 9095 9096 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9097 * interpolator construction */ 9098 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9099 { 9100 PetscSection section, newSection, gsection; 9101 PetscSF sf; 9102 PetscBool hasConstraints, ghasConstraints; 9103 9104 PetscFunctionBegin; 9105 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9106 PetscValidPointer(odm,2); 9107 PetscCall(DMGetLocalSection(dm, §ion)); 9108 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9109 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9110 if (!ghasConstraints) { 9111 PetscCall(PetscObjectReference((PetscObject)dm)); 9112 *odm = dm; 9113 PetscFunctionReturn(0); 9114 } 9115 PetscCall(DMClone(dm, odm)); 9116 PetscCall(DMCopyFields(dm, *odm)); 9117 PetscCall(DMGetLocalSection(*odm, &newSection)); 9118 PetscCall(DMGetPointSF(*odm, &sf)); 9119 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9120 PetscCall(DMSetGlobalSection(*odm, gsection)); 9121 PetscCall(PetscSectionDestroy(&gsection)); 9122 PetscFunctionReturn(0); 9123 } 9124 9125 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9126 { 9127 DM dmco, dmfo; 9128 Mat interpo; 9129 Vec rscale; 9130 Vec cglobalo, clocal; 9131 Vec fglobal, fglobalo, flocal; 9132 PetscBool regular; 9133 9134 PetscFunctionBegin; 9135 PetscCall(DMGetFullDM(dmc, &dmco)); 9136 PetscCall(DMGetFullDM(dmf, &dmfo)); 9137 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9138 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9139 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9140 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9141 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9142 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9143 PetscCall(VecSet(cglobalo, 0.)); 9144 PetscCall(VecSet(clocal, 0.)); 9145 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9146 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9147 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9148 PetscCall(VecSet(fglobal, 0.)); 9149 PetscCall(VecSet(fglobalo, 0.)); 9150 PetscCall(VecSet(flocal, 0.)); 9151 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9152 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9153 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9154 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9155 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9156 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9157 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9158 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9159 *shift = fglobal; 9160 PetscCall(VecDestroy(&flocal)); 9161 PetscCall(VecDestroy(&fglobalo)); 9162 PetscCall(VecDestroy(&clocal)); 9163 PetscCall(VecDestroy(&cglobalo)); 9164 PetscCall(VecDestroy(&rscale)); 9165 PetscCall(MatDestroy(&interpo)); 9166 PetscCall(DMDestroy(&dmfo)); 9167 PetscCall(DMDestroy(&dmco)); 9168 PetscFunctionReturn(0); 9169 } 9170 9171 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9172 { 9173 PetscObject shifto; 9174 Vec shift; 9175 9176 PetscFunctionBegin; 9177 if (!interp) { 9178 Vec rscale; 9179 9180 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9181 PetscCall(VecDestroy(&rscale)); 9182 } else { 9183 PetscCall(PetscObjectReference((PetscObject)interp)); 9184 } 9185 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9186 if (!shifto) { 9187 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9188 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9189 shifto = (PetscObject) shift; 9190 PetscCall(VecDestroy(&shift)); 9191 } 9192 shift = (Vec) shifto; 9193 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9194 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9195 PetscCall(MatDestroy(&interp)); 9196 PetscFunctionReturn(0); 9197 } 9198 9199 /* Pointwise interpolation 9200 Just code FEM for now 9201 u^f = I u^c 9202 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9203 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9204 I_{ij} = psi^f_i phi^c_j 9205 */ 9206 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9207 { 9208 PetscSection gsc, gsf; 9209 PetscInt m, n; 9210 void *ctx; 9211 DM cdm; 9212 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9213 9214 PetscFunctionBegin; 9215 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9216 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9217 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9218 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9219 9220 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9221 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9222 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9223 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9224 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9225 9226 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9227 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9228 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9229 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9230 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9231 if (scaling) { 9232 /* Use naive scaling */ 9233 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9234 } 9235 PetscFunctionReturn(0); 9236 } 9237 9238 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9239 { 9240 VecScatter ctx; 9241 9242 PetscFunctionBegin; 9243 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9244 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9245 PetscCall(VecScatterDestroy(&ctx)); 9246 PetscFunctionReturn(0); 9247 } 9248 9249 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9250 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9251 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9252 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9253 { 9254 const PetscInt Nc = uOff[1] - uOff[0]; 9255 PetscInt c; 9256 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9257 } 9258 9259 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9260 { 9261 DM dmc; 9262 PetscDS ds; 9263 Vec ones, locmass; 9264 IS cellIS; 9265 PetscFormKey key; 9266 PetscInt depth; 9267 9268 PetscFunctionBegin; 9269 PetscCall(DMClone(dm, &dmc)); 9270 PetscCall(DMCopyDisc(dm, dmc)); 9271 PetscCall(DMGetDS(dmc, &ds)); 9272 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9273 PetscCall(DMCreateGlobalVector(dmc, mass)); 9274 PetscCall(DMGetLocalVector(dmc, &ones)); 9275 PetscCall(DMGetLocalVector(dmc, &locmass)); 9276 PetscCall(DMPlexGetDepth(dmc, &depth)); 9277 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9278 PetscCall(VecSet(locmass, 0.0)); 9279 PetscCall(VecSet(ones, 1.0)); 9280 key.label = NULL; 9281 key.value = 0; 9282 key.field = 0; 9283 key.part = 0; 9284 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9285 PetscCall(ISDestroy(&cellIS)); 9286 PetscCall(VecSet(*mass, 0.0)); 9287 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9288 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9289 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9290 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9291 PetscCall(DMDestroy(&dmc)); 9292 PetscFunctionReturn(0); 9293 } 9294 9295 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9296 { 9297 PetscSection gsc, gsf; 9298 PetscInt m, n; 9299 void *ctx; 9300 DM cdm; 9301 PetscBool regular; 9302 9303 PetscFunctionBegin; 9304 if (dmFine == dmCoarse) { 9305 DM dmc; 9306 PetscDS ds; 9307 PetscWeakForm wf; 9308 Vec u; 9309 IS cellIS; 9310 PetscFormKey key; 9311 PetscInt depth; 9312 9313 PetscCall(DMClone(dmFine, &dmc)); 9314 PetscCall(DMCopyDisc(dmFine, dmc)); 9315 PetscCall(DMGetDS(dmc, &ds)); 9316 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9317 PetscCall(PetscWeakFormClear(wf)); 9318 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9319 PetscCall(DMCreateMatrix(dmc, mass)); 9320 PetscCall(DMGetGlobalVector(dmc, &u)); 9321 PetscCall(DMPlexGetDepth(dmc, &depth)); 9322 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9323 PetscCall(MatZeroEntries(*mass)); 9324 key.label = NULL; 9325 key.value = 0; 9326 key.field = 0; 9327 key.part = 0; 9328 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9329 PetscCall(ISDestroy(&cellIS)); 9330 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9331 PetscCall(DMDestroy(&dmc)); 9332 } else { 9333 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9334 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9335 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9336 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9337 9338 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9339 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9340 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9341 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9342 9343 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9344 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9345 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9346 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9347 } 9348 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9349 PetscFunctionReturn(0); 9350 } 9351 9352 /*@ 9353 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9354 9355 Input Parameter: 9356 . dm - The DMPlex object 9357 9358 Output Parameter: 9359 . regular - The flag 9360 9361 Level: intermediate 9362 9363 .seealso: `DMPlexSetRegularRefinement()` 9364 @*/ 9365 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9366 { 9367 PetscFunctionBegin; 9368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9369 PetscValidBoolPointer(regular, 2); 9370 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9371 PetscFunctionReturn(0); 9372 } 9373 9374 /*@ 9375 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9376 9377 Input Parameters: 9378 + dm - The DMPlex object 9379 - regular - The flag 9380 9381 Level: intermediate 9382 9383 .seealso: `DMPlexGetRegularRefinement()` 9384 @*/ 9385 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9386 { 9387 PetscFunctionBegin; 9388 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9389 ((DM_Plex *) dm->data)->regularRefinement = regular; 9390 PetscFunctionReturn(0); 9391 } 9392 9393 /* anchors */ 9394 /*@ 9395 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9396 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9397 9398 not collective 9399 9400 Input Parameter: 9401 . dm - The DMPlex object 9402 9403 Output Parameters: 9404 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9405 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9406 9407 Level: intermediate 9408 9409 .seealso: `DMPlexSetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9410 @*/ 9411 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9412 { 9413 DM_Plex *plex = (DM_Plex *)dm->data; 9414 9415 PetscFunctionBegin; 9416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9417 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9418 if (anchorSection) *anchorSection = plex->anchorSection; 9419 if (anchorIS) *anchorIS = plex->anchorIS; 9420 PetscFunctionReturn(0); 9421 } 9422 9423 /*@ 9424 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9425 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9426 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9427 9428 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9429 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9430 9431 collective on dm 9432 9433 Input Parameters: 9434 + dm - The DMPlex object 9435 . 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). 9436 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9437 9438 The reference counts of anchorSection and anchorIS are incremented. 9439 9440 Level: intermediate 9441 9442 .seealso: `DMPlexGetAnchors()`, `DMGetDefaultConstraints()`, `DMSetDefaultConstraints()` 9443 @*/ 9444 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9445 { 9446 DM_Plex *plex = (DM_Plex *)dm->data; 9447 PetscMPIInt result; 9448 9449 PetscFunctionBegin; 9450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9451 if (anchorSection) { 9452 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9453 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9454 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9455 } 9456 if (anchorIS) { 9457 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9458 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9459 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9460 } 9461 9462 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9463 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9464 plex->anchorSection = anchorSection; 9465 9466 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9467 PetscCall(ISDestroy(&plex->anchorIS)); 9468 plex->anchorIS = anchorIS; 9469 9470 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9471 PetscInt size, a, pStart, pEnd; 9472 const PetscInt *anchors; 9473 9474 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9475 PetscCall(ISGetLocalSize(anchorIS,&size)); 9476 PetscCall(ISGetIndices(anchorIS,&anchors)); 9477 for (a = 0; a < size; a++) { 9478 PetscInt p; 9479 9480 p = anchors[a]; 9481 if (p >= pStart && p < pEnd) { 9482 PetscInt dof; 9483 9484 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9485 if (dof) { 9486 9487 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9488 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9489 } 9490 } 9491 } 9492 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9493 } 9494 /* reset the generic constraints */ 9495 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9496 PetscFunctionReturn(0); 9497 } 9498 9499 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9500 { 9501 PetscSection anchorSection; 9502 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9503 9504 PetscFunctionBegin; 9505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9506 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9507 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9508 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9509 if (numFields) { 9510 PetscInt f; 9511 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9512 9513 for (f = 0; f < numFields; f++) { 9514 PetscInt numComp; 9515 9516 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9517 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9518 } 9519 } 9520 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9521 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9522 pStart = PetscMax(pStart,sStart); 9523 pEnd = PetscMin(pEnd,sEnd); 9524 pEnd = PetscMax(pStart,pEnd); 9525 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9526 for (p = pStart; p < pEnd; p++) { 9527 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9528 if (dof) { 9529 PetscCall(PetscSectionGetDof(section,p,&dof)); 9530 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9531 for (f = 0; f < numFields; f++) { 9532 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9533 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9534 } 9535 } 9536 } 9537 PetscCall(PetscSectionSetUp(*cSec)); 9538 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9539 PetscFunctionReturn(0); 9540 } 9541 9542 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9543 { 9544 PetscSection aSec; 9545 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9546 const PetscInt *anchors; 9547 PetscInt numFields, f; 9548 IS aIS; 9549 MatType mtype; 9550 PetscBool iscuda,iskokkos; 9551 9552 PetscFunctionBegin; 9553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9554 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9555 PetscCall(PetscSectionGetStorageSize(section, &n)); 9556 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9557 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9558 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9559 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9560 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9561 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9562 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9563 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9564 else mtype = MATSEQAIJ; 9565 PetscCall(MatSetType(*cMat,mtype)); 9566 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9567 PetscCall(ISGetIndices(aIS,&anchors)); 9568 /* cSec will be a subset of aSec and section */ 9569 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9570 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9571 PetscCall(PetscMalloc1(m+1,&i)); 9572 i[0] = 0; 9573 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9574 for (p = pStart; p < pEnd; p++) { 9575 PetscInt rDof, rOff, r; 9576 9577 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9578 if (!rDof) continue; 9579 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9580 if (numFields) { 9581 for (f = 0; f < numFields; f++) { 9582 annz = 0; 9583 for (r = 0; r < rDof; r++) { 9584 a = anchors[rOff + r]; 9585 if (a < sStart || a >= sEnd) continue; 9586 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9587 annz += aDof; 9588 } 9589 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9590 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9591 for (q = 0; q < dof; q++) { 9592 i[off + q + 1] = i[off + q] + annz; 9593 } 9594 } 9595 } else { 9596 annz = 0; 9597 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9598 for (q = 0; q < dof; q++) { 9599 a = anchors[rOff + q]; 9600 if (a < sStart || a >= sEnd) continue; 9601 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9602 annz += aDof; 9603 } 9604 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9605 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9606 for (q = 0; q < dof; q++) { 9607 i[off + q + 1] = i[off + q] + annz; 9608 } 9609 } 9610 } 9611 nnz = i[m]; 9612 PetscCall(PetscMalloc1(nnz,&j)); 9613 offset = 0; 9614 for (p = pStart; p < pEnd; p++) { 9615 if (numFields) { 9616 for (f = 0; f < numFields; f++) { 9617 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9618 for (q = 0; q < dof; q++) { 9619 PetscInt rDof, rOff, r; 9620 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9621 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9622 for (r = 0; r < rDof; r++) { 9623 PetscInt s; 9624 9625 a = anchors[rOff + r]; 9626 if (a < sStart || a >= sEnd) continue; 9627 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9628 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9629 for (s = 0; s < aDof; s++) { 9630 j[offset++] = aOff + s; 9631 } 9632 } 9633 } 9634 } 9635 } else { 9636 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9637 for (q = 0; q < dof; q++) { 9638 PetscInt rDof, rOff, r; 9639 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9640 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9641 for (r = 0; r < rDof; r++) { 9642 PetscInt s; 9643 9644 a = anchors[rOff + r]; 9645 if (a < sStart || a >= sEnd) continue; 9646 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9647 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9648 for (s = 0; s < aDof; s++) { 9649 j[offset++] = aOff + s; 9650 } 9651 } 9652 } 9653 } 9654 } 9655 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9656 PetscCall(PetscFree(i)); 9657 PetscCall(PetscFree(j)); 9658 PetscCall(ISRestoreIndices(aIS,&anchors)); 9659 PetscFunctionReturn(0); 9660 } 9661 9662 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9663 { 9664 DM_Plex *plex = (DM_Plex *)dm->data; 9665 PetscSection anchorSection, section, cSec; 9666 Mat cMat; 9667 9668 PetscFunctionBegin; 9669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9670 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9671 if (anchorSection) { 9672 PetscInt Nf; 9673 9674 PetscCall(DMGetLocalSection(dm,§ion)); 9675 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9676 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9677 PetscCall(DMGetNumFields(dm,&Nf)); 9678 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9679 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9680 PetscCall(PetscSectionDestroy(&cSec)); 9681 PetscCall(MatDestroy(&cMat)); 9682 } 9683 PetscFunctionReturn(0); 9684 } 9685 9686 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9687 { 9688 IS subis; 9689 PetscSection section, subsection; 9690 9691 PetscFunctionBegin; 9692 PetscCall(DMGetLocalSection(dm, §ion)); 9693 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9694 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9695 /* Create subdomain */ 9696 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9697 /* Create submodel */ 9698 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9699 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9700 PetscCall(DMSetLocalSection(*subdm, subsection)); 9701 PetscCall(PetscSectionDestroy(&subsection)); 9702 PetscCall(DMCopyDisc(dm, *subdm)); 9703 /* Create map from submodel to global model */ 9704 if (is) { 9705 PetscSection sectionGlobal, subsectionGlobal; 9706 IS spIS; 9707 const PetscInt *spmap; 9708 PetscInt *subIndices; 9709 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9710 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9711 9712 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9713 PetscCall(ISGetIndices(spIS, &spmap)); 9714 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9715 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9716 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9717 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9718 for (p = pStart; p < pEnd; ++p) { 9719 PetscInt gdof, pSubSize = 0; 9720 9721 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9722 if (gdof > 0) { 9723 for (f = 0; f < Nf; ++f) { 9724 PetscInt fdof, fcdof; 9725 9726 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9727 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9728 pSubSize += fdof-fcdof; 9729 } 9730 subSize += pSubSize; 9731 if (pSubSize) { 9732 if (bs < 0) { 9733 bs = pSubSize; 9734 } else if (bs != pSubSize) { 9735 /* Layout does not admit a pointwise block size */ 9736 bs = 1; 9737 } 9738 } 9739 } 9740 } 9741 /* Must have same blocksize on all procs (some might have no points) */ 9742 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9743 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9744 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9745 else {bs = bsMinMax[0];} 9746 PetscCall(PetscMalloc1(subSize, &subIndices)); 9747 for (p = pStart; p < pEnd; ++p) { 9748 PetscInt gdof, goff; 9749 9750 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9751 if (gdof > 0) { 9752 const PetscInt point = spmap[p]; 9753 9754 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9755 for (f = 0; f < Nf; ++f) { 9756 PetscInt fdof, fcdof, fc, f2, poff = 0; 9757 9758 /* Can get rid of this loop by storing field information in the global section */ 9759 for (f2 = 0; f2 < f; ++f2) { 9760 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9761 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9762 poff += fdof-fcdof; 9763 } 9764 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9765 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9766 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9767 subIndices[subOff] = goff+poff+fc; 9768 } 9769 } 9770 } 9771 } 9772 PetscCall(ISRestoreIndices(spIS, &spmap)); 9773 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9774 if (bs > 1) { 9775 /* We need to check that the block size does not come from non-contiguous fields */ 9776 PetscInt i, j, set = 1; 9777 for (i = 0; i < subSize; i += bs) { 9778 for (j = 0; j < bs; ++j) { 9779 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9780 } 9781 } 9782 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9783 } 9784 /* Attach nullspace */ 9785 for (f = 0; f < Nf; ++f) { 9786 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9787 if ((*subdm)->nullspaceConstructors[f]) break; 9788 } 9789 if (f < Nf) { 9790 MatNullSpace nullSpace; 9791 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9792 9793 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9794 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9795 } 9796 } 9797 PetscFunctionReturn(0); 9798 } 9799 9800 /*@ 9801 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9802 9803 Input Parameter: 9804 - dm - The DM 9805 9806 Level: developer 9807 9808 Options Database Keys: 9809 . -dm_plex_monitor_throughput - Activate the monitor 9810 9811 .seealso: `DMSetFromOptions()`, `DMPlexCreate()` 9812 @*/ 9813 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9814 { 9815 #if defined(PETSC_USE_LOG) 9816 PetscStageLog stageLog; 9817 PetscLogEvent event; 9818 PetscLogStage stage; 9819 PetscEventPerfInfo eventInfo; 9820 PetscReal cellRate, flopRate; 9821 PetscInt cStart, cEnd, Nf, N; 9822 const char *name; 9823 #endif 9824 9825 PetscFunctionBegin; 9826 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9827 #if defined(PETSC_USE_LOG) 9828 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9829 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9830 PetscCall(DMGetNumFields(dm, &Nf)); 9831 PetscCall(PetscLogGetStageLog(&stageLog)); 9832 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9833 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9834 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9835 N = (cEnd - cStart)*Nf*eventInfo.count; 9836 flopRate = eventInfo.flops/eventInfo.time; 9837 cellRate = N/eventInfo.time; 9838 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))); 9839 #else 9840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9841 #endif 9842 PetscFunctionReturn(0); 9843 } 9844