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