1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petsc/private/glvisvecimpl.h> 5 #include <petscsf.h> 6 #include <petscds.h> 7 #include <petscdraw.h> 8 #include <petscdmfield.h> 9 #include <petscdmplextransform.h> 10 11 /* Logging support */ 12 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_InterpolateSF, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Symmetrize, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh, DMPLEX_RebalanceSharedPoints, DMPLEX_PartSelf, DMPLEX_PartLabelInvert, DMPLEX_PartLabelCreateSF, DMPLEX_PartStratSF, DMPLEX_CreatePointSF,DMPLEX_LocatePoints,DMPLEX_TopologyView,DMPLEX_LabelsView,DMPLEX_CoordinatesView,DMPLEX_SectionView,DMPLEX_GlobalVectorView,DMPLEX_LocalVectorView,DMPLEX_TopologyLoad,DMPLEX_LabelsLoad,DMPLEX_CoordinatesLoad,DMPLEX_SectionLoad,DMPLEX_GlobalVectorLoad,DMPLEX_LocalVectorLoad; 13 14 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 15 16 /*@ 17 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 18 19 Input Parameter: 20 . dm - The DMPlex object 21 22 Output Parameter: 23 . simplex - Flag checking for a simplex 24 25 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 26 If the mesh has no cells, this returns PETSC_FALSE. 27 28 Level: intermediate 29 30 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices() 31 @*/ 32 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 33 { 34 DMPolytopeType ct; 35 PetscInt cStart, cEnd; 36 37 PetscFunctionBegin; 38 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameters: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 67 PetscFunctionBegin; 68 PetscCall(DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE)); 69 for (c = cS; c < cE; ++c) { 70 DMPolytopeType cct; 71 72 PetscCall(DMPlexGetCellType(dm, c, &cct)); 73 if ((PetscInt) cct < 0) break; 74 switch (cct) { 75 case DM_POLYTOPE_POINT: 76 case DM_POLYTOPE_SEGMENT: 77 case DM_POLYTOPE_TRIANGLE: 78 case DM_POLYTOPE_QUADRILATERAL: 79 case DM_POLYTOPE_TETRAHEDRON: 80 case DM_POLYTOPE_HEXAHEDRON: 81 ct = cct; 82 break; 83 default: break; 84 } 85 if (ct != DM_POLYTOPE_UNKNOWN) break; 86 } 87 if (ct != DM_POLYTOPE_UNKNOWN) { 88 DMLabel ctLabel; 89 90 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 91 PetscCall(DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE)); 92 } 93 if (cStart) *cStart = cS; 94 if (cEnd) *cEnd = cE; 95 PetscFunctionReturn(0); 96 } 97 98 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 99 { 100 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 101 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 102 103 PetscFunctionBegin; 104 *ft = PETSC_VTK_INVALID; 105 PetscCall(DMGetCoordinateDim(dm, &cdim)); 106 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 107 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 108 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 109 if (field >= 0) { 110 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, vStart, field, &vcdof[0])); 111 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetFieldDof(section, cStart, field, &vcdof[1])); 112 } else { 113 if ((vStart >= pStart) && (vStart < pEnd)) PetscCall(PetscSectionGetDof(section, vStart, &vcdof[0])); 114 if ((cStart >= pStart) && (cStart < pEnd)) PetscCall(PetscSectionGetDof(section, cStart, &vcdof[1])); 115 } 116 PetscCallMPI(MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 117 if (globalvcdof[0]) { 118 *sStart = vStart; 119 *sEnd = vEnd; 120 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 121 else *ft = PETSC_VTK_POINT_FIELD; 122 } else if (globalvcdof[1]) { 123 *sStart = cStart; 124 *sEnd = cEnd; 125 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 126 else *ft = PETSC_VTK_CELL_FIELD; 127 } else { 128 if (field >= 0) { 129 const char *fieldname; 130 131 PetscCall(PetscSectionGetFieldName(section, field, &fieldname)); 132 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section field %" PetscInt_FMT " \"%s\"\n", field, fieldname)); 133 } else { 134 PetscCall(PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\n")); 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /*@ 141 DMPlexVecView1D - Plot many 1D solutions on the same line graph 142 143 Collective on dm 144 145 Input Parameters: 146 + dm - The DMPlex 147 . n - The number of vectors 148 . u - The array of local vectors 149 - viewer - The Draw viewer 150 151 Level: advanced 152 153 .seealso: VecViewFromOptions(), VecView() 154 @*/ 155 PetscErrorCode DMPlexVecView1D(DM dm, PetscInt n, Vec u[], PetscViewer viewer) 156 { 157 PetscDS ds; 158 PetscDraw draw = NULL; 159 PetscDrawLG lg; 160 Vec coordinates; 161 const PetscScalar *coords, **sol; 162 PetscReal *vals; 163 PetscInt *Nc; 164 PetscInt Nf, f, c, Nl, l, i, vStart, vEnd, v; 165 char **names; 166 167 PetscFunctionBegin; 168 PetscCall(DMGetDS(dm, &ds)); 169 PetscCall(PetscDSGetNumFields(ds, &Nf)); 170 PetscCall(PetscDSGetTotalComponents(ds, &Nl)); 171 PetscCall(PetscDSGetComponents(ds, &Nc)); 172 173 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 174 if (!draw) PetscFunctionReturn(0); 175 PetscCall(PetscDrawLGCreate(draw, n*Nl, &lg)); 176 177 PetscCall(PetscMalloc3(n, &sol, n*Nl, &names, n*Nl, &vals)); 178 for (i = 0, l = 0; i < n; ++i) { 179 const char *vname; 180 181 PetscCall(PetscObjectGetName((PetscObject) u[i], &vname)); 182 for (f = 0; f < Nf; ++f) { 183 PetscObject disc; 184 const char *fname; 185 char tmpname[PETSC_MAX_PATH_LEN]; 186 187 PetscCall(PetscDSGetDiscretization(ds, f, &disc)); 188 /* TODO Create names for components */ 189 for (c = 0; c < Nc[f]; ++c, ++l) { 190 PetscCall(PetscObjectGetName(disc, &fname)); 191 PetscCall(PetscStrcpy(tmpname, vname)); 192 PetscCall(PetscStrlcat(tmpname, ":", PETSC_MAX_PATH_LEN)); 193 PetscCall(PetscStrlcat(tmpname, fname, PETSC_MAX_PATH_LEN)); 194 PetscCall(PetscStrallocpy(tmpname, &names[l])); 195 } 196 } 197 } 198 PetscCall(PetscDrawLGSetLegend(lg, (const char *const *) names)); 199 /* Just add P_1 support for now */ 200 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 201 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 202 PetscCall(VecGetArrayRead(coordinates, &coords)); 203 for (i = 0; i < n; ++i) PetscCall(VecGetArrayRead(u[i], &sol[i])); 204 for (v = vStart; v < vEnd; ++v) { 205 PetscScalar *x, *svals; 206 207 PetscCall(DMPlexPointLocalRead(dm, v, coords, &x)); 208 for (i = 0; i < n; ++i) { 209 PetscCall(DMPlexPointLocalRead(dm, v, sol[i], &svals)); 210 for (l = 0; l < Nl; ++l) vals[i*Nl + l] = PetscRealPart(svals[l]); 211 } 212 PetscCall(PetscDrawLGAddCommonPoint(lg, PetscRealPart(x[0]), vals)); 213 } 214 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 215 for (i = 0; i < n; ++i) PetscCall(VecRestoreArrayRead(u[i], &sol[i])); 216 for (l = 0; l < n*Nl; ++l) PetscCall(PetscFree(names[l])); 217 PetscCall(PetscFree3(sol, names, vals)); 218 219 PetscCall(PetscDrawLGDraw(lg)); 220 PetscCall(PetscDrawLGDestroy(&lg)); 221 PetscFunctionReturn(0); 222 } 223 224 static PetscErrorCode VecView_Plex_Local_Draw_1D(Vec u, PetscViewer viewer) 225 { 226 DM dm; 227 228 PetscFunctionBegin; 229 PetscCall(VecGetDM(u, &dm)); 230 PetscCall(DMPlexVecView1D(dm, 1, &u, viewer)); 231 PetscFunctionReturn(0); 232 } 233 234 static PetscErrorCode VecView_Plex_Local_Draw_2D(Vec v, PetscViewer viewer) 235 { 236 DM dm; 237 PetscSection s; 238 PetscDraw draw, popup; 239 DM cdm; 240 PetscSection coordSection; 241 Vec coordinates; 242 const PetscScalar *coords, *array; 243 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 244 PetscReal vbound[2], time; 245 PetscBool flg; 246 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 247 const char *name; 248 char title[PETSC_MAX_PATH_LEN]; 249 250 PetscFunctionBegin; 251 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 252 PetscCall(VecGetDM(v, &dm)); 253 PetscCall(DMGetCoordinateDim(dm, &dim)); 254 PetscCall(DMGetLocalSection(dm, &s)); 255 PetscCall(PetscSectionGetNumFields(s, &Nf)); 256 PetscCall(DMGetCoarsenLevel(dm, &level)); 257 PetscCall(DMGetCoordinateDM(dm, &cdm)); 258 PetscCall(DMGetLocalSection(cdm, &coordSection)); 259 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 260 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 261 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 262 263 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 264 PetscCall(DMGetOutputSequenceNumber(dm, &step, &time)); 265 266 PetscCall(VecGetLocalSize(coordinates, &N)); 267 PetscCall(VecGetArrayRead(coordinates, &coords)); 268 for (c = 0; c < N; c += dim) { 269 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 270 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 271 } 272 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 273 PetscCall(PetscDrawClear(draw)); 274 275 /* Could implement something like DMDASelectFields() */ 276 for (f = 0; f < Nf; ++f) { 277 DM fdm = dm; 278 Vec fv = v; 279 IS fis; 280 char prefix[PETSC_MAX_PATH_LEN]; 281 const char *fname; 282 283 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 284 PetscCall(PetscSectionGetFieldName(s, f, &fname)); 285 286 if (v->hdr.prefix) PetscCall(PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix))); 287 else {prefix[0] = '\0';} 288 if (Nf > 1) { 289 PetscCall(DMCreateSubDM(dm, 1, &f, &fis, &fdm)); 290 PetscCall(VecGetSubVector(v, fis, &fv)); 291 PetscCall(PetscStrlcat(prefix, fname,sizeof(prefix))); 292 PetscCall(PetscStrlcat(prefix, "_",sizeof(prefix))); 293 } 294 for (comp = 0; comp < Nc; ++comp, ++w) { 295 PetscInt nmax = 2; 296 297 PetscCall(PetscViewerDrawGetDraw(viewer, w, &draw)); 298 if (Nc > 1) PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s_%" PetscInt_FMT " Step: %" PetscInt_FMT " Time: %.4g", name, fname, comp, step, (double)time)); 299 else PetscCall(PetscSNPrintf(title, sizeof(title), "%s:%s Step: %" PetscInt_FMT " Time: %.4g", name, fname, step, (double)time)); 300 PetscCall(PetscDrawSetTitle(draw, title)); 301 302 /* TODO Get max and min only for this component */ 303 PetscCall(PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg)); 304 if (!flg) { 305 PetscCall(VecMin(fv, NULL, &vbound[0])); 306 PetscCall(VecMax(fv, NULL, &vbound[1])); 307 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 308 } 309 PetscCall(PetscDrawGetPopup(draw, &popup)); 310 PetscCall(PetscDrawScalePopup(popup, vbound[0], vbound[1])); 311 PetscCall(PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3])); 312 313 PetscCall(VecGetArrayRead(fv, &array)); 314 for (c = cStart; c < cEnd; ++c) { 315 PetscScalar *coords = NULL, *a = NULL; 316 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 317 318 PetscCall(DMPlexPointLocalRead(fdm, c, array, &a)); 319 if (a) { 320 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 321 color[1] = color[2] = color[3] = color[0]; 322 } else { 323 PetscScalar *vals = NULL; 324 PetscInt numVals, va; 325 326 PetscCall(DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals)); 327 PetscCheck(numVals % Nc == 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of components %" PetscInt_FMT " does not divide the number of values in the closure %" PetscInt_FMT, Nc, numVals); 328 switch (numVals/Nc) { 329 case 3: /* P1 Triangle */ 330 case 4: /* P1 Quadrangle */ 331 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 332 break; 333 case 6: /* P2 Triangle */ 334 case 8: /* P2 Quadrangle */ 335 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 336 break; 337 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %" PetscInt_FMT " cannot be handled", numVals/Nc); 338 } 339 PetscCall(DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals)); 340 } 341 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 342 switch (numCoords) { 343 case 6: 344 case 12: /* Localized triangle */ 345 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 346 break; 347 case 8: 348 case 16: /* Localized quadrilateral */ 349 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color[0], color[1], color[2])); 350 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color[2], color[3], color[0])); 351 break; 352 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %" PetscInt_FMT " coordinates", numCoords); 353 } 354 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 355 } 356 PetscCall(VecRestoreArrayRead(fv, &array)); 357 PetscCall(PetscDrawFlush(draw)); 358 PetscCall(PetscDrawPause(draw)); 359 PetscCall(PetscDrawSave(draw)); 360 } 361 if (Nf > 1) { 362 PetscCall(VecRestoreSubVector(v, fis, &fv)); 363 PetscCall(ISDestroy(&fis)); 364 PetscCall(DMDestroy(&fdm)); 365 } 366 } 367 PetscFunctionReturn(0); 368 } 369 370 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 371 { 372 DM dm; 373 PetscDraw draw; 374 PetscInt dim; 375 PetscBool isnull; 376 377 PetscFunctionBegin; 378 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 379 PetscCall(PetscDrawIsNull(draw, &isnull)); 380 if (isnull) PetscFunctionReturn(0); 381 382 PetscCall(VecGetDM(v, &dm)); 383 PetscCall(DMGetCoordinateDim(dm, &dim)); 384 switch (dim) { 385 case 1: PetscCall(VecView_Plex_Local_Draw_1D(v, viewer));break; 386 case 2: PetscCall(VecView_Plex_Local_Draw_2D(v, viewer));break; 387 default: SETERRQ(PetscObjectComm((PetscObject) v), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT ". Try PETSCVIEWERGLVIS", dim); 388 } 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 393 { 394 DM dm; 395 Vec locv; 396 const char *name; 397 PetscSection section; 398 PetscInt pStart, pEnd; 399 PetscInt numFields; 400 PetscViewerVTKFieldType ft; 401 402 PetscFunctionBegin; 403 PetscCall(VecGetDM(v, &dm)); 404 PetscCall(DMCreateLocalVector(dm, &locv)); /* VTK viewer requires exclusive ownership of the vector */ 405 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 406 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 407 PetscCall(VecCopy(v, locv)); 408 PetscCall(DMGetLocalSection(dm, §ion)); 409 PetscCall(PetscSectionGetNumFields(section, &numFields)); 410 if (!numFields) { 411 PetscCall(DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft)); 412 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv)); 413 } else { 414 PetscInt f; 415 416 for (f = 0; f < numFields; f++) { 417 PetscCall(DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft)); 418 if (ft == PETSC_VTK_INVALID) continue; 419 PetscCall(PetscObjectReference((PetscObject)locv)); 420 PetscCall(PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv)); 421 } 422 PetscCall(VecDestroy(&locv)); 423 } 424 PetscFunctionReturn(0); 425 } 426 427 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 428 { 429 DM dm; 430 PetscBool isvtk, ishdf5, isdraw, isglvis; 431 432 PetscFunctionBegin; 433 PetscCall(VecGetDM(v, &dm)); 434 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 435 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 436 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 437 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 438 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 439 if (isvtk || ishdf5 || isdraw || isglvis) { 440 PetscInt i,numFields; 441 PetscObject fe; 442 PetscBool fem = PETSC_FALSE; 443 Vec locv = v; 444 const char *name; 445 PetscInt step; 446 PetscReal time; 447 448 PetscCall(DMGetNumFields(dm, &numFields)); 449 for (i=0; i<numFields; i++) { 450 PetscCall(DMGetField(dm, i, NULL, &fe)); 451 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 452 } 453 if (fem) { 454 PetscObject isZero; 455 456 PetscCall(DMGetLocalVector(dm, &locv)); 457 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 458 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 459 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 460 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 461 PetscCall(VecCopy(v, locv)); 462 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 463 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL)); 464 } 465 if (isvtk) { 466 PetscCall(VecView_Plex_Local_VTK(locv, viewer)); 467 } else if (ishdf5) { 468 #if defined(PETSC_HAVE_HDF5) 469 PetscCall(VecView_Plex_Local_HDF5_Internal(locv, viewer)); 470 #else 471 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 472 #endif 473 } else if (isdraw) { 474 PetscCall(VecView_Plex_Local_Draw(locv, viewer)); 475 } else if (isglvis) { 476 PetscCall(DMGetOutputSequenceNumber(dm, &step, NULL)); 477 PetscCall(PetscViewerGLVisSetSnapId(viewer, step)); 478 PetscCall(VecView_GLVis(locv, viewer)); 479 } 480 if (fem) { 481 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 482 PetscCall(DMRestoreLocalVector(dm, &locv)); 483 } 484 } else { 485 PetscBool isseq; 486 487 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 488 if (isseq) PetscCall(VecView_Seq(v, viewer)); 489 else PetscCall(VecView_MPI(v, viewer)); 490 } 491 PetscFunctionReturn(0); 492 } 493 494 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 495 { 496 DM dm; 497 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 498 499 PetscFunctionBegin; 500 PetscCall(VecGetDM(v, &dm)); 501 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 502 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 503 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 504 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 505 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 506 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 507 if (isvtk || isdraw || isglvis) { 508 Vec locv; 509 PetscObject isZero; 510 const char *name; 511 512 PetscCall(DMGetLocalVector(dm, &locv)); 513 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 514 PetscCall(PetscObjectSetName((PetscObject) locv, name)); 515 PetscCall(DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv)); 516 PetscCall(DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv)); 517 PetscCall(PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero)); 518 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero)); 519 PetscCall(VecView_Plex_Local(locv, viewer)); 520 PetscCall(PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL)); 521 PetscCall(DMRestoreLocalVector(dm, &locv)); 522 } else if (ishdf5) { 523 #if defined(PETSC_HAVE_HDF5) 524 PetscCall(VecView_Plex_HDF5_Internal(v, viewer)); 525 #else 526 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 527 #endif 528 } else if (isexodusii) { 529 #if defined(PETSC_HAVE_EXODUSII) 530 PetscCall(VecView_PlexExodusII_Internal(v, viewer)); 531 #else 532 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 533 #endif 534 } else { 535 PetscBool isseq; 536 537 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 538 if (isseq) PetscCall(VecView_Seq(v, viewer)); 539 else PetscCall(VecView_MPI(v, viewer)); 540 } 541 PetscFunctionReturn(0); 542 } 543 544 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 545 { 546 DM dm; 547 MPI_Comm comm; 548 PetscViewerFormat format; 549 Vec v; 550 PetscBool isvtk, ishdf5; 551 552 PetscFunctionBegin; 553 PetscCall(VecGetDM(originalv, &dm)); 554 PetscCall(PetscObjectGetComm((PetscObject) originalv, &comm)); 555 PetscCheck(dm,comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 556 PetscCall(PetscViewerGetFormat(viewer, &format)); 557 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 558 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 559 if (format == PETSC_VIEWER_NATIVE) { 560 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 561 /* this need a better fix */ 562 if (dm->useNatural) { 563 if (dm->sfNatural) { 564 const char *vecname; 565 PetscInt n, nroots; 566 567 PetscCall(VecGetLocalSize(originalv, &n)); 568 PetscCall(PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL)); 569 if (n == nroots) { 570 PetscCall(DMGetGlobalVector(dm, &v)); 571 PetscCall(DMPlexGlobalToNaturalBegin(dm, originalv, v)); 572 PetscCall(DMPlexGlobalToNaturalEnd(dm, originalv, v)); 573 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 574 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 575 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 576 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 577 } else v = originalv; 578 } else v = originalv; 579 580 if (ishdf5) { 581 #if defined(PETSC_HAVE_HDF5) 582 PetscCall(VecView_Plex_HDF5_Native_Internal(v, viewer)); 583 #else 584 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 585 #endif 586 } else if (isvtk) { 587 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 588 } else { 589 PetscBool isseq; 590 591 PetscCall(PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq)); 592 if (isseq) PetscCall(VecView_Seq(v, viewer)); 593 else PetscCall(VecView_MPI(v, viewer)); 594 } 595 if (v != originalv) PetscCall(DMRestoreGlobalVector(dm, &v)); 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 600 { 601 DM dm; 602 PetscBool ishdf5; 603 604 PetscFunctionBegin; 605 PetscCall(VecGetDM(v, &dm)); 606 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 607 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 608 if (ishdf5) { 609 DM dmBC; 610 Vec gv; 611 const char *name; 612 613 PetscCall(DMGetOutputDM(dm, &dmBC)); 614 PetscCall(DMGetGlobalVector(dmBC, &gv)); 615 PetscCall(PetscObjectGetName((PetscObject) v, &name)); 616 PetscCall(PetscObjectSetName((PetscObject) gv, name)); 617 PetscCall(VecLoad_Default(gv, viewer)); 618 PetscCall(DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v)); 619 PetscCall(DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v)); 620 PetscCall(DMRestoreGlobalVector(dmBC, &gv)); 621 } else { 622 PetscCall(VecLoad_Default(v, viewer)); 623 } 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 628 { 629 DM dm; 630 PetscBool ishdf5,isexodusii; 631 632 PetscFunctionBegin; 633 PetscCall(VecGetDM(v, &dm)); 634 PetscCheck(dm,PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 635 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 636 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii)); 637 if (ishdf5) { 638 #if defined(PETSC_HAVE_HDF5) 639 PetscCall(VecLoad_Plex_HDF5_Internal(v, viewer)); 640 #else 641 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 642 #endif 643 } else if (isexodusii) { 644 #if defined(PETSC_HAVE_EXODUSII) 645 PetscCall(VecLoad_PlexExodusII_Internal(v, viewer)); 646 #else 647 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 648 #endif 649 } else { 650 PetscCall(VecLoad_Default(v, viewer)); 651 } 652 PetscFunctionReturn(0); 653 } 654 655 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 656 { 657 DM dm; 658 PetscViewerFormat format; 659 PetscBool ishdf5; 660 661 PetscFunctionBegin; 662 PetscCall(VecGetDM(originalv, &dm)); 663 PetscCheck(dm,PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 664 PetscCall(PetscViewerGetFormat(viewer, &format)); 665 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 666 if (format == PETSC_VIEWER_NATIVE) { 667 if (dm->useNatural) { 668 if (dm->sfNatural) { 669 if (ishdf5) { 670 #if defined(PETSC_HAVE_HDF5) 671 Vec v; 672 const char *vecname; 673 674 PetscCall(DMGetGlobalVector(dm, &v)); 675 PetscCall(PetscObjectGetName((PetscObject) originalv, &vecname)); 676 PetscCall(PetscObjectSetName((PetscObject) v, vecname)); 677 PetscCall(VecLoad_Plex_HDF5_Native_Internal(v, viewer)); 678 PetscCall(DMPlexNaturalToGlobalBegin(dm, v, originalv)); 679 PetscCall(DMPlexNaturalToGlobalEnd(dm, v, originalv)); 680 PetscCall(DMRestoreGlobalVector(dm, &v)); 681 #else 682 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 683 #endif 684 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 685 } 686 } else { 687 PetscCall(VecLoad_Default(originalv, viewer)); 688 } 689 } 690 PetscFunctionReturn(0); 691 } 692 693 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 694 { 695 PetscSection coordSection; 696 Vec coordinates; 697 DMLabel depthLabel, celltypeLabel; 698 const char *name[4]; 699 const PetscScalar *a; 700 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 701 702 PetscFunctionBegin; 703 PetscCall(DMGetDimension(dm, &dim)); 704 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 705 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 706 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 707 PetscCall(DMPlexGetCellTypeLabel(dm, &celltypeLabel)); 708 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 709 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 710 PetscCall(VecGetArrayRead(coordinates, &a)); 711 name[0] = "vertex"; 712 name[1] = "edge"; 713 name[dim-1] = "face"; 714 name[dim] = "cell"; 715 for (c = cStart; c < cEnd; ++c) { 716 PetscInt *closure = NULL; 717 PetscInt closureSize, cl, ct; 718 719 PetscCall(DMLabelGetValue(celltypeLabel, c, &ct)); 720 PetscCall(PetscViewerASCIIPrintf(viewer, "Geometry for cell %" PetscInt_FMT " polytope type %s:\n", c, DMPolytopeTypes[ct])); 721 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 722 PetscCall(PetscViewerASCIIPushTab(viewer)); 723 for (cl = 0; cl < closureSize*2; cl += 2) { 724 PetscInt point = closure[cl], depth, dof, off, d, p; 725 726 if ((point < pStart) || (point >= pEnd)) continue; 727 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 728 if (!dof) continue; 729 PetscCall(DMLabelGetValue(depthLabel, point, &depth)); 730 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 731 PetscCall(PetscViewerASCIIPrintf(viewer, "%s %" PetscInt_FMT " coords:", name[depth], point)); 732 for (p = 0; p < dof/dim; ++p) { 733 PetscCall(PetscViewerASCIIPrintf(viewer, " (")); 734 for (d = 0; d < dim; ++d) { 735 if (d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 736 PetscCall(PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]))); 737 } 738 PetscCall(PetscViewerASCIIPrintf(viewer, ")")); 739 } 740 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 741 } 742 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 743 PetscCall(PetscViewerASCIIPopTab(viewer)); 744 } 745 PetscCall(VecRestoreArrayRead(coordinates, &a)); 746 PetscFunctionReturn(0); 747 } 748 749 typedef enum {CS_CARTESIAN, CS_POLAR, CS_CYLINDRICAL, CS_SPHERICAL} CoordSystem; 750 const char *CoordSystems[] = {"cartesian", "polar", "cylindrical", "spherical", "CoordSystem", "CS_", NULL}; 751 752 static PetscErrorCode DMPlexView_Ascii_Coordinates(PetscViewer viewer, CoordSystem cs, PetscInt dim, const PetscScalar x[]) 753 { 754 PetscInt i; 755 756 PetscFunctionBegin; 757 if (dim > 3) { 758 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) PetscRealPart(x[i]))); 759 } else { 760 PetscReal coords[3], trcoords[3]; 761 762 for (i = 0; i < dim; ++i) coords[i] = PetscRealPart(x[i]); 763 switch (cs) { 764 case CS_CARTESIAN: for (i = 0; i < dim; ++i) trcoords[i] = coords[i];break; 765 case CS_POLAR: 766 PetscCheck(dim == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Polar coordinates are for 2 dimension, not %" PetscInt_FMT, dim); 767 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 768 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 769 break; 770 case CS_CYLINDRICAL: 771 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cylindrical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 772 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])); 773 trcoords[1] = PetscAtan2Real(coords[1], coords[0]); 774 trcoords[2] = coords[2]; 775 break; 776 case CS_SPHERICAL: 777 PetscCheck(dim == 3,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Spherical coordinates are for 3 dimension, not %" PetscInt_FMT, dim); 778 trcoords[0] = PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1]) + PetscSqr(coords[2])); 779 trcoords[1] = PetscAtan2Real(PetscSqrtReal(PetscSqr(coords[0]) + PetscSqr(coords[1])), coords[2]); 780 trcoords[2] = PetscAtan2Real(coords[1], coords[0]); 781 break; 782 } 783 for (i = 0; i < dim; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double) trcoords[i])); 784 } 785 PetscFunctionReturn(0); 786 } 787 788 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 789 { 790 DM_Plex *mesh = (DM_Plex*) dm->data; 791 DM cdm; 792 PetscSection coordSection; 793 Vec coordinates; 794 PetscViewerFormat format; 795 796 PetscFunctionBegin; 797 PetscCall(DMGetCoordinateDM(dm, &cdm)); 798 PetscCall(DMGetLocalSection(cdm, &coordSection)); 799 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 800 PetscCall(PetscViewerGetFormat(viewer, &format)); 801 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 802 const char *name; 803 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 804 PetscInt pStart, pEnd, p, numLabels, l; 805 PetscMPIInt rank, size; 806 807 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 808 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 809 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 810 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 811 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 812 PetscCall(DMGetDimension(dm, &dim)); 813 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 814 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 815 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 816 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 817 PetscCall(PetscViewerASCIIPrintf(viewer, "Supports:\n")); 818 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 819 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %" PetscInt_FMT "\n", rank, maxSupportSize)); 820 for (p = pStart; p < pEnd; ++p) { 821 PetscInt dof, off, s; 822 823 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 824 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 825 for (s = off; s < off+dof; ++s) { 826 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " ----> %" PetscInt_FMT "\n", rank, p, mesh->supports[s])); 827 } 828 } 829 PetscCall(PetscViewerFlush(viewer)); 830 PetscCall(PetscViewerASCIIPrintf(viewer, "Cones:\n")); 831 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %" PetscInt_FMT "\n", rank, maxConeSize)); 832 for (p = pStart; p < pEnd; ++p) { 833 PetscInt dof, off, c; 834 835 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 836 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 837 for (c = off; c < off+dof; ++c) { 838 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %" PetscInt_FMT " <---- %" PetscInt_FMT " (%" PetscInt_FMT ")\n", rank, p, mesh->cones[c], mesh->coneOrientations[c])); 839 } 840 } 841 PetscCall(PetscViewerFlush(viewer)); 842 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 843 if (coordSection && coordinates) { 844 CoordSystem cs = CS_CARTESIAN; 845 const PetscScalar *array; 846 PetscInt Nf, Nc, pStart, pEnd, p; 847 PetscMPIInt rank; 848 const char *name; 849 850 PetscCall(PetscOptionsGetEnum(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_coord_system", CoordSystems, (PetscEnum *) &cs, NULL)); 851 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 852 PetscCall(PetscSectionGetNumFields(coordSection, &Nf)); 853 PetscCheck(Nf == 1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate section should have 1 field, not %" PetscInt_FMT, Nf); 854 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 855 PetscCall(PetscSectionGetChart(coordSection, &pStart, &pEnd)); 856 PetscCall(PetscObjectGetName((PetscObject) coordinates, &name)); 857 PetscCall(PetscViewerASCIIPrintf(viewer, "%s with %" PetscInt_FMT " fields\n", name, Nf)); 858 PetscCall(PetscViewerASCIIPrintf(viewer, " field 0 with %" PetscInt_FMT " components\n", Nc)); 859 if (cs != CS_CARTESIAN) PetscCall(PetscViewerASCIIPrintf(viewer, " output coordinate system: %s\n", CoordSystems[cs])); 860 861 PetscCall(VecGetArrayRead(coordinates, &array)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 864 for (p = pStart; p < pEnd; ++p) { 865 PetscInt dof, off; 866 867 PetscCall(PetscSectionGetDof(coordSection, p, &dof)); 868 PetscCall(PetscSectionGetOffset(coordSection, p, &off)); 869 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT, p, dof, off)); 870 PetscCall(DMPlexView_Ascii_Coordinates(viewer, cs, dof, &array[off])); 871 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 872 } 873 PetscCall(PetscViewerFlush(viewer)); 874 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 875 PetscCall(VecRestoreArrayRead(coordinates, &array)); 876 } 877 PetscCall(DMGetNumLabels(dm, &numLabels)); 878 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 879 for (l = 0; l < numLabels; ++l) { 880 DMLabel label; 881 PetscBool isdepth; 882 const char *name; 883 884 PetscCall(DMGetLabelName(dm, l, &name)); 885 PetscCall(PetscStrcmp(name, "depth", &isdepth)); 886 if (isdepth) continue; 887 PetscCall(DMGetLabel(dm, name, &label)); 888 PetscCall(DMLabelView(label, viewer)); 889 } 890 if (size > 1) { 891 PetscSF sf; 892 893 PetscCall(DMGetPointSF(dm, &sf)); 894 PetscCall(PetscSFView(sf, viewer)); 895 } 896 PetscCall(PetscViewerFlush(viewer)); 897 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 898 const char *name, *color; 899 const char *defcolors[3] = {"gray", "orange", "green"}; 900 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 901 char lname[PETSC_MAX_PATH_LEN]; 902 PetscReal scale = 2.0; 903 PetscReal tikzscale = 1.0; 904 PetscBool useNumbers = PETSC_TRUE, drawNumbers[4], drawColors[4], useLabels, useColors, plotEdges, drawHasse = PETSC_FALSE; 905 double tcoords[3]; 906 PetscScalar *coords; 907 PetscInt numLabels, l, numColors, numLColors, dim, d, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p, n; 908 PetscMPIInt rank, size; 909 char **names, **colors, **lcolors; 910 PetscBool flg, lflg; 911 PetscBT wp = NULL; 912 PetscInt pEnd, pStart; 913 914 PetscCall(DMGetDimension(dm, &dim)); 915 PetscCall(DMPlexGetDepth(dm, &depth)); 916 PetscCall(DMGetNumLabels(dm, &numLabels)); 917 numLabels = PetscMax(numLabels, 10); 918 numColors = 10; 919 numLColors = 10; 920 PetscCall(PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors)); 921 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL)); 922 PetscCall(PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL)); 923 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL)); 924 for (d = 0; d < 4; ++d) drawNumbers[d] = useNumbers; 925 for (d = 0; d < 4; ++d) drawColors[d] = PETSC_TRUE; 926 n = 4; 927 PetscCall(PetscOptionsGetBoolArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers_depth", drawNumbers, &n, &flg)); 928 PetscCheckFalse(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 PetscCheckFalse(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 PetscCheckFalse(flg && plotEdges && depth < dim,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 947 if (depth < dim) plotEdges = PETSC_FALSE; 948 PetscCall(PetscOptionsGetBool(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_hasse", &drawHasse, NULL)); 949 950 /* filter points with labelvalue != labeldefaultvalue */ 951 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 952 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 953 PetscCall(DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd)); 954 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 955 if (lflg) { 956 DMLabel lbl; 957 958 PetscCall(DMGetLabel(dm, lname, &lbl)); 959 if (lbl) { 960 PetscInt val, defval; 961 962 PetscCall(DMLabelGetDefaultValue(lbl, &defval)); 963 PetscCall(PetscBTCreate(pEnd-pStart, &wp)); 964 for (c = pStart; c < pEnd; c++) { 965 PetscInt *closure = NULL; 966 PetscInt closureSize; 967 968 PetscCall(DMLabelGetValue(lbl, c, &val)); 969 if (val == defval) continue; 970 971 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 972 for (p = 0; p < closureSize*2; p += 2) { 973 PetscCall(PetscBTSet(wp, closure[p] - pStart)); 974 } 975 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 976 } 977 } 978 } 979 980 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 981 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 982 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 983 PetscCall(PetscViewerASCIIPrintf(viewer, "\ 984 \\documentclass[tikz]{standalone}\n\n\ 985 \\usepackage{pgflibraryshapes}\n\ 986 \\usetikzlibrary{backgrounds}\n\ 987 \\usetikzlibrary{arrows}\n\ 988 \\begin{document}\n")); 989 if (size > 1) { 990 PetscCall(PetscViewerASCIIPrintf(viewer, "%s for process ", name)); 991 for (p = 0; p < size; ++p) { 992 if (p) PetscCall(PetscViewerASCIIPrintf(viewer, (p == size-1) ? ", and " : ", ")); 993 PetscCall(PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%" PetscInt_FMT "}", colors[p%numColors], p)); 994 } 995 PetscCall(PetscViewerASCIIPrintf(viewer, ".\n\n\n")); 996 } 997 if (drawHasse) { 998 PetscInt maxStratum = PetscMax(vEnd-vStart, PetscMax(eEnd-eStart, cEnd-cStart)); 999 1000 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vStart}{%" PetscInt_FMT "}\n", vStart)); 1001 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vEnd}{%" PetscInt_FMT "}\n", vEnd-1)); 1002 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numVertices}{%" PetscInt_FMT "}\n", vEnd-vStart)); 1003 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\vShift}{%.2f}\n", 3 + (maxStratum-(vEnd-vStart))/2.)); 1004 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eStart}{%" PetscInt_FMT "}\n", eStart)); 1005 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eEnd}{%" PetscInt_FMT "}\n", eEnd-1)); 1006 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\eShift}{%.2f}\n", 3 + (maxStratum-(eEnd-eStart))/2.)); 1007 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numEdges}{%" PetscInt_FMT "}\n", eEnd-eStart)); 1008 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cStart}{%" PetscInt_FMT "}\n", cStart)); 1009 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cEnd}{%" PetscInt_FMT "}\n", cEnd-1)); 1010 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\numCells}{%" PetscInt_FMT "}\n", cEnd-cStart)); 1011 PetscCall(PetscViewerASCIIPrintf(viewer, "\\newcommand{\\cShift}{%.2f}\n", 3 + (maxStratum-(cEnd-cStart))/2.)); 1012 } 1013 PetscCall(PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale)); 1014 1015 /* Plot vertices */ 1016 PetscCall(VecGetArray(coordinates, &coords)); 1017 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 1018 for (v = vStart; v < vEnd; ++v) { 1019 PetscInt off, dof, d; 1020 PetscBool isLabeled = PETSC_FALSE; 1021 1022 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 1023 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 1024 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 1025 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1026 PetscCheck(dof <= 3,PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %" PetscInt_FMT " has dof %" PetscInt_FMT " > 3",v,dof); 1027 for (d = 0; d < dof; ++d) { 1028 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1029 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1030 } 1031 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1032 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1033 for (d = 0; d < dof; ++d) { 1034 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1035 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d])); 1036 } 1037 if (drawHasse) color = colors[0%numColors]; 1038 else color = colors[rank%numColors]; 1039 for (l = 0; l < numLabels; ++l) { 1040 PetscInt val; 1041 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1042 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1043 } 1044 if (drawNumbers[0]) { 1045 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", v, rank, color, v)); 1046 } else if (drawColors[0]) { 1047 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color)); 1048 } else { 1049 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", v, rank)); 1050 } 1051 } 1052 PetscCall(VecRestoreArray(coordinates, &coords)); 1053 PetscCall(PetscViewerFlush(viewer)); 1054 /* Plot edges */ 1055 if (plotEdges) { 1056 PetscCall(VecGetArray(coordinates, &coords)); 1057 PetscCall(PetscViewerASCIIPrintf(viewer, "\\path\n")); 1058 for (e = eStart; e < eEnd; ++e) { 1059 const PetscInt *cone; 1060 PetscInt coneSize, offA, offB, dof, d; 1061 1062 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1063 PetscCall(DMPlexGetConeSize(dm, e, &coneSize)); 1064 PetscCheck(coneSize == 2,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " cone should have two vertices, not %" PetscInt_FMT, e, coneSize); 1065 PetscCall(DMPlexGetCone(dm, e, &cone)); 1066 PetscCall(PetscSectionGetDof(coordSection, cone[0], &dof)); 1067 PetscCall(PetscSectionGetOffset(coordSection, cone[0], &offA)); 1068 PetscCall(PetscSectionGetOffset(coordSection, cone[1], &offB)); 1069 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(")); 1070 for (d = 0; d < dof; ++d) { 1071 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 1072 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1073 } 1074 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1075 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1076 for (d = 0; d < dof; ++d) { 1077 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1078 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d])); 1079 } 1080 if (drawHasse) color = colors[1%numColors]; 1081 else color = colors[rank%numColors]; 1082 for (l = 0; l < numLabels; ++l) { 1083 PetscInt val; 1084 PetscCall(DMGetLabelValue(dm, names[l], v, &val)); 1085 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1086 } 1087 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "} --\n", e, rank, color, e)); 1088 } 1089 PetscCall(VecRestoreArray(coordinates, &coords)); 1090 PetscCall(PetscViewerFlush(viewer)); 1091 PetscCall(PetscViewerASCIIPrintf(viewer, "(0,0);\n")); 1092 } 1093 /* Plot cells */ 1094 if (dim == 3 || !drawNumbers[1]) { 1095 for (e = eStart; e < eEnd; ++e) { 1096 const PetscInt *cone; 1097 1098 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 1099 color = colors[rank%numColors]; 1100 for (l = 0; l < numLabels; ++l) { 1101 PetscInt val; 1102 PetscCall(DMGetLabelValue(dm, names[l], e, &val)); 1103 if (val >= 0) {color = lcolors[l%numLColors]; break;} 1104 } 1105 PetscCall(DMPlexGetCone(dm, e, &cone)); 1106 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", color, cone[0], rank, cone[1], rank)); 1107 } 1108 } else { 1109 DMPolytopeType ct; 1110 1111 /* Drawing a 2D polygon */ 1112 for (c = cStart; c < cEnd; ++c) { 1113 if (wp && !PetscBTLookup(wp, c - pStart)) continue; 1114 PetscCall(DMPlexGetCellType(dm, c, &ct)); 1115 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || 1116 ct == DM_POLYTOPE_TRI_PRISM_TENSOR || 1117 ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1118 const PetscInt *cone; 1119 PetscInt coneSize, e; 1120 1121 PetscCall(DMPlexGetCone(dm, c, &cone)); 1122 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 1123 for (e = 0; e < coneSize; ++e) { 1124 const PetscInt *econe; 1125 1126 PetscCall(DMPlexGetCone(dm, cone[e], &econe)); 1127 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", colors[rank%numColors], econe[0], rank, cone[e], rank, econe[1], rank)); 1128 } 1129 } else { 1130 PetscInt *closure = NULL; 1131 PetscInt closureSize, Nv = 0, v; 1132 1133 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1134 for (p = 0; p < closureSize*2; p += 2) { 1135 const PetscInt point = closure[p]; 1136 1137 if ((point >= vStart) && (point < vEnd)) closure[Nv++] = point; 1138 } 1139 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors])); 1140 for (v = 0; v <= Nv; ++v) { 1141 const PetscInt vertex = closure[v%Nv]; 1142 1143 if (v > 0) { 1144 if (plotEdges) { 1145 const PetscInt *edge; 1146 PetscInt endpoints[2], ne; 1147 1148 endpoints[0] = closure[v-1]; endpoints[1] = vertex; 1149 PetscCall(DMPlexGetJoin(dm, 2, endpoints, &ne, &edge)); 1150 PetscCheck(ne == 1,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find edge for vertices %" PetscInt_FMT ", %" PetscInt_FMT, endpoints[0], endpoints[1]); 1151 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- (%" PetscInt_FMT "_%d) -- ", edge[0], rank)); 1152 PetscCall(DMPlexRestoreJoin(dm, 2, endpoints, &ne, &edge)); 1153 } else { 1154 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " -- ")); 1155 } 1156 } 1157 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "(%" PetscInt_FMT "_%d)", vertex, rank)); 1158 } 1159 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ";\n")); 1160 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1161 } 1162 } 1163 } 1164 PetscCall(VecGetArray(coordinates, &coords)); 1165 for (c = cStart; c < cEnd; ++c) { 1166 double ccoords[3] = {0.0, 0.0, 0.0}; 1167 PetscBool isLabeled = PETSC_FALSE; 1168 PetscInt *closure = NULL; 1169 PetscInt closureSize, dof, d, n = 0; 1170 1171 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 1172 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1173 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\\path (")); 1174 for (p = 0; p < closureSize*2; p += 2) { 1175 const PetscInt point = closure[p]; 1176 PetscInt off; 1177 1178 if ((point < vStart) || (point >= vEnd)) continue; 1179 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 1180 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 1181 for (d = 0; d < dof; ++d) { 1182 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 1183 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 1184 } 1185 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 1186 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 1187 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 1188 ++n; 1189 } 1190 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 1191 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 1192 for (d = 0; d < dof; ++d) { 1193 if (d > 0) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ",")); 1194 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d])); 1195 } 1196 if (drawHasse) color = colors[depth%numColors]; 1197 else color = colors[rank%numColors]; 1198 for (l = 0; l < numLabels; ++l) { 1199 PetscInt val; 1200 PetscCall(DMGetLabelValue(dm, names[l], c, &val)); 1201 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 1202 } 1203 if (drawNumbers[dim]) { 1204 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [draw,shape=circle,color=%s] {%" PetscInt_FMT "};\n", c, rank, color, c)); 1205 } else if (drawColors[dim]) { 1206 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color)); 1207 } else { 1208 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, ") node(%" PetscInt_FMT "_%d) [] {};\n", c, rank)); 1209 } 1210 } 1211 PetscCall(VecRestoreArray(coordinates, &coords)); 1212 if (drawHasse) { 1213 color = colors[depth%numColors]; 1214 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Cells\n")); 1215 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\c in {\\cStart,...,\\cEnd}\n")); 1216 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1217 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\c_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\cShift+\\c-\\cStart,0) {\\c};\n", rank, color)); 1218 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1219 1220 color = colors[1%numColors]; 1221 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Edges\n")); 1222 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\e in {\\eStart,...,\\eEnd}\n")); 1223 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1224 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\e_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\eShift+\\e-\\eStart,1) {\\e};\n", rank, color)); 1225 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1226 1227 color = colors[0%numColors]; 1228 PetscCall(PetscViewerASCIIPrintf(viewer, "%% Vertices\n")); 1229 PetscCall(PetscViewerASCIIPrintf(viewer, "\\foreach \\v in {\\vStart,...,\\vEnd}\n")); 1230 PetscCall(PetscViewerASCIIPrintf(viewer, "{\n")); 1231 PetscCall(PetscViewerASCIIPrintf(viewer, " \\node(\\v_%d) [draw,shape=circle,color=%s,minimum size = 6mm] at (\\vShift+\\v-\\vStart,2) {\\v};\n", rank, color)); 1232 PetscCall(PetscViewerASCIIPrintf(viewer, "}\n")); 1233 1234 for (p = pStart; p < pEnd; ++p) { 1235 const PetscInt *cone; 1236 PetscInt coneSize, cp; 1237 1238 PetscCall(DMPlexGetCone(dm, p, &cone)); 1239 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1240 for (cp = 0; cp < coneSize; ++cp) { 1241 PetscCall(PetscViewerASCIIPrintf(viewer, "\\draw[->, shorten >=1pt] (%" PetscInt_FMT "_%d) -- (%" PetscInt_FMT "_%d);\n", cone[cp], rank, p, rank)); 1242 } 1243 } 1244 } 1245 PetscCall(PetscViewerFlush(viewer)); 1246 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 1247 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n")); 1248 PetscCall(PetscViewerASCIIPrintf(viewer, "\\end{document}\n")); 1249 for (l = 0; l < numLabels; ++l) PetscCall(PetscFree(names[l])); 1250 for (c = 0; c < numColors; ++c) PetscCall(PetscFree(colors[c])); 1251 for (c = 0; c < numLColors; ++c) PetscCall(PetscFree(lcolors[c])); 1252 PetscCall(PetscFree3(names, colors, lcolors)); 1253 PetscCall(PetscBTDestroy(&wp)); 1254 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 1255 Vec cown,acown; 1256 VecScatter sct; 1257 ISLocalToGlobalMapping g2l; 1258 IS gid,acis; 1259 MPI_Comm comm,ncomm = MPI_COMM_NULL; 1260 MPI_Group ggroup,ngroup; 1261 PetscScalar *array,nid; 1262 const PetscInt *idxs; 1263 PetscInt *idxs2,*start,*adjacency,*work; 1264 PetscInt64 lm[3],gm[3]; 1265 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 1266 PetscMPIInt d1,d2,rank; 1267 1268 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1269 PetscCallMPI(MPI_Comm_rank(comm,&rank)); 1270 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1271 PetscCallMPI(MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm)); 1272 #endif 1273 if (ncomm != MPI_COMM_NULL) { 1274 PetscCallMPI(MPI_Comm_group(comm,&ggroup)); 1275 PetscCallMPI(MPI_Comm_group(ncomm,&ngroup)); 1276 d1 = 0; 1277 PetscCallMPI(MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2)); 1278 nid = d2; 1279 PetscCallMPI(MPI_Group_free(&ggroup)); 1280 PetscCallMPI(MPI_Group_free(&ngroup)); 1281 PetscCallMPI(MPI_Comm_free(&ncomm)); 1282 } else nid = 0.0; 1283 1284 /* Get connectivity */ 1285 PetscCall(DMPlexGetVTKCellHeight(dm,&cellHeight)); 1286 PetscCall(DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid)); 1287 1288 /* filter overlapped local cells */ 1289 PetscCall(DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd)); 1290 PetscCall(ISGetIndices(gid,&idxs)); 1291 PetscCall(ISGetLocalSize(gid,&cum)); 1292 PetscCall(PetscMalloc1(cum,&idxs2)); 1293 for (c = cStart, cum = 0; c < cEnd; c++) { 1294 if (idxs[c-cStart] < 0) continue; 1295 idxs2[cum++] = idxs[c-cStart]; 1296 } 1297 PetscCall(ISRestoreIndices(gid,&idxs)); 1298 PetscCheck(numVertices == cum,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,numVertices,cum); 1299 PetscCall(ISDestroy(&gid)); 1300 PetscCall(ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid)); 1301 1302 /* support for node-aware cell locality */ 1303 PetscCall(ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis)); 1304 PetscCall(VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown)); 1305 PetscCall(VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown)); 1306 PetscCall(VecGetArray(cown,&array)); 1307 for (c = 0; c < numVertices; c++) array[c] = nid; 1308 PetscCall(VecRestoreArray(cown,&array)); 1309 PetscCall(VecScatterCreate(cown,acis,acown,NULL,&sct)); 1310 PetscCall(VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1311 PetscCall(VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD)); 1312 PetscCall(ISDestroy(&acis)); 1313 PetscCall(VecScatterDestroy(&sct)); 1314 PetscCall(VecDestroy(&cown)); 1315 1316 /* compute edgeCut */ 1317 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1318 PetscCall(PetscMalloc1(cum,&work)); 1319 PetscCall(ISLocalToGlobalMappingCreateIS(gid,&g2l)); 1320 PetscCall(ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH)); 1321 PetscCall(ISDestroy(&gid)); 1322 PetscCall(VecGetArray(acown,&array)); 1323 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1324 PetscInt totl; 1325 1326 totl = start[c+1]-start[c]; 1327 PetscCall(ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work)); 1328 for (i = 0; i < totl; i++) { 1329 if (work[i] < 0) { 1330 ect += 1; 1331 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1332 } 1333 } 1334 } 1335 PetscCall(PetscFree(work)); 1336 PetscCall(VecRestoreArray(acown,&array)); 1337 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1338 lm[1] = -numVertices; 1339 PetscCall(MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm)); 1340 PetscCall(PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %" PetscInt_FMT ", min %" PetscInt_FMT,-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0])); 1341 lm[0] = ect; /* edgeCut */ 1342 lm[1] = ectn; /* node-aware edgeCut */ 1343 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1344 PetscCall(MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm)); 1345 PetscCall(PetscViewerASCIIPrintf(viewer,", empty %" PetscInt_FMT ")\n",(PetscInt)gm[2])); 1346 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1347 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.)); 1348 #else 1349 PetscCall(PetscViewerASCIIPrintf(viewer," Edge Cut: %" PetscInt_FMT " (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0)); 1350 #endif 1351 PetscCall(ISLocalToGlobalMappingDestroy(&g2l)); 1352 PetscCall(PetscFree(start)); 1353 PetscCall(PetscFree(adjacency)); 1354 PetscCall(VecDestroy(&acown)); 1355 } else { 1356 const char *name; 1357 PetscInt *sizes, *hybsizes, *ghostsizes; 1358 PetscInt locDepth, depth, cellHeight, dim, d; 1359 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1360 PetscInt numLabels, l, maxSize = 17; 1361 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1362 MPI_Comm comm; 1363 PetscMPIInt size, rank; 1364 1365 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 1366 PetscCallMPI(MPI_Comm_size(comm, &size)); 1367 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1368 PetscCall(DMGetDimension(dm, &dim)); 1369 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1370 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1371 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "%s in %" PetscInt_FMT " dimension%s:\n", name, dim, dim == 1 ? "" : "s")); 1372 else PetscCall(PetscViewerASCIIPrintf(viewer, "Mesh in %" PetscInt_FMT " dimension%s:\n", dim, dim == 1 ? "" : "s")); 1373 if (cellHeight) PetscCall(PetscViewerASCIIPrintf(viewer, " Cells are at height %" PetscInt_FMT "\n", cellHeight)); 1374 PetscCall(DMPlexGetDepth(dm, &locDepth)); 1375 PetscCall(MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm)); 1376 PetscCall(DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd)); 1377 gcNum = gcEnd - gcStart; 1378 if (size < maxSize) PetscCall(PetscCalloc3(size, &sizes, size, &hybsizes, size, &ghostsizes)); 1379 else PetscCall(PetscCalloc3(3, &sizes, 3, &hybsizes, 3, &ghostsizes)); 1380 for (d = 0; d <= depth; d++) { 1381 PetscInt Nc[2] = {0, 0}, ict; 1382 1383 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 1384 if (pStart < pEnd) PetscCall(DMPlexGetCellType(dm, pStart, &ct0)); 1385 ict = ct0; 1386 PetscCallMPI(MPI_Bcast(&ict, 1, MPIU_INT, 0, comm)); 1387 ct0 = (DMPolytopeType) ict; 1388 for (p = pStart; p < pEnd; ++p) { 1389 DMPolytopeType ct; 1390 1391 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1392 if (ct == ct0) ++Nc[0]; 1393 else ++Nc[1]; 1394 } 1395 if (size < maxSize) { 1396 PetscCallMPI(MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm)); 1397 PetscCallMPI(MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm)); 1398 if (d == depth) PetscCallMPI(MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm)); 1399 PetscCall(PetscViewerASCIIPrintf(viewer, " Number of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1400 for (p = 0; p < size; ++p) { 1401 if (rank == 0) { 1402 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, sizes[p]+hybsizes[p])); 1403 if (hybsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT ")", hybsizes[p])); 1404 if (ghostsizes[p] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "]", ghostsizes[p])); 1405 } 1406 } 1407 } else { 1408 PetscInt locMinMax[2]; 1409 1410 locMinMax[0] = Nc[0]+Nc[1]; locMinMax[1] = Nc[0]+Nc[1]; 1411 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, sizes)); 1412 locMinMax[0] = Nc[1]; locMinMax[1] = Nc[1]; 1413 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, hybsizes)); 1414 if (d == depth) { 1415 locMinMax[0] = gcNum; locMinMax[1] = gcNum; 1416 PetscCall(PetscGlobalMinMaxInt(comm, locMinMax, ghostsizes)); 1417 } 1418 PetscCall(PetscViewerASCIIPrintf(viewer, " Min/Max of %" PetscInt_FMT "-cells per rank:", (depth == 1) && d ? dim : d)); 1419 PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "/%" PetscInt_FMT, sizes[0], sizes[1])); 1420 if (hybsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " (%" PetscInt_FMT "/%" PetscInt_FMT ")", hybsizes[0], hybsizes[1])); 1421 if (ghostsizes[0] > 0) PetscCall(PetscViewerASCIIPrintf(viewer, " [%" PetscInt_FMT "/%" PetscInt_FMT "]", ghostsizes[0], ghostsizes[1])); 1422 } 1423 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 1424 } 1425 PetscCall(PetscFree3(sizes, hybsizes, ghostsizes)); 1426 { 1427 const PetscReal *maxCell; 1428 const PetscReal *L; 1429 const DMBoundaryType *bd; 1430 PetscBool per, localized; 1431 1432 PetscCall(DMGetPeriodicity(dm, &per, &maxCell, &L, &bd)); 1433 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 1434 if (per) { 1435 PetscCall(PetscViewerASCIIPrintf(viewer, "Periodic mesh (")); 1436 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1437 for (d = 0; d < dim; ++d) { 1438 if (bd && d > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1439 if (bd) PetscCall(PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]])); 1440 } 1441 PetscCall(PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized")); 1442 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1443 } 1444 } 1445 PetscCall(DMGetNumLabels(dm, &numLabels)); 1446 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Labels:\n")); 1447 for (l = 0; l < numLabels; ++l) { 1448 DMLabel label; 1449 const char *name; 1450 IS valueIS; 1451 const PetscInt *values; 1452 PetscInt numValues, v; 1453 1454 PetscCall(DMGetLabelName(dm, l, &name)); 1455 PetscCall(DMGetLabel(dm, name, &label)); 1456 PetscCall(DMLabelGetNumValues(label, &numValues)); 1457 PetscCall(PetscViewerASCIIPrintf(viewer, " %s: %" PetscInt_FMT " strata with value/size (", name, numValues)); 1458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1459 PetscCall(ISGetIndices(valueIS, &values)); 1460 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE)); 1461 for (v = 0; v < numValues; ++v) { 1462 PetscInt size; 1463 1464 PetscCall(DMLabelGetStratumSize(label, values[v], &size)); 1465 if (v > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 1466 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " (%" PetscInt_FMT ")", values[v], size)); 1467 } 1468 PetscCall(PetscViewerASCIIPrintf(viewer, ")\n")); 1469 PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE)); 1470 PetscCall(ISRestoreIndices(valueIS, &values)); 1471 PetscCall(ISDestroy(&valueIS)); 1472 } 1473 { 1474 char **labelNames; 1475 PetscInt Nl = numLabels; 1476 PetscBool flg; 1477 1478 PetscCall(PetscMalloc1(Nl, &labelNames)); 1479 PetscCall(PetscOptionsGetStringArray(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_plex_view_labels", labelNames, &Nl, &flg)); 1480 for (l = 0; l < Nl; ++l) { 1481 DMLabel label; 1482 1483 PetscCall(DMHasLabel(dm, labelNames[l], &flg)); 1484 if (flg) { 1485 PetscCall(DMGetLabel(dm, labelNames[l], &label)); 1486 PetscCall(DMLabelView(label, viewer)); 1487 } 1488 PetscCall(PetscFree(labelNames[l])); 1489 } 1490 PetscCall(PetscFree(labelNames)); 1491 } 1492 /* If no fields are specified, people do not want to see adjacency */ 1493 if (dm->Nf) { 1494 PetscInt f; 1495 1496 for (f = 0; f < dm->Nf; ++f) { 1497 const char *name; 1498 1499 PetscCall(PetscObjectGetName(dm->fields[f].disc, &name)); 1500 if (numLabels) PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s:\n", name)); 1501 PetscCall(PetscViewerASCIIPushTab(viewer)); 1502 if (dm->fields[f].label) PetscCall(DMLabelView(dm->fields[f].label, viewer)); 1503 if (dm->fields[f].adjacency[0]) { 1504 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n")); 1505 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FVM\n")); 1506 } else { 1507 if (dm->fields[f].adjacency[1]) PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FEM\n")); 1508 else PetscCall(PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n")); 1509 } 1510 PetscCall(PetscViewerASCIIPopTab(viewer)); 1511 } 1512 } 1513 PetscCall(DMGetCoarseDM(dm, &cdm)); 1514 if (cdm) { 1515 PetscCall(PetscViewerASCIIPushTab(viewer)); 1516 PetscCall(DMPlexView_Ascii(cdm, viewer)); 1517 PetscCall(PetscViewerASCIIPopTab(viewer)); 1518 } 1519 } 1520 PetscFunctionReturn(0); 1521 } 1522 1523 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1524 { 1525 DMPolytopeType ct; 1526 PetscMPIInt rank; 1527 PetscInt cdim; 1528 1529 PetscFunctionBegin; 1530 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1531 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1532 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1533 switch (ct) { 1534 case DM_POLYTOPE_SEGMENT: 1535 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1536 switch (cdim) { 1537 case 1: 1538 { 1539 const PetscReal y = 0.5; /* TODO Put it in the middle of the viewport */ 1540 const PetscReal dy = 0.05; /* TODO Make it a fraction of the total length */ 1541 1542 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y, PetscRealPart(coords[1]), y, PETSC_DRAW_BLACK)); 1543 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), y+dy, PetscRealPart(coords[0]), y-dy, PETSC_DRAW_BLACK)); 1544 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[1]), y+dy, PetscRealPart(coords[1]), y-dy, PETSC_DRAW_BLACK)); 1545 } 1546 break; 1547 case 2: 1548 { 1549 const PetscReal dx = (PetscRealPart(coords[3]) - PetscRealPart(coords[1])); 1550 const PetscReal dy = (PetscRealPart(coords[2]) - PetscRealPart(coords[0])); 1551 const PetscReal l = 0.1/PetscSqrtReal(dx*dx + dy*dy); 1552 1553 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1554 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0])+l*dx, PetscRealPart(coords[1])+l*dy, PetscRealPart(coords[0])-l*dx, PetscRealPart(coords[1])-l*dy, PETSC_DRAW_BLACK)); 1555 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2])+l*dx, PetscRealPart(coords[3])+l*dy, PetscRealPart(coords[2])-l*dx, PetscRealPart(coords[3])-l*dy, PETSC_DRAW_BLACK)); 1556 } 1557 break; 1558 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of dimension %" PetscInt_FMT, cdim); 1559 } 1560 break; 1561 case DM_POLYTOPE_TRIANGLE: 1562 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1563 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1564 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1565 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1566 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1567 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1568 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1569 break; 1570 case DM_POLYTOPE_QUADRILATERAL: 1571 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1572 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1573 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1574 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1575 PetscCall(PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1576 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1577 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1578 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2)); 1579 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK)); 1580 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK)); 1581 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK)); 1582 PetscCall(PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK)); 1583 break; 1584 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1585 } 1586 PetscFunctionReturn(0); 1587 } 1588 1589 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1590 { 1591 DMPolytopeType ct; 1592 PetscReal centroid[2] = {0., 0.}; 1593 PetscMPIInt rank; 1594 PetscInt fillColor, v, e, d; 1595 1596 PetscFunctionBegin; 1597 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 1598 PetscCall(DMPlexGetCellType(dm, cell, &ct)); 1599 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1600 switch (ct) { 1601 case DM_POLYTOPE_TRIANGLE: 1602 { 1603 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1604 1605 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1606 for (e = 0; e < 3; ++e) { 1607 refCoords[0] = refVertices[e*2+0]; 1608 refCoords[1] = refVertices[e*2+1]; 1609 for (d = 1; d <= edgeDiv; ++d) { 1610 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1611 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1612 } 1613 PetscCall(DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords)); 1614 for (d = 0; d < edgeDiv; ++d) { 1615 PetscCall(PetscDrawTriangle(draw, centroid[0], centroid[1], edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], fillColor, fillColor, fillColor)); 1616 PetscCall(PetscDrawLine(draw, edgeCoords[d*2+0], edgeCoords[d*2+1], edgeCoords[(d+1)*2+0], edgeCoords[(d+1)*2+1], PETSC_DRAW_BLACK)); 1617 } 1618 } 1619 } 1620 break; 1621 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1622 } 1623 PetscFunctionReturn(0); 1624 } 1625 1626 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1627 { 1628 PetscDraw draw; 1629 DM cdm; 1630 PetscSection coordSection; 1631 Vec coordinates; 1632 const PetscScalar *coords; 1633 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1634 PetscReal *refCoords, *edgeCoords; 1635 PetscBool isnull, drawAffine = PETSC_TRUE; 1636 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1637 1638 PetscFunctionBegin; 1639 PetscCall(DMGetCoordinateDim(dm, &dim)); 1640 PetscCheck(dim <= 2,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %" PetscInt_FMT, dim); 1641 PetscCall(PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL)); 1642 if (!drawAffine) PetscCall(PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords)); 1643 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1644 PetscCall(DMGetLocalSection(cdm, &coordSection)); 1645 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1646 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1647 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1648 1649 PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw)); 1650 PetscCall(PetscDrawIsNull(draw, &isnull)); 1651 if (isnull) PetscFunctionReturn(0); 1652 PetscCall(PetscDrawSetTitle(draw, "Mesh")); 1653 1654 PetscCall(VecGetLocalSize(coordinates, &N)); 1655 PetscCall(VecGetArrayRead(coordinates, &coords)); 1656 for (c = 0; c < N; c += dim) { 1657 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1658 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1659 } 1660 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1661 PetscCall(MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm))); 1662 PetscCall(MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm))); 1663 PetscCall(PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1])); 1664 PetscCall(PetscDrawClear(draw)); 1665 1666 for (c = cStart; c < cEnd; ++c) { 1667 PetscScalar *coords = NULL; 1668 PetscInt numCoords; 1669 1670 PetscCall(DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords)); 1671 if (drawAffine) { 1672 PetscCall(DMPlexDrawCell(dm, draw, c, coords)); 1673 } else { 1674 PetscCall(DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords)); 1675 } 1676 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords)); 1677 } 1678 if (!drawAffine) PetscCall(PetscFree2(refCoords, edgeCoords)); 1679 PetscCall(PetscDrawFlush(draw)); 1680 PetscCall(PetscDrawPause(draw)); 1681 PetscCall(PetscDrawSave(draw)); 1682 PetscFunctionReturn(0); 1683 } 1684 1685 #if defined(PETSC_HAVE_EXODUSII) 1686 #include <exodusII.h> 1687 #include <petscviewerexodusii.h> 1688 #endif 1689 1690 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1691 { 1692 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1693 char name[PETSC_MAX_PATH_LEN]; 1694 1695 PetscFunctionBegin; 1696 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1697 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1698 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii)); 1699 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1700 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1701 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw)); 1702 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1703 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus)); 1704 if (iascii) { 1705 PetscViewerFormat format; 1706 PetscCall(PetscViewerGetFormat(viewer, &format)); 1707 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1708 PetscCall(DMPlexView_GLVis(dm, viewer)); 1709 } else { 1710 PetscCall(DMPlexView_Ascii(dm, viewer)); 1711 } 1712 } else if (ishdf5) { 1713 #if defined(PETSC_HAVE_HDF5) 1714 PetscCall(DMPlexView_HDF5_Internal(dm, viewer)); 1715 #else 1716 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1717 #endif 1718 } else if (isvtk) { 1719 PetscCall(DMPlexVTKWriteAll((PetscObject) dm,viewer)); 1720 } else if (isdraw) { 1721 PetscCall(DMPlexView_Draw(dm, viewer)); 1722 } else if (isglvis) { 1723 PetscCall(DMPlexView_GLVis(dm, viewer)); 1724 #if defined(PETSC_HAVE_EXODUSII) 1725 } else if (isexodus) { 1726 /* 1727 exodusII requires that all sets be part of exactly one cell set. 1728 If the dm does not have a "Cell Sets" label defined, we create one 1729 with ID 1, containig all cells. 1730 Note that if the Cell Sets label is defined but does not cover all cells, 1731 we may still have a problem. This should probably be checked here or in the viewer; 1732 */ 1733 PetscInt numCS; 1734 PetscCall(DMGetLabelSize(dm,"Cell Sets",&numCS)); 1735 if (!numCS) { 1736 PetscInt cStart, cEnd, c; 1737 PetscCall(DMCreateLabel(dm, "Cell Sets")); 1738 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1739 for (c = cStart; c < cEnd; ++c) PetscCall(DMSetLabelValue(dm, "Cell Sets", c, 1)); 1740 } 1741 PetscCall(DMView_PlexExodusII(dm, viewer)); 1742 #endif 1743 } else { 1744 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1745 } 1746 /* Optionally view the partition */ 1747 PetscCall(PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg)); 1748 if (flg) { 1749 Vec ranks; 1750 PetscCall(DMPlexCreateRankField(dm, &ranks)); 1751 PetscCall(VecView(ranks, viewer)); 1752 PetscCall(VecDestroy(&ranks)); 1753 } 1754 /* Optionally view a label */ 1755 PetscCall(PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg)); 1756 if (flg) { 1757 DMLabel label; 1758 Vec val; 1759 1760 PetscCall(DMGetLabel(dm, name, &label)); 1761 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1762 PetscCall(DMPlexCreateLabelField(dm, label, &val)); 1763 PetscCall(VecView(val, viewer)); 1764 PetscCall(VecDestroy(&val)); 1765 } 1766 PetscFunctionReturn(0); 1767 } 1768 1769 /*@ 1770 DMPlexTopologyView - Saves a DMPlex topology into a file 1771 1772 Collective on DM 1773 1774 Input Parameters: 1775 + dm - The DM whose topology is to be saved 1776 - viewer - The PetscViewer for saving 1777 1778 Level: advanced 1779 1780 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad() 1781 @*/ 1782 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1783 { 1784 PetscBool ishdf5; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1790 PetscCall(PetscLogEventBegin(DMPLEX_TopologyView,viewer,0,0,0)); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 IS globalPointNumbering; 1797 1798 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1799 PetscCall(DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1800 PetscCall(ISDestroy(&globalPointNumbering)); 1801 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1802 #else 1803 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1804 #endif 1805 } 1806 PetscCall(PetscLogEventEnd(DMPLEX_TopologyView,viewer,0,0,0)); 1807 PetscFunctionReturn(0); 1808 } 1809 1810 /*@ 1811 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1812 1813 Collective on DM 1814 1815 Input Parameters: 1816 + dm - The DM whose coordinates are to be saved 1817 - viewer - The PetscViewer for saving 1818 1819 Level: advanced 1820 1821 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad() 1822 @*/ 1823 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1824 { 1825 PetscBool ishdf5; 1826 1827 PetscFunctionBegin; 1828 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1829 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1830 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1831 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesView,viewer,0,0,0)); 1832 if (ishdf5) { 1833 #if defined(PETSC_HAVE_HDF5) 1834 PetscViewerFormat format; 1835 PetscCall(PetscViewerGetFormat(viewer, &format)); 1836 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1837 PetscCall(DMPlexCoordinatesView_HDF5_Internal(dm, viewer)); 1838 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1839 #else 1840 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1841 #endif 1842 } 1843 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesView,viewer,0,0,0)); 1844 PetscFunctionReturn(0); 1845 } 1846 1847 /*@ 1848 DMPlexLabelsView - Saves DMPlex labels into a file 1849 1850 Collective on DM 1851 1852 Input Parameters: 1853 + dm - The DM whose labels are to be saved 1854 - viewer - The PetscViewer for saving 1855 1856 Level: advanced 1857 1858 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad() 1859 @*/ 1860 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1861 { 1862 PetscBool ishdf5; 1863 1864 PetscFunctionBegin; 1865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1866 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1867 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1868 PetscCall(PetscLogEventBegin(DMPLEX_LabelsView,viewer,0,0,0)); 1869 if (ishdf5) { 1870 #if defined(PETSC_HAVE_HDF5) 1871 IS globalPointNumbering; 1872 PetscViewerFormat format; 1873 1874 PetscCall(PetscViewerGetFormat(viewer, &format)); 1875 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1876 PetscCall(DMPlexCreatePointNumbering(dm, &globalPointNumbering)); 1877 PetscCall(DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer)); 1878 PetscCall(ISDestroy(&globalPointNumbering)); 1879 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1880 #else 1881 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1882 #endif 1883 } 1884 PetscCall(PetscLogEventEnd(DMPLEX_LabelsView,viewer,0,0,0)); 1885 PetscFunctionReturn(0); 1886 } 1887 1888 /*@ 1889 DMPlexSectionView - Saves a section associated with a DMPlex 1890 1891 Collective on DM 1892 1893 Input Parameters: 1894 + dm - The DM that contains the topology on which the section to be saved is defined 1895 . viewer - The PetscViewer for saving 1896 - sectiondm - The DM that contains the section to be saved 1897 1898 Level: advanced 1899 1900 Notes: 1901 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1902 1903 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1904 1905 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad() 1906 @*/ 1907 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1908 { 1909 PetscBool ishdf5; 1910 1911 PetscFunctionBegin; 1912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1913 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1914 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1915 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 1916 PetscCall(PetscLogEventBegin(DMPLEX_SectionView,viewer,0,0,0)); 1917 if (ishdf5) { 1918 #if defined(PETSC_HAVE_HDF5) 1919 PetscCall(DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm)); 1920 #else 1921 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1922 #endif 1923 } 1924 PetscCall(PetscLogEventEnd(DMPLEX_SectionView,viewer,0,0,0)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@ 1929 DMPlexGlobalVectorView - Saves a global vector 1930 1931 Collective on DM 1932 1933 Input Parameters: 1934 + dm - The DM that represents the topology 1935 . viewer - The PetscViewer to save data with 1936 . sectiondm - The DM that contains the global section on which vec is defined 1937 - vec - The global vector to be saved 1938 1939 Level: advanced 1940 1941 Notes: 1942 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1943 1944 Typical calling sequence 1945 $ DMCreate(PETSC_COMM_WORLD, &dm); 1946 $ DMSetType(dm, DMPLEX); 1947 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1948 $ DMClone(dm, §iondm); 1949 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1950 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1951 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1952 $ PetscSectionSetChart(section, pStart, pEnd); 1953 $ PetscSectionSetUp(section); 1954 $ DMSetLocalSection(sectiondm, section); 1955 $ PetscSectionDestroy(§ion); 1956 $ DMGetGlobalVector(sectiondm, &vec); 1957 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1958 $ DMPlexTopologyView(dm, viewer); 1959 $ DMPlexSectionView(dm, viewer, sectiondm); 1960 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1961 $ DMRestoreGlobalVector(sectiondm, &vec); 1962 $ DMDestroy(§iondm); 1963 $ DMDestroy(&dm); 1964 1965 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 1966 @*/ 1967 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1968 { 1969 PetscBool ishdf5; 1970 1971 PetscFunctionBegin; 1972 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1973 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1974 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1975 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1976 /* Check consistency */ 1977 { 1978 PetscSection section; 1979 PetscBool includesConstraints; 1980 PetscInt m, m1; 1981 1982 PetscCall(VecGetLocalSize(vec, &m1)); 1983 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 1984 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 1985 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 1986 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 1987 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 1988 } 1989 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 1990 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1991 if (ishdf5) { 1992 #if defined(PETSC_HAVE_HDF5) 1993 PetscCall(DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 1994 #else 1995 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1996 #endif 1997 } 1998 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorView,viewer,0,0,0)); 1999 PetscFunctionReturn(0); 2000 } 2001 2002 /*@ 2003 DMPlexLocalVectorView - Saves a local vector 2004 2005 Collective on DM 2006 2007 Input Parameters: 2008 + dm - The DM that represents the topology 2009 . viewer - The PetscViewer to save data with 2010 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 2011 - vec - The local vector to be saved 2012 2013 Level: advanced 2014 2015 Notes: 2016 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2017 2018 Typical calling sequence 2019 $ DMCreate(PETSC_COMM_WORLD, &dm); 2020 $ DMSetType(dm, DMPLEX); 2021 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2022 $ DMClone(dm, §iondm); 2023 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2024 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 2025 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 2026 $ PetscSectionSetChart(section, pStart, pEnd); 2027 $ PetscSectionSetUp(section); 2028 $ DMSetLocalSection(sectiondm, section); 2029 $ DMGetLocalVector(sectiondm, &vec); 2030 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2031 $ DMPlexTopologyView(dm, viewer); 2032 $ DMPlexSectionView(dm, viewer, sectiondm); 2033 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 2034 $ DMRestoreLocalVector(sectiondm, &vec); 2035 $ DMDestroy(§iondm); 2036 $ DMDestroy(&dm); 2037 2038 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 2039 @*/ 2040 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 2041 { 2042 PetscBool ishdf5; 2043 2044 PetscFunctionBegin; 2045 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2046 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2047 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2048 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 2049 /* Check consistency */ 2050 { 2051 PetscSection section; 2052 PetscBool includesConstraints; 2053 PetscInt m, m1; 2054 2055 PetscCall(VecGetLocalSize(vec, &m1)); 2056 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2057 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2058 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2059 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2060 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2061 } 2062 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2063 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorView,viewer,0,0,0)); 2064 if (ishdf5) { 2065 #if defined(PETSC_HAVE_HDF5) 2066 PetscCall(DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec)); 2067 #else 2068 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2069 #endif 2070 } 2071 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorView,viewer,0,0,0)); 2072 PetscFunctionReturn(0); 2073 } 2074 2075 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 2076 { 2077 PetscBool ishdf5; 2078 2079 PetscFunctionBegin; 2080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2081 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2082 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2083 if (ishdf5) { 2084 #if defined(PETSC_HAVE_HDF5) 2085 PetscViewerFormat format; 2086 PetscCall(PetscViewerGetFormat(viewer, &format)); 2087 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 2088 PetscCall(DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer)); 2089 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2090 PetscCall(DMPlexLoad_HDF5_Internal(dm, viewer)); 2091 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2092 PetscFunctionReturn(0); 2093 #else 2094 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2095 #endif 2096 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 2097 } 2098 2099 /*@ 2100 DMPlexTopologyLoad - Loads a topology into a DMPlex 2101 2102 Collective on DM 2103 2104 Input Parameters: 2105 + dm - The DM into which the topology is loaded 2106 - viewer - The PetscViewer for the saved topology 2107 2108 Output Parameters: 2109 . globalToLocalPointSF - The PetscSF that pushes points in [0, N) to the associated points in the loaded plex, where N is the global number of points; NULL if unneeded 2110 2111 Level: advanced 2112 2113 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2114 @*/ 2115 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 2116 { 2117 PetscBool ishdf5; 2118 2119 PetscFunctionBegin; 2120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2121 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2122 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 2123 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2124 PetscCall(PetscLogEventBegin(DMPLEX_TopologyLoad,viewer,0,0,0)); 2125 if (ishdf5) { 2126 #if defined(PETSC_HAVE_HDF5) 2127 PetscViewerFormat format; 2128 PetscCall(PetscViewerGetFormat(viewer, &format)); 2129 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2130 PetscCall(DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2131 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2132 #else 2133 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2134 #endif 2135 } 2136 PetscCall(PetscLogEventEnd(DMPLEX_TopologyLoad,viewer,0,0,0)); 2137 PetscFunctionReturn(0); 2138 } 2139 2140 /*@ 2141 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 2142 2143 Collective on DM 2144 2145 Input Parameters: 2146 + dm - The DM into which the coordinates are loaded 2147 . viewer - The PetscViewer for the saved coordinates 2148 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2149 2150 Level: advanced 2151 2152 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2153 @*/ 2154 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2155 { 2156 PetscBool ishdf5; 2157 2158 PetscFunctionBegin; 2159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2160 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2161 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2162 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2163 PetscCall(PetscLogEventBegin(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2164 if (ishdf5) { 2165 #if defined(PETSC_HAVE_HDF5) 2166 PetscViewerFormat format; 2167 PetscCall(PetscViewerGetFormat(viewer, &format)); 2168 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2169 PetscCall(DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2170 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2171 #else 2172 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2173 #endif 2174 } 2175 PetscCall(PetscLogEventEnd(DMPLEX_CoordinatesLoad,viewer,0,0,0)); 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 DMPlexLabelsLoad - Loads labels into a DMPlex 2181 2182 Collective on DM 2183 2184 Input Parameters: 2185 + dm - The DM into which the labels are loaded 2186 . viewer - The PetscViewer for the saved labels 2187 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2188 2189 Level: advanced 2190 2191 Notes: 2192 The PetscSF argument must not be NULL if the DM is distributed, otherwise an error occurs. 2193 2194 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 2195 @*/ 2196 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer, PetscSF globalToLocalPointSF) 2197 { 2198 PetscBool ishdf5; 2199 2200 PetscFunctionBegin; 2201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2202 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2203 if (globalToLocalPointSF) PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 3); 2204 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 2205 PetscCall(PetscLogEventBegin(DMPLEX_LabelsLoad,viewer,0,0,0)); 2206 if (ishdf5) { 2207 #if defined(PETSC_HAVE_HDF5) 2208 PetscViewerFormat format; 2209 2210 PetscCall(PetscViewerGetFormat(viewer, &format)); 2211 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 2212 PetscCall(DMPlexLabelsLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF)); 2213 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 2214 #else 2215 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2216 #endif 2217 } 2218 PetscCall(PetscLogEventEnd(DMPLEX_LabelsLoad,viewer,0,0,0)); 2219 PetscFunctionReturn(0); 2220 } 2221 2222 /*@ 2223 DMPlexSectionLoad - Loads section into a DMPlex 2224 2225 Collective on DM 2226 2227 Input Parameters: 2228 + dm - The DM that represents the topology 2229 . viewer - The PetscViewer that represents the on-disk section (sectionA) 2230 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 2231 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 2232 2233 Output Parameters 2234 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 2235 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 2236 2237 Level: advanced 2238 2239 Notes: 2240 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 2241 2242 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2243 2244 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 2245 2246 Example using 2 processes: 2247 $ NX (number of points on dm): 4 2248 $ sectionA : the on-disk section 2249 $ vecA : a vector associated with sectionA 2250 $ sectionB : sectiondm's local section constructed in this function 2251 $ vecB (local) : a vector associated with sectiondm's local section 2252 $ vecB (global) : a vector associated with sectiondm's global section 2253 $ 2254 $ rank 0 rank 1 2255 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 2256 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 2257 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 2258 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 2259 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 2260 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 2261 $ sectionB->atlasDof : 1 0 1 | 1 3 2262 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 2263 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 2264 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 2265 $ 2266 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 2267 2268 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView() 2269 @*/ 2270 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 2271 { 2272 PetscBool ishdf5; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2276 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2277 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2278 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 2279 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 2280 if (localDofSF) PetscValidPointer(localDofSF, 6); 2281 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2282 PetscCall(PetscLogEventBegin(DMPLEX_SectionLoad,viewer,0,0,0)); 2283 if (ishdf5) { 2284 #if defined(PETSC_HAVE_HDF5) 2285 PetscCall(DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF)); 2286 #else 2287 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2288 #endif 2289 } 2290 PetscCall(PetscLogEventEnd(DMPLEX_SectionLoad,viewer,0,0,0)); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 DMPlexGlobalVectorLoad - Loads on-disk vector data into a global vector 2296 2297 Collective on DM 2298 2299 Input Parameters: 2300 + dm - The DM that represents the topology 2301 . viewer - The PetscViewer that represents the on-disk vector data 2302 . sectiondm - The DM that contains the global section on which vec is defined 2303 . sf - The SF that migrates the on-disk vector data into vec 2304 - vec - The global vector to set values of 2305 2306 Level: advanced 2307 2308 Notes: 2309 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2310 2311 Typical calling sequence 2312 $ DMCreate(PETSC_COMM_WORLD, &dm); 2313 $ DMSetType(dm, DMPLEX); 2314 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2315 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2316 $ DMClone(dm, §iondm); 2317 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2318 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, &gsf, NULL); 2319 $ DMGetGlobalVector(sectiondm, &vec); 2320 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2321 $ DMPlexGlobalVectorLoad(dm, viewer, sectiondm, gsf, vec); 2322 $ DMRestoreGlobalVector(sectiondm, &vec); 2323 $ PetscSFDestroy(&gsf); 2324 $ PetscSFDestroy(&sfX); 2325 $ DMDestroy(§iondm); 2326 $ DMDestroy(&dm); 2327 2328 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexLocalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView() 2329 @*/ 2330 PetscErrorCode DMPlexGlobalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2331 { 2332 PetscBool ishdf5; 2333 2334 PetscFunctionBegin; 2335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2336 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2337 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2338 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2339 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2340 /* Check consistency */ 2341 { 2342 PetscSection section; 2343 PetscBool includesConstraints; 2344 PetscInt m, m1; 2345 2346 PetscCall(VecGetLocalSize(vec, &m1)); 2347 PetscCall(DMGetGlobalSection(sectiondm, §ion)); 2348 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2349 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2350 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2351 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%" PetscInt_FMT ") != global section storage size (%" PetscInt_FMT ")", m1, m); 2352 } 2353 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2354 PetscCall(PetscLogEventBegin(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2355 if (ishdf5) { 2356 #if defined(PETSC_HAVE_HDF5) 2357 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2358 #else 2359 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2360 #endif 2361 } 2362 PetscCall(PetscLogEventEnd(DMPLEX_GlobalVectorLoad,viewer,0,0,0)); 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMPlexLocalVectorLoad - Loads on-disk vector data into a local vector 2368 2369 Collective on DM 2370 2371 Input Parameters: 2372 + dm - The DM that represents the topology 2373 . viewer - The PetscViewer that represents the on-disk vector data 2374 . sectiondm - The DM that contains the local section on which vec is defined 2375 . sf - The SF that migrates the on-disk vector data into vec 2376 - vec - The local vector to set values of 2377 2378 Level: advanced 2379 2380 Notes: 2381 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 2382 2383 Typical calling sequence 2384 $ DMCreate(PETSC_COMM_WORLD, &dm); 2385 $ DMSetType(dm, DMPLEX); 2386 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 2387 $ DMPlexTopologyLoad(dm, viewer, &sfX); 2388 $ DMClone(dm, §iondm); 2389 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 2390 $ DMPlexSectionLoad(dm, viewer, sectiondm, sfX, NULL, &lsf); 2391 $ DMGetLocalVector(sectiondm, &vec); 2392 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 2393 $ DMPlexLocalVectorLoad(dm, viewer, sectiondm, lsf, vec); 2394 $ DMRestoreLocalVector(sectiondm, &vec); 2395 $ PetscSFDestroy(&lsf); 2396 $ PetscSFDestroy(&sfX); 2397 $ DMDestroy(§iondm); 2398 $ DMDestroy(&dm); 2399 2400 .seealso: DMPlexTopologyLoad(), DMPlexSectionLoad(), DMPlexGlobalVectorLoad(), DMPlexGlobalVectorView(), DMPlexLocalVectorView() 2401 @*/ 2402 PetscErrorCode DMPlexLocalVectorLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF sf, Vec vec) 2403 { 2404 PetscBool ishdf5; 2405 2406 PetscFunctionBegin; 2407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2408 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2409 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 2410 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 4); 2411 PetscValidHeaderSpecific(vec, VEC_CLASSID, 5); 2412 /* Check consistency */ 2413 { 2414 PetscSection section; 2415 PetscBool includesConstraints; 2416 PetscInt m, m1; 2417 2418 PetscCall(VecGetLocalSize(vec, &m1)); 2419 PetscCall(DMGetLocalSection(sectiondm, §ion)); 2420 PetscCall(PetscSectionGetIncludesConstraints(section, &includesConstraints)); 2421 if (includesConstraints) PetscCall(PetscSectionGetStorageSize(section, &m)); 2422 else PetscCall(PetscSectionGetConstrainedStorageSize(section, &m)); 2423 PetscCheck(m1 == m,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%" PetscInt_FMT ") != local section storage size (%" PetscInt_FMT ")", m1, m); 2424 } 2425 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5)); 2426 PetscCall(PetscLogEventBegin(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2427 if (ishdf5) { 2428 #if defined(PETSC_HAVE_HDF5) 2429 PetscCall(DMPlexVecLoad_HDF5_Internal(dm, viewer, sectiondm, sf, vec)); 2430 #else 2431 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2432 #endif 2433 } 2434 PetscCall(PetscLogEventEnd(DMPLEX_LocalVectorLoad,viewer,0,0,0)); 2435 PetscFunctionReturn(0); 2436 } 2437 2438 PetscErrorCode DMDestroy_Plex(DM dm) 2439 { 2440 DM_Plex *mesh = (DM_Plex*) dm->data; 2441 2442 PetscFunctionBegin; 2443 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 2444 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL)); 2445 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL)); 2446 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL)); 2447 if (--mesh->refct > 0) PetscFunctionReturn(0); 2448 PetscCall(PetscSectionDestroy(&mesh->coneSection)); 2449 PetscCall(PetscFree(mesh->cones)); 2450 PetscCall(PetscFree(mesh->coneOrientations)); 2451 PetscCall(PetscSectionDestroy(&mesh->supportSection)); 2452 PetscCall(PetscSectionDestroy(&mesh->subdomainSection)); 2453 PetscCall(PetscFree(mesh->supports)); 2454 PetscCall(PetscFree(mesh->facesTmp)); 2455 PetscCall(PetscFree(mesh->tetgenOpts)); 2456 PetscCall(PetscFree(mesh->triangleOpts)); 2457 PetscCall(PetscFree(mesh->transformType)); 2458 PetscCall(PetscPartitionerDestroy(&mesh->partitioner)); 2459 PetscCall(DMLabelDestroy(&mesh->subpointMap)); 2460 PetscCall(ISDestroy(&mesh->subpointIS)); 2461 PetscCall(ISDestroy(&mesh->globalVertexNumbers)); 2462 PetscCall(ISDestroy(&mesh->globalCellNumbers)); 2463 PetscCall(PetscSectionDestroy(&mesh->anchorSection)); 2464 PetscCall(ISDestroy(&mesh->anchorIS)); 2465 PetscCall(PetscSectionDestroy(&mesh->parentSection)); 2466 PetscCall(PetscFree(mesh->parents)); 2467 PetscCall(PetscFree(mesh->childIDs)); 2468 PetscCall(PetscSectionDestroy(&mesh->childSection)); 2469 PetscCall(PetscFree(mesh->children)); 2470 PetscCall(DMDestroy(&mesh->referenceTree)); 2471 PetscCall(PetscGridHashDestroy(&mesh->lbox)); 2472 PetscCall(PetscFree(mesh->neighbors)); 2473 if (mesh->metricCtx) PetscCall(PetscFree(mesh->metricCtx)); 2474 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 2475 PetscCall(PetscFree(mesh)); 2476 PetscFunctionReturn(0); 2477 } 2478 2479 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 2480 { 2481 PetscSection sectionGlobal; 2482 PetscInt bs = -1, mbs; 2483 PetscInt localSize; 2484 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 2485 MatType mtype; 2486 ISLocalToGlobalMapping ltog; 2487 2488 PetscFunctionBegin; 2489 PetscCall(MatInitializePackage()); 2490 mtype = dm->mattype; 2491 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 2492 /* PetscCall(PetscSectionGetStorageSize(sectionGlobal, &localSize)); */ 2493 PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize)); 2494 PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 2495 PetscCall(MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE)); 2496 PetscCall(MatSetType(*J, mtype)); 2497 PetscCall(MatSetFromOptions(*J)); 2498 PetscCall(MatGetBlockSize(*J, &mbs)); 2499 if (mbs > 1) bs = mbs; 2500 PetscCall(PetscStrcmp(mtype, MATSHELL, &isShell)); 2501 PetscCall(PetscStrcmp(mtype, MATBAIJ, &isBlock)); 2502 PetscCall(PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock)); 2503 PetscCall(PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock)); 2504 PetscCall(PetscStrcmp(mtype, MATSBAIJ, &isSymBlock)); 2505 PetscCall(PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock)); 2506 PetscCall(PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock)); 2507 PetscCall(PetscStrcmp(mtype, MATIS, &isMatIS)); 2508 if (!isShell) { 2509 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2510 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2]; 2511 PetscInt pStart, pEnd, p, dof, cdof; 2512 2513 PetscCall(DMGetLocalToGlobalMapping(dm,<og)); 2514 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 2515 for (p = pStart; p < pEnd; ++p) { 2516 PetscInt bdof; 2517 2518 PetscCall(PetscSectionGetDof(sectionGlobal, p, &dof)); 2519 PetscCall(PetscSectionGetConstraintDof(sectionGlobal, p, &cdof)); 2520 dof = dof < 0 ? -(dof+1) : dof; 2521 bdof = cdof && (dof-cdof) ? 1 : dof; 2522 if (dof) { 2523 if (bs < 0) {bs = bdof;} 2524 else if (bs != bdof) {bs = 1; break;} 2525 } 2526 } 2527 /* Must have same blocksize on all procs (some might have no points) */ 2528 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 2529 bsLocal[1] = bs; 2530 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 2531 if (bsMinMax[0] != bsMinMax[1]) bs = 1; 2532 else bs = bsMinMax[0]; 2533 bs = PetscMax(1,bs); 2534 PetscCall(MatSetLocalToGlobalMapping(*J,ltog,ltog)); 2535 if (dm->prealloc_skip) { // User will likely use MatSetPreallocationCOO(), but still set structural parameters 2536 PetscCall(MatSetBlockSize(*J, bs)); 2537 PetscCall(MatSetUp(*J)); 2538 } else { 2539 PetscCall(PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu)); 2540 PetscCall(DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix)); 2541 PetscCall(PetscFree4(dnz, onz, dnzu, onzu)); 2542 } 2543 } 2544 PetscCall(MatSetDM(*J, dm)); 2545 PetscFunctionReturn(0); 2546 } 2547 2548 /*@ 2549 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2550 2551 Not collective 2552 2553 Input Parameter: 2554 . mesh - The DMPlex 2555 2556 Output Parameters: 2557 . subsection - The subdomain section 2558 2559 Level: developer 2560 2561 .seealso: 2562 @*/ 2563 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2564 { 2565 DM_Plex *mesh = (DM_Plex*) dm->data; 2566 2567 PetscFunctionBegin; 2568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2569 if (!mesh->subdomainSection) { 2570 PetscSection section; 2571 PetscSF sf; 2572 2573 PetscCall(PetscSFCreate(PETSC_COMM_SELF,&sf)); 2574 PetscCall(DMGetLocalSection(dm,§ion)); 2575 PetscCall(PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection)); 2576 PetscCall(PetscSFDestroy(&sf)); 2577 } 2578 *subsection = mesh->subdomainSection; 2579 PetscFunctionReturn(0); 2580 } 2581 2582 /*@ 2583 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2584 2585 Not collective 2586 2587 Input Parameter: 2588 . mesh - The DMPlex 2589 2590 Output Parameters: 2591 + pStart - The first mesh point 2592 - pEnd - The upper bound for mesh points 2593 2594 Level: beginner 2595 2596 .seealso: DMPlexCreate(), DMPlexSetChart() 2597 @*/ 2598 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2599 { 2600 DM_Plex *mesh = (DM_Plex*) dm->data; 2601 2602 PetscFunctionBegin; 2603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2604 PetscCall(PetscSectionGetChart(mesh->coneSection, pStart, pEnd)); 2605 PetscFunctionReturn(0); 2606 } 2607 2608 /*@ 2609 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2610 2611 Not collective 2612 2613 Input Parameters: 2614 + mesh - The DMPlex 2615 . pStart - The first mesh point 2616 - pEnd - The upper bound for mesh points 2617 2618 Output Parameters: 2619 2620 Level: beginner 2621 2622 .seealso: DMPlexCreate(), DMPlexGetChart() 2623 @*/ 2624 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2625 { 2626 DM_Plex *mesh = (DM_Plex*) dm->data; 2627 2628 PetscFunctionBegin; 2629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2630 PetscCall(PetscSectionSetChart(mesh->coneSection, pStart, pEnd)); 2631 PetscCall(PetscSectionSetChart(mesh->supportSection, pStart, pEnd)); 2632 PetscFunctionReturn(0); 2633 } 2634 2635 /*@ 2636 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2637 2638 Not collective 2639 2640 Input Parameters: 2641 + mesh - The DMPlex 2642 - p - The point, which must lie in the chart set with DMPlexSetChart() 2643 2644 Output Parameter: 2645 . size - The cone size for point p 2646 2647 Level: beginner 2648 2649 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 2650 @*/ 2651 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2652 { 2653 DM_Plex *mesh = (DM_Plex*) dm->data; 2654 2655 PetscFunctionBegin; 2656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2657 PetscValidIntPointer(size, 3); 2658 PetscCall(PetscSectionGetDof(mesh->coneSection, p, size)); 2659 PetscFunctionReturn(0); 2660 } 2661 2662 /*@ 2663 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2664 2665 Not collective 2666 2667 Input Parameters: 2668 + mesh - The DMPlex 2669 . p - The point, which must lie in the chart set with DMPlexSetChart() 2670 - size - The cone size for point p 2671 2672 Output Parameter: 2673 2674 Note: 2675 This should be called after DMPlexSetChart(). 2676 2677 Level: beginner 2678 2679 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 2680 @*/ 2681 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2682 { 2683 DM_Plex *mesh = (DM_Plex*) dm->data; 2684 2685 PetscFunctionBegin; 2686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2687 PetscCall(PetscSectionSetDof(mesh->coneSection, p, size)); 2688 PetscFunctionReturn(0); 2689 } 2690 2691 /*@ 2692 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2693 2694 Not collective 2695 2696 Input Parameters: 2697 + mesh - The DMPlex 2698 . p - The point, which must lie in the chart set with DMPlexSetChart() 2699 - size - The additional cone size for point p 2700 2701 Output Parameter: 2702 2703 Note: 2704 This should be called after DMPlexSetChart(). 2705 2706 Level: beginner 2707 2708 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 2709 @*/ 2710 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2711 { 2712 DM_Plex *mesh = (DM_Plex*) dm->data; 2713 PetscFunctionBegin; 2714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2715 PetscCall(PetscSectionAddDof(mesh->coneSection, p, size)); 2716 PetscFunctionReturn(0); 2717 } 2718 2719 /*@C 2720 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2721 2722 Not collective 2723 2724 Input Parameters: 2725 + dm - The DMPlex 2726 - p - The point, which must lie in the chart set with DMPlexSetChart() 2727 2728 Output Parameter: 2729 . cone - An array of points which are on the in-edges for point p 2730 2731 Level: beginner 2732 2733 Fortran Notes: 2734 Since it returns an array, this routine is only available in Fortran 90, and you must 2735 include petsc.h90 in your code. 2736 You must also call DMPlexRestoreCone() after you finish using the returned array. 2737 DMPlexRestoreCone() is not needed/available in C. 2738 2739 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart() 2740 @*/ 2741 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2742 { 2743 DM_Plex *mesh = (DM_Plex*) dm->data; 2744 PetscInt off; 2745 2746 PetscFunctionBegin; 2747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2748 PetscValidPointer(cone, 3); 2749 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2750 *cone = &mesh->cones[off]; 2751 PetscFunctionReturn(0); 2752 } 2753 2754 /*@C 2755 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2756 2757 Not collective 2758 2759 Input Parameters: 2760 + dm - The DMPlex 2761 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2762 2763 Output Parameters: 2764 + pConesSection - PetscSection describing the layout of pCones 2765 - pCones - An array of points which are on the in-edges for the point set p 2766 2767 Level: intermediate 2768 2769 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart() 2770 @*/ 2771 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2772 { 2773 PetscSection cs, newcs; 2774 PetscInt *cones; 2775 PetscInt *newarr=NULL; 2776 PetscInt n; 2777 2778 PetscFunctionBegin; 2779 PetscCall(DMPlexGetCones(dm, &cones)); 2780 PetscCall(DMPlexGetConeSection(dm, &cs)); 2781 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL)); 2782 if (pConesSection) *pConesSection = newcs; 2783 if (pCones) { 2784 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 2785 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones)); 2786 } 2787 PetscFunctionReturn(0); 2788 } 2789 2790 /*@ 2791 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2792 2793 Not collective 2794 2795 Input Parameters: 2796 + dm - The DMPlex 2797 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2798 2799 Output Parameter: 2800 . expandedPoints - An array of vertices recursively expanded from input points 2801 2802 Level: advanced 2803 2804 Notes: 2805 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2806 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2807 2808 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth() 2809 @*/ 2810 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2811 { 2812 IS *expandedPointsAll; 2813 PetscInt depth; 2814 2815 PetscFunctionBegin; 2816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2817 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2818 PetscValidPointer(expandedPoints, 3); 2819 PetscCall(DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2820 *expandedPoints = expandedPointsAll[0]; 2821 PetscCall(PetscObjectReference((PetscObject)expandedPointsAll[0])); 2822 PetscCall(DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL)); 2823 PetscFunctionReturn(0); 2824 } 2825 2826 /*@ 2827 DMPlexGetConeRecursive - Expand each given point into its cone points and do that recursively until we end up just with vertices (DAG points of depth 0, i.e. without cones). 2828 2829 Not collective 2830 2831 Input Parameters: 2832 + dm - The DMPlex 2833 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2834 2835 Output Parameters: 2836 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2837 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2838 - sections - (optional) An array of sections which describe mappings from points to their cone points 2839 2840 Level: advanced 2841 2842 Notes: 2843 Like DMPlexGetConeTuple() but recursive. 2844 2845 Array expandedPoints has size equal to depth. Each expandedPoints[d] contains DAG points with maximum depth d, recursively cone-wise expanded from the input points. 2846 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2847 2848 Array section has size equal to depth. Each PetscSection sections[d] realizes mapping from expandedPoints[d+1] (section points) to expandedPoints[d] (section dofs) as follows: 2849 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2850 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2851 2852 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2853 @*/ 2854 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2855 { 2856 const PetscInt *arr0=NULL, *cone=NULL; 2857 PetscInt *arr=NULL, *newarr=NULL; 2858 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2859 IS *expandedPoints_; 2860 PetscSection *sections_; 2861 2862 PetscFunctionBegin; 2863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2864 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2865 if (depth) PetscValidIntPointer(depth, 3); 2866 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2867 if (sections) PetscValidPointer(sections, 5); 2868 PetscCall(ISGetLocalSize(points, &n)); 2869 PetscCall(ISGetIndices(points, &arr0)); 2870 PetscCall(DMPlexGetDepth(dm, &depth_)); 2871 PetscCall(PetscCalloc1(depth_, &expandedPoints_)); 2872 PetscCall(PetscCalloc1(depth_, §ions_)); 2873 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2874 for (d=depth_-1; d>=0; d--) { 2875 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ions_[d])); 2876 PetscCall(PetscSectionSetChart(sections_[d], 0, n)); 2877 for (i=0; i<n; i++) { 2878 PetscCall(DMPlexGetDepthStratum(dm, d+1, &start, &end)); 2879 if (arr[i] >= start && arr[i] < end) { 2880 PetscCall(DMPlexGetConeSize(dm, arr[i], &cn)); 2881 PetscCall(PetscSectionSetDof(sections_[d], i, cn)); 2882 } else { 2883 PetscCall(PetscSectionSetDof(sections_[d], i, 1)); 2884 } 2885 } 2886 PetscCall(PetscSectionSetUp(sections_[d])); 2887 PetscCall(PetscSectionGetStorageSize(sections_[d], &newn)); 2888 PetscCall(PetscMalloc1(newn, &newarr)); 2889 for (i=0; i<n; i++) { 2890 PetscCall(PetscSectionGetDof(sections_[d], i, &cn)); 2891 PetscCall(PetscSectionGetOffset(sections_[d], i, &co)); 2892 if (cn > 1) { 2893 PetscCall(DMPlexGetCone(dm, arr[i], &cone)); 2894 PetscCall(PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt))); 2895 } else { 2896 newarr[co] = arr[i]; 2897 } 2898 } 2899 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d])); 2900 arr = newarr; 2901 n = newn; 2902 } 2903 PetscCall(ISRestoreIndices(points, &arr0)); 2904 *depth = depth_; 2905 if (expandedPoints) *expandedPoints = expandedPoints_; 2906 else { 2907 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&expandedPoints_[d])); 2908 PetscCall(PetscFree(expandedPoints_)); 2909 } 2910 if (sections) *sections = sections_; 2911 else { 2912 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(§ions_[d])); 2913 PetscCall(PetscFree(sections_)); 2914 } 2915 PetscFunctionReturn(0); 2916 } 2917 2918 /*@ 2919 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2920 2921 Not collective 2922 2923 Input Parameters: 2924 + dm - The DMPlex 2925 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2926 2927 Output Parameters: 2928 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2929 . expandedPoints - (optional) An array of recursively expanded cones 2930 - sections - (optional) An array of sections which describe mappings from points to their cone points 2931 2932 Level: advanced 2933 2934 Notes: 2935 See DMPlexGetConeRecursive() for details. 2936 2937 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2938 @*/ 2939 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2940 { 2941 PetscInt d, depth_; 2942 2943 PetscFunctionBegin; 2944 PetscCall(DMPlexGetDepth(dm, &depth_)); 2945 PetscCheckFalse(depth && *depth != depth_,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2946 if (depth) *depth = 0; 2947 if (expandedPoints) { 2948 for (d=0; d<depth_; d++) PetscCall(ISDestroy(&((*expandedPoints)[d]))); 2949 PetscCall(PetscFree(*expandedPoints)); 2950 } 2951 if (sections) { 2952 for (d=0; d<depth_; d++) PetscCall(PetscSectionDestroy(&((*sections)[d]))); 2953 PetscCall(PetscFree(*sections)); 2954 } 2955 PetscFunctionReturn(0); 2956 } 2957 2958 /*@ 2959 DMPlexSetCone - Set the points on the in-edges for this point in the DAG; that is these are the points that cover the specific point 2960 2961 Not collective 2962 2963 Input Parameters: 2964 + mesh - The DMPlex 2965 . p - The point, which must lie in the chart set with DMPlexSetChart() 2966 - cone - An array of points which are on the in-edges for point p 2967 2968 Output Parameter: 2969 2970 Note: 2971 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2972 2973 Level: beginner 2974 2975 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize() 2976 @*/ 2977 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 2978 { 2979 DM_Plex *mesh = (DM_Plex*) dm->data; 2980 PetscInt pStart, pEnd; 2981 PetscInt dof, off, c; 2982 2983 PetscFunctionBegin; 2984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2985 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 2986 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 2987 if (dof) PetscValidIntPointer(cone, 3); 2988 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 2989 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 2990 for (c = 0; c < dof; ++c) { 2991 PetscCheck(!(cone[c] < pStart) && !(cone[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", cone[c], pStart, pEnd); 2992 mesh->cones[off+c] = cone[c]; 2993 } 2994 PetscFunctionReturn(0); 2995 } 2996 2997 /*@C 2998 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 2999 3000 Not collective 3001 3002 Input Parameters: 3003 + mesh - The DMPlex 3004 - p - The point, which must lie in the chart set with DMPlexSetChart() 3005 3006 Output Parameter: 3007 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 3008 integer giving the prescription for cone traversal. 3009 3010 Level: beginner 3011 3012 Notes: 3013 The number indexes the symmetry transformations for the cell type (see manual). Orientation 0 is always 3014 the identity transformation. Negative orientation indicates reflection so that -(o+1) is the reflection 3015 of o, however it is not necessarily the inverse. To get the inverse, use DMPolytopeTypeComposeOrientationInv() 3016 with the identity. 3017 3018 Fortran Notes: 3019 Since it returns an array, this routine is only available in Fortran 90, and you must 3020 include petsc.h90 in your code. 3021 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 3022 DMPlexRestoreConeOrientation() is not needed/available in C. 3023 3024 .seealso: DMPolytopeTypeComposeOrientation(), DMPolytopeTypeComposeOrientationInv(), DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 3025 @*/ 3026 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 3027 { 3028 DM_Plex *mesh = (DM_Plex*) dm->data; 3029 PetscInt off; 3030 3031 PetscFunctionBegin; 3032 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3033 if (PetscDefined(USE_DEBUG)) { 3034 PetscInt dof; 3035 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3036 if (dof) PetscValidPointer(coneOrientation, 3); 3037 } 3038 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3039 3040 *coneOrientation = &mesh->coneOrientations[off]; 3041 PetscFunctionReturn(0); 3042 } 3043 3044 /*@ 3045 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 3046 3047 Not collective 3048 3049 Input Parameters: 3050 + mesh - The DMPlex 3051 . p - The point, which must lie in the chart set with DMPlexSetChart() 3052 - coneOrientation - An array of orientations 3053 Output Parameter: 3054 3055 Notes: 3056 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 3057 3058 The meaning of coneOrientation is detailed in DMPlexGetConeOrientation(). 3059 3060 Level: beginner 3061 3062 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3063 @*/ 3064 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 3065 { 3066 DM_Plex *mesh = (DM_Plex*) dm->data; 3067 PetscInt pStart, pEnd; 3068 PetscInt dof, off, c; 3069 3070 PetscFunctionBegin; 3071 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3072 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3073 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3074 if (dof) PetscValidIntPointer(coneOrientation, 3); 3075 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3076 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3077 for (c = 0; c < dof; ++c) { 3078 PetscInt cdof, o = coneOrientation[c]; 3079 3080 PetscCall(PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof)); 3081 PetscCheckFalse(o && ((o < -(cdof+1)) || (o >= cdof)),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ". %" PetscInt_FMT ")", o, -(cdof+1), cdof); 3082 mesh->coneOrientations[off+c] = o; 3083 } 3084 PetscFunctionReturn(0); 3085 } 3086 3087 /*@ 3088 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 3089 3090 Not collective 3091 3092 Input Parameters: 3093 + mesh - The DMPlex 3094 . p - The point, which must lie in the chart set with DMPlexSetChart() 3095 . conePos - The local index in the cone where the point should be put 3096 - conePoint - The mesh point to insert 3097 3098 Level: beginner 3099 3100 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3101 @*/ 3102 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 3103 { 3104 DM_Plex *mesh = (DM_Plex*) dm->data; 3105 PetscInt pStart, pEnd; 3106 PetscInt dof, off; 3107 3108 PetscFunctionBegin; 3109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3110 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3111 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3112 PetscCheck(!(conePoint < pStart) && !(conePoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", conePoint, pStart, pEnd); 3113 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3114 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3115 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3116 mesh->cones[off+conePos] = conePoint; 3117 PetscFunctionReturn(0); 3118 } 3119 3120 /*@ 3121 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 3122 3123 Not collective 3124 3125 Input Parameters: 3126 + mesh - The DMPlex 3127 . p - The point, which must lie in the chart set with DMPlexSetChart() 3128 . conePos - The local index in the cone where the point should be put 3129 - coneOrientation - The point orientation to insert 3130 3131 Level: beginner 3132 3133 Notes: 3134 The meaning of coneOrientation values is detailed in DMPlexGetConeOrientation(). 3135 3136 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3137 @*/ 3138 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 3139 { 3140 DM_Plex *mesh = (DM_Plex*) dm->data; 3141 PetscInt pStart, pEnd; 3142 PetscInt dof, off; 3143 3144 PetscFunctionBegin; 3145 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3146 PetscCall(PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd)); 3147 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3148 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3149 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3150 PetscCheck(!(conePos < 0) && !(conePos >= dof),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", conePos, p, dof); 3151 mesh->coneOrientations[off+conePos] = coneOrientation; 3152 PetscFunctionReturn(0); 3153 } 3154 3155 /*@ 3156 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 3157 3158 Not collective 3159 3160 Input Parameters: 3161 + mesh - The DMPlex 3162 - p - The point, which must lie in the chart set with DMPlexSetChart() 3163 3164 Output Parameter: 3165 . size - The support size for point p 3166 3167 Level: beginner 3168 3169 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 3170 @*/ 3171 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 3172 { 3173 DM_Plex *mesh = (DM_Plex*) dm->data; 3174 3175 PetscFunctionBegin; 3176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3177 PetscValidIntPointer(size, 3); 3178 PetscCall(PetscSectionGetDof(mesh->supportSection, p, size)); 3179 PetscFunctionReturn(0); 3180 } 3181 3182 /*@ 3183 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 3184 3185 Not collective 3186 3187 Input Parameters: 3188 + mesh - The DMPlex 3189 . p - The point, which must lie in the chart set with DMPlexSetChart() 3190 - size - The support size for point p 3191 3192 Output Parameter: 3193 3194 Note: 3195 This should be called after DMPlexSetChart(). 3196 3197 Level: beginner 3198 3199 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 3200 @*/ 3201 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 3202 { 3203 DM_Plex *mesh = (DM_Plex*) dm->data; 3204 3205 PetscFunctionBegin; 3206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3207 PetscCall(PetscSectionSetDof(mesh->supportSection, p, size)); 3208 PetscFunctionReturn(0); 3209 } 3210 3211 /*@C 3212 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 3213 3214 Not collective 3215 3216 Input Parameters: 3217 + mesh - The DMPlex 3218 - p - The point, which must lie in the chart set with DMPlexSetChart() 3219 3220 Output Parameter: 3221 . support - An array of points which are on the out-edges for point p 3222 3223 Level: beginner 3224 3225 Fortran Notes: 3226 Since it returns an array, this routine is only available in Fortran 90, and you must 3227 include petsc.h90 in your code. 3228 You must also call DMPlexRestoreSupport() after you finish using the returned array. 3229 DMPlexRestoreSupport() is not needed/available in C. 3230 3231 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart() 3232 @*/ 3233 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 3234 { 3235 DM_Plex *mesh = (DM_Plex*) dm->data; 3236 PetscInt off; 3237 3238 PetscFunctionBegin; 3239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3240 PetscValidPointer(support, 3); 3241 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3242 *support = &mesh->supports[off]; 3243 PetscFunctionReturn(0); 3244 } 3245 3246 /*@ 3247 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 3248 3249 Not collective 3250 3251 Input Parameters: 3252 + mesh - The DMPlex 3253 . p - The point, which must lie in the chart set with DMPlexSetChart() 3254 - support - An array of points which are on the out-edges for point p 3255 3256 Output Parameter: 3257 3258 Note: 3259 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 3260 3261 Level: beginner 3262 3263 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 3264 @*/ 3265 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 3266 { 3267 DM_Plex *mesh = (DM_Plex*) dm->data; 3268 PetscInt pStart, pEnd; 3269 PetscInt dof, off, c; 3270 3271 PetscFunctionBegin; 3272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3273 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3274 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3275 if (dof) PetscValidIntPointer(support, 3); 3276 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3277 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3278 for (c = 0; c < dof; ++c) { 3279 PetscCheck(!(support[c] < pStart) && !(support[c] >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", support[c], pStart, pEnd); 3280 mesh->supports[off+c] = support[c]; 3281 } 3282 PetscFunctionReturn(0); 3283 } 3284 3285 /*@ 3286 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 3287 3288 Not collective 3289 3290 Input Parameters: 3291 + mesh - The DMPlex 3292 . p - The point, which must lie in the chart set with DMPlexSetChart() 3293 . supportPos - The local index in the cone where the point should be put 3294 - supportPoint - The mesh point to insert 3295 3296 Level: beginner 3297 3298 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 3299 @*/ 3300 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 3301 { 3302 DM_Plex *mesh = (DM_Plex*) dm->data; 3303 PetscInt pStart, pEnd; 3304 PetscInt dof, off; 3305 3306 PetscFunctionBegin; 3307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3308 PetscCall(PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd)); 3309 PetscCall(PetscSectionGetDof(mesh->supportSection, p, &dof)); 3310 PetscCall(PetscSectionGetOffset(mesh->supportSection, p, &off)); 3311 PetscCheck(!(p < pStart) && !(p >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, pStart, pEnd); 3312 PetscCheck(!(supportPoint < pStart) && !(supportPoint >= pEnd),PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %" PetscInt_FMT " is not in the valid range [%" PetscInt_FMT ", %" PetscInt_FMT ")", supportPoint, pStart, pEnd); 3313 PetscCheck(supportPos < dof,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %" PetscInt_FMT " of point %" PetscInt_FMT " is not in the valid range [0, %" PetscInt_FMT ")", supportPos, p, dof); 3314 mesh->supports[off+supportPos] = supportPoint; 3315 PetscFunctionReturn(0); 3316 } 3317 3318 /* Converts an orientation o in the current numbering to the previous scheme used in Plex */ 3319 PetscInt DMPolytopeConvertNewOrientation_Internal(DMPolytopeType ct, PetscInt o) 3320 { 3321 switch (ct) { 3322 case DM_POLYTOPE_SEGMENT: 3323 if (o == -1) return -2; 3324 break; 3325 case DM_POLYTOPE_TRIANGLE: 3326 if (o == -3) return -1; 3327 if (o == -2) return -3; 3328 if (o == -1) return -2; 3329 break; 3330 case DM_POLYTOPE_QUADRILATERAL: 3331 if (o == -4) return -2; 3332 if (o == -3) return -1; 3333 if (o == -2) return -4; 3334 if (o == -1) return -3; 3335 break; 3336 default: return o; 3337 } 3338 return o; 3339 } 3340 3341 /* Converts an orientation o in the previous scheme used in Plex to the current numbering */ 3342 PetscInt DMPolytopeConvertOldOrientation_Internal(DMPolytopeType ct, PetscInt o) 3343 { 3344 switch (ct) { 3345 case DM_POLYTOPE_SEGMENT: 3346 if ((o == -2) || (o == 1)) return -1; 3347 if (o == -1) return 0; 3348 break; 3349 case DM_POLYTOPE_TRIANGLE: 3350 if (o == -3) return -2; 3351 if (o == -2) return -1; 3352 if (o == -1) return -3; 3353 break; 3354 case DM_POLYTOPE_QUADRILATERAL: 3355 if (o == -4) return -2; 3356 if (o == -3) return -1; 3357 if (o == -2) return -4; 3358 if (o == -1) return -3; 3359 break; 3360 default: return o; 3361 } 3362 return o; 3363 } 3364 3365 /* Takes in a mesh whose orientations are in the previous scheme and converts them all to the current numbering */ 3366 PetscErrorCode DMPlexConvertOldOrientations_Internal(DM dm) 3367 { 3368 PetscInt pStart, pEnd, p; 3369 3370 PetscFunctionBegin; 3371 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3372 for (p = pStart; p < pEnd; ++p) { 3373 const PetscInt *cone, *ornt; 3374 PetscInt coneSize, c; 3375 3376 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3377 PetscCall(DMPlexGetCone(dm, p, &cone)); 3378 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 3379 for (c = 0; c < coneSize; ++c) { 3380 DMPolytopeType ct; 3381 const PetscInt o = ornt[c]; 3382 3383 PetscCall(DMPlexGetCellType(dm, cone[c], &ct)); 3384 switch (ct) { 3385 case DM_POLYTOPE_SEGMENT: 3386 if ((o == -2) || (o == 1)) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3387 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, 0)); 3388 break; 3389 case DM_POLYTOPE_TRIANGLE: 3390 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3391 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3392 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3393 break; 3394 case DM_POLYTOPE_QUADRILATERAL: 3395 if (o == -4) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -2)); 3396 if (o == -3) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -1)); 3397 if (o == -2) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -4)); 3398 if (o == -1) PetscCall(DMPlexInsertConeOrientation(dm, p, c, -3)); 3399 break; 3400 default: break; 3401 } 3402 } 3403 } 3404 PetscFunctionReturn(0); 3405 } 3406 3407 static PetscErrorCode DMPlexGetTransitiveClosure_Depth1_Private(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3408 { 3409 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3410 PetscInt *closure; 3411 const PetscInt *tmp = NULL, *tmpO = NULL; 3412 PetscInt off = 0, tmpSize, t; 3413 3414 PetscFunctionBeginHot; 3415 if (ornt) { 3416 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3417 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3418 } 3419 if (*points) { 3420 closure = *points; 3421 } else { 3422 PetscInt maxConeSize, maxSupportSize; 3423 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3424 PetscCall(DMGetWorkArray(dm, 2*(PetscMax(maxConeSize, maxSupportSize)+1), MPIU_INT, &closure)); 3425 } 3426 if (useCone) { 3427 PetscCall(DMPlexGetConeSize(dm, p, &tmpSize)); 3428 PetscCall(DMPlexGetCone(dm, p, &tmp)); 3429 PetscCall(DMPlexGetConeOrientation(dm, p, &tmpO)); 3430 } else { 3431 PetscCall(DMPlexGetSupportSize(dm, p, &tmpSize)); 3432 PetscCall(DMPlexGetSupport(dm, p, &tmp)); 3433 } 3434 if (ct == DM_POLYTOPE_UNKNOWN) { 3435 closure[off++] = p; 3436 closure[off++] = 0; 3437 for (t = 0; t < tmpSize; ++t) { 3438 closure[off++] = tmp[t]; 3439 closure[off++] = tmpO ? tmpO[t] : 0; 3440 } 3441 } else { 3442 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, ornt); 3443 3444 /* We assume that cells with a valid type have faces with a valid type */ 3445 closure[off++] = p; 3446 closure[off++] = ornt; 3447 for (t = 0; t < tmpSize; ++t) { 3448 DMPolytopeType ft; 3449 3450 PetscCall(DMPlexGetCellType(dm, tmp[t], &ft)); 3451 closure[off++] = tmp[arr[t]]; 3452 closure[off++] = tmpO ? DMPolytopeTypeComposeOrientation(ft, ornt, tmpO[t]) : 0; 3453 } 3454 } 3455 if (numPoints) *numPoints = tmpSize+1; 3456 if (points) *points = closure; 3457 PetscFunctionReturn(0); 3458 } 3459 3460 /* We need a special tensor verison becasue we want to allow duplicate points in the endcaps for hybrid cells */ 3461 static PetscErrorCode DMPlexTransitiveClosure_Tensor_Internal(DM dm, PetscInt point, DMPolytopeType ct, PetscInt o, PetscBool useCone, PetscInt *numPoints, PetscInt **points) 3462 { 3463 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 3464 const PetscInt *cone, *ornt; 3465 PetscInt *pts, *closure = NULL; 3466 DMPolytopeType ft; 3467 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries, maxSize; 3468 PetscInt dim, coneSize, c, d, clSize, cl; 3469 3470 PetscFunctionBeginHot; 3471 PetscCall(DMGetDimension(dm, &dim)); 3472 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3473 PetscCall(DMPlexGetCone(dm, point, &cone)); 3474 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3475 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3476 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, dim+1)-1)/(maxConeSize-1)) : dim+1; 3477 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, dim+1)-1)/(maxSupportSize-1)) : dim+1; 3478 maxSize = PetscMax(coneSeries, supportSeries); 3479 if (*points) {pts = *points;} 3480 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &pts)); 3481 c = 0; 3482 pts[c++] = point; 3483 pts[c++] = o; 3484 PetscCall(DMPlexGetCellType(dm, cone[arr[0*2+0]], &ft)); 3485 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[0*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[0*2+1], ornt[0]), useCone, &clSize, &closure)); 3486 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3487 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[arr[1*2+0]], DMPolytopeTypeComposeOrientation(ft, arr[1*2+1], ornt[1]), useCone, &clSize, &closure)); 3488 for (cl = 0; cl < clSize*2; cl += 2) {pts[c++] = closure[cl]; pts[c++] = closure[cl+1];} 3489 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], useCone, &clSize, &closure)); 3490 for (d = 2; d < coneSize; ++d) { 3491 PetscCall(DMPlexGetCellType(dm, cone[arr[d*2+0]], &ft)); 3492 pts[c++] = cone[arr[d*2+0]]; 3493 pts[c++] = DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d]); 3494 } 3495 if (dim >= 3) { 3496 for (d = 2; d < coneSize; ++d) { 3497 const PetscInt fpoint = cone[arr[d*2+0]]; 3498 const PetscInt *fcone, *fornt; 3499 PetscInt fconeSize, fc, i; 3500 3501 PetscCall(DMPlexGetCellType(dm, fpoint, &ft)); 3502 const PetscInt *farr = DMPolytopeTypeGetArrangment(ft, DMPolytopeTypeComposeOrientation(ft, arr[d*2+1], ornt[d])); 3503 PetscCall(DMPlexGetConeSize(dm, fpoint, &fconeSize)); 3504 PetscCall(DMPlexGetCone(dm, fpoint, &fcone)); 3505 PetscCall(DMPlexGetConeOrientation(dm, fpoint, &fornt)); 3506 for (fc = 0; fc < fconeSize; ++fc) { 3507 const PetscInt cp = fcone[farr[fc*2+0]]; 3508 const PetscInt co = farr[fc*2+1]; 3509 3510 for (i = 0; i < c; i += 2) if (pts[i] == cp) break; 3511 if (i == c) { 3512 PetscCall(DMPlexGetCellType(dm, cp, &ft)); 3513 pts[c++] = cp; 3514 pts[c++] = DMPolytopeTypeComposeOrientation(ft, co, fornt[farr[fc*2+0]]); 3515 } 3516 } 3517 } 3518 } 3519 *numPoints = c/2; 3520 *points = pts; 3521 PetscFunctionReturn(0); 3522 } 3523 3524 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3525 { 3526 DMPolytopeType ct; 3527 PetscInt *closure, *fifo; 3528 PetscInt closureSize = 0, fifoStart = 0, fifoSize = 0; 3529 PetscInt maxConeSize, maxSupportSize, coneSeries, supportSeries; 3530 PetscInt depth, maxSize; 3531 3532 PetscFunctionBeginHot; 3533 PetscCall(DMPlexGetDepth(dm, &depth)); 3534 if (depth == 1) { 3535 PetscCall(DMPlexGetTransitiveClosure_Depth1_Private(dm, p, ornt, useCone, numPoints, points)); 3536 PetscFunctionReturn(0); 3537 } 3538 PetscCall(DMPlexGetCellType(dm, p, &ct)); 3539 if (ct == DM_POLYTOPE_FV_GHOST || ct == DM_POLYTOPE_INTERIOR_GHOST || ct == DM_POLYTOPE_UNKNOWN) ct = DM_POLYTOPE_UNKNOWN; 3540 if (ct == DM_POLYTOPE_SEG_PRISM_TENSOR || ct == DM_POLYTOPE_TRI_PRISM_TENSOR || ct == DM_POLYTOPE_QUAD_PRISM_TENSOR) { 3541 PetscCall(DMPlexTransitiveClosure_Tensor_Internal(dm, p, ct, ornt, useCone, numPoints, points)); 3542 PetscFunctionReturn(0); 3543 } 3544 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 3545 coneSeries = (maxConeSize > 1) ? ((PetscPowInt(maxConeSize, depth+1)-1)/(maxConeSize-1)) : depth+1; 3546 supportSeries = (maxSupportSize > 1) ? ((PetscPowInt(maxSupportSize, depth+1)-1)/(maxSupportSize-1)) : depth+1; 3547 maxSize = PetscMax(coneSeries, supportSeries); 3548 PetscCall(DMGetWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3549 if (*points) {closure = *points;} 3550 else PetscCall(DMGetWorkArray(dm, 2*maxSize, MPIU_INT, &closure)); 3551 closure[closureSize++] = p; 3552 closure[closureSize++] = ornt; 3553 fifo[fifoSize++] = p; 3554 fifo[fifoSize++] = ornt; 3555 fifo[fifoSize++] = ct; 3556 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3557 while (fifoSize - fifoStart) { 3558 const PetscInt q = fifo[fifoStart++]; 3559 const PetscInt o = fifo[fifoStart++]; 3560 const DMPolytopeType qt = (DMPolytopeType) fifo[fifoStart++]; 3561 const PetscInt *qarr = DMPolytopeTypeGetArrangment(qt, o); 3562 const PetscInt *tmp, *tmpO; 3563 PetscInt tmpSize, t; 3564 3565 if (PetscDefined(USE_DEBUG)) { 3566 PetscInt nO = DMPolytopeTypeGetNumArrangments(qt)/2; 3567 PetscCheck(!o || !(o >= nO || o < -nO),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, o, -nO, nO, DMPolytopeTypes[qt], q); 3568 } 3569 if (useCone) { 3570 PetscCall(DMPlexGetConeSize(dm, q, &tmpSize)); 3571 PetscCall(DMPlexGetCone(dm, q, &tmp)); 3572 PetscCall(DMPlexGetConeOrientation(dm, q, &tmpO)); 3573 } else { 3574 PetscCall(DMPlexGetSupportSize(dm, q, &tmpSize)); 3575 PetscCall(DMPlexGetSupport(dm, q, &tmp)); 3576 tmpO = NULL; 3577 } 3578 for (t = 0; t < tmpSize; ++t) { 3579 const PetscInt ip = useCone && qarr ? qarr[t*2] : t; 3580 const PetscInt io = useCone && qarr ? qarr[t*2+1] : 0; 3581 const PetscInt cp = tmp[ip]; 3582 PetscCall(DMPlexGetCellType(dm, cp, &ct)); 3583 const PetscInt co = tmpO ? DMPolytopeTypeComposeOrientation(ct, io, tmpO[ip]) : 0; 3584 PetscInt c; 3585 3586 /* Check for duplicate */ 3587 for (c = 0; c < closureSize; c += 2) { 3588 if (closure[c] == cp) break; 3589 } 3590 if (c == closureSize) { 3591 closure[closureSize++] = cp; 3592 closure[closureSize++] = co; 3593 fifo[fifoSize++] = cp; 3594 fifo[fifoSize++] = co; 3595 fifo[fifoSize++] = ct; 3596 } 3597 } 3598 } 3599 PetscCall(DMRestoreWorkArray(dm, 3*maxSize, MPIU_INT, &fifo)); 3600 if (numPoints) *numPoints = closureSize/2; 3601 if (points) *points = closure; 3602 PetscFunctionReturn(0); 3603 } 3604 3605 /*@C 3606 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 3607 3608 Not collective 3609 3610 Input Parameters: 3611 + dm - The DMPlex 3612 . p - The mesh point 3613 - useCone - PETSC_TRUE for the closure, otherwise return the star 3614 3615 Input/Output Parameter: 3616 . points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]; 3617 if NULL on input, internal storage will be returned, otherwise the provided array is used 3618 3619 Output Parameter: 3620 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3621 3622 Note: 3623 If using internal storage (points is NULL on input), each call overwrites the last output. 3624 3625 Fortran Notes: 3626 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3627 3628 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3629 3630 Level: beginner 3631 3632 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3633 @*/ 3634 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3635 { 3636 PetscFunctionBeginHot; 3637 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3638 if (numPoints) PetscValidIntPointer(numPoints, 4); 3639 if (points) PetscValidPointer(points, 5); 3640 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, p, 0, useCone, numPoints, points)); 3641 PetscFunctionReturn(0); 3642 } 3643 3644 /*@C 3645 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3646 3647 Not collective 3648 3649 Input Parameters: 3650 + dm - The DMPlex 3651 . p - The mesh point 3652 . useCone - PETSC_TRUE for the closure, otherwise return the star 3653 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3654 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3655 3656 Note: 3657 If not using internal storage (points is not NULL on input), this call is unnecessary 3658 3659 Fortran Notes: 3660 Since it returns an array, this routine is only available in Fortran 90, and you must include petsc.h90 in your code. 3661 3662 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3663 3664 Level: beginner 3665 3666 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3667 @*/ 3668 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3669 { 3670 PetscFunctionBeginHot; 3671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3672 if (numPoints) *numPoints = 0; 3673 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, points)); 3674 PetscFunctionReturn(0); 3675 } 3676 3677 /*@ 3678 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3679 3680 Not collective 3681 3682 Input Parameter: 3683 . mesh - The DMPlex 3684 3685 Output Parameters: 3686 + maxConeSize - The maximum number of in-edges 3687 - maxSupportSize - The maximum number of out-edges 3688 3689 Level: beginner 3690 3691 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 3692 @*/ 3693 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3694 { 3695 DM_Plex *mesh = (DM_Plex*) dm->data; 3696 3697 PetscFunctionBegin; 3698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3699 if (maxConeSize) { 3700 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, maxConeSize)); 3701 } 3702 if (maxSupportSize) { 3703 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, maxSupportSize)); 3704 } 3705 PetscFunctionReturn(0); 3706 } 3707 3708 PetscErrorCode DMSetUp_Plex(DM dm) 3709 { 3710 DM_Plex *mesh = (DM_Plex*) dm->data; 3711 PetscInt size, maxSupportSize; 3712 3713 PetscFunctionBegin; 3714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3715 PetscCall(PetscSectionSetUp(mesh->coneSection)); 3716 PetscCall(PetscSectionGetStorageSize(mesh->coneSection, &size)); 3717 PetscCall(PetscMalloc1(size, &mesh->cones)); 3718 PetscCall(PetscCalloc1(size, &mesh->coneOrientations)); 3719 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt))); 3720 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 3721 if (maxSupportSize) { 3722 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3723 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &size)); 3724 PetscCall(PetscMalloc1(size, &mesh->supports)); 3725 PetscCall(PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt))); 3726 } 3727 PetscFunctionReturn(0); 3728 } 3729 3730 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3731 { 3732 PetscFunctionBegin; 3733 if (subdm) PetscCall(DMClone(dm, subdm)); 3734 PetscCall(DMCreateSectionSubDM(dm, numFields, fields, is, subdm)); 3735 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3736 if (dm->useNatural && dm->sfMigration) { 3737 PetscSF sfMigrationInv,sfNatural; 3738 PetscSection section, sectionSeq; 3739 3740 (*subdm)->sfMigration = dm->sfMigration; 3741 PetscCall(PetscObjectReference((PetscObject) dm->sfMigration)); 3742 PetscCall(DMGetLocalSection((*subdm), §ion)); 3743 PetscCall(PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv)); 3744 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq)); 3745 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3746 3747 PetscCall(DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural)); 3748 (*subdm)->sfNatural = sfNatural; 3749 PetscCall(PetscSectionDestroy(§ionSeq)); 3750 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3751 } 3752 PetscFunctionReturn(0); 3753 } 3754 3755 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3756 { 3757 PetscInt i = 0; 3758 3759 PetscFunctionBegin; 3760 PetscCall(DMClone(dms[0], superdm)); 3761 PetscCall(DMCreateSectionSuperDM(dms, len, is, superdm)); 3762 (*superdm)->useNatural = PETSC_FALSE; 3763 for (i = 0; i < len; i++) { 3764 if (dms[i]->useNatural && dms[i]->sfMigration) { 3765 PetscSF sfMigrationInv,sfNatural; 3766 PetscSection section, sectionSeq; 3767 3768 (*superdm)->sfMigration = dms[i]->sfMigration; 3769 PetscCall(PetscObjectReference((PetscObject) dms[i]->sfMigration)); 3770 (*superdm)->useNatural = PETSC_TRUE; 3771 PetscCall(DMGetLocalSection((*superdm), §ion)); 3772 PetscCall(PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv)); 3773 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq)); 3774 PetscCall(PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq)); 3775 3776 PetscCall(DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural)); 3777 (*superdm)->sfNatural = sfNatural; 3778 PetscCall(PetscSectionDestroy(§ionSeq)); 3779 PetscCall(PetscSFDestroy(&sfMigrationInv)); 3780 break; 3781 } 3782 } 3783 PetscFunctionReturn(0); 3784 } 3785 3786 /*@ 3787 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3788 3789 Not collective 3790 3791 Input Parameter: 3792 . mesh - The DMPlex 3793 3794 Output Parameter: 3795 3796 Note: 3797 This should be called after all calls to DMPlexSetCone() 3798 3799 Level: beginner 3800 3801 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 3802 @*/ 3803 PetscErrorCode DMPlexSymmetrize(DM dm) 3804 { 3805 DM_Plex *mesh = (DM_Plex*) dm->data; 3806 PetscInt *offsets; 3807 PetscInt supportSize; 3808 PetscInt pStart, pEnd, p; 3809 3810 PetscFunctionBegin; 3811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3812 PetscCheck(!mesh->supports,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3813 PetscCall(PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0)); 3814 /* Calculate support sizes */ 3815 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3816 for (p = pStart; p < pEnd; ++p) { 3817 PetscInt dof, off, c; 3818 3819 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3820 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3821 for (c = off; c < off+dof; ++c) { 3822 PetscCall(PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1)); 3823 } 3824 } 3825 PetscCall(PetscSectionSetUp(mesh->supportSection)); 3826 /* Calculate supports */ 3827 PetscCall(PetscSectionGetStorageSize(mesh->supportSection, &supportSize)); 3828 PetscCall(PetscMalloc1(supportSize, &mesh->supports)); 3829 PetscCall(PetscCalloc1(pEnd - pStart, &offsets)); 3830 for (p = pStart; p < pEnd; ++p) { 3831 PetscInt dof, off, c; 3832 3833 PetscCall(PetscSectionGetDof(mesh->coneSection, p, &dof)); 3834 PetscCall(PetscSectionGetOffset(mesh->coneSection, p, &off)); 3835 for (c = off; c < off+dof; ++c) { 3836 const PetscInt q = mesh->cones[c]; 3837 PetscInt offS; 3838 3839 PetscCall(PetscSectionGetOffset(mesh->supportSection, q, &offS)); 3840 3841 mesh->supports[offS+offsets[q]] = p; 3842 ++offsets[q]; 3843 } 3844 } 3845 PetscCall(PetscFree(offsets)); 3846 PetscCall(PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0)); 3847 PetscFunctionReturn(0); 3848 } 3849 3850 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3851 { 3852 IS stratumIS; 3853 3854 PetscFunctionBegin; 3855 if (pStart >= pEnd) PetscFunctionReturn(0); 3856 if (PetscDefined(USE_DEBUG)) { 3857 PetscInt qStart, qEnd, numLevels, level; 3858 PetscBool overlap = PETSC_FALSE; 3859 PetscCall(DMLabelGetNumValues(label, &numLevels)); 3860 for (level = 0; level < numLevels; level++) { 3861 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3862 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3863 } 3864 PetscCheck(!overlap,PETSC_COMM_SELF, PETSC_ERR_PLIB, "New depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ") overlaps with depth %" PetscInt_FMT " range [%" PetscInt_FMT ",%" PetscInt_FMT ")", depth, pStart, pEnd, level, qStart, qEnd); 3865 } 3866 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS)); 3867 PetscCall(DMLabelSetStratumIS(label, depth, stratumIS)); 3868 PetscCall(ISDestroy(&stratumIS)); 3869 PetscFunctionReturn(0); 3870 } 3871 3872 /*@ 3873 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3874 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3875 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3876 the DAG. 3877 3878 Collective on dm 3879 3880 Input Parameter: 3881 . mesh - The DMPlex 3882 3883 Output Parameter: 3884 3885 Notes: 3886 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3887 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3888 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3889 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3890 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3891 3892 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3893 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3894 we had a mesh consisting of one triangle (c0) and three vertices (v0, v1, v2), and only one edge is on the boundary so we choose 3895 to interpolate only that one (e0), so that 3896 $ cone(c0) = {e0, v2} 3897 $ cone(e0) = {v0, v1} 3898 If DMPlexStratify() is run on this mesh, it will give depths 3899 $ depth 0 = {v0, v1, v2} 3900 $ depth 1 = {e0, c0} 3901 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3902 3903 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3904 3905 Level: beginner 3906 3907 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes() 3908 @*/ 3909 PetscErrorCode DMPlexStratify(DM dm) 3910 { 3911 DM_Plex *mesh = (DM_Plex*) dm->data; 3912 DMLabel label; 3913 PetscInt pStart, pEnd, p; 3914 PetscInt numRoots = 0, numLeaves = 0; 3915 3916 PetscFunctionBegin; 3917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3918 PetscCall(PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0)); 3919 3920 /* Create depth label */ 3921 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3922 PetscCall(DMCreateLabel(dm, "depth")); 3923 PetscCall(DMPlexGetDepthLabel(dm, &label)); 3924 3925 { 3926 /* Initialize roots and count leaves */ 3927 PetscInt sMin = PETSC_MAX_INT; 3928 PetscInt sMax = PETSC_MIN_INT; 3929 PetscInt coneSize, supportSize; 3930 3931 for (p = pStart; p < pEnd; ++p) { 3932 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3933 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3934 if (!coneSize && supportSize) { 3935 sMin = PetscMin(p, sMin); 3936 sMax = PetscMax(p, sMax); 3937 ++numRoots; 3938 } else if (!supportSize && coneSize) { 3939 ++numLeaves; 3940 } else if (!supportSize && !coneSize) { 3941 /* Isolated points */ 3942 sMin = PetscMin(p, sMin); 3943 sMax = PetscMax(p, sMax); 3944 } 3945 } 3946 PetscCall(DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1)); 3947 } 3948 3949 if (numRoots + numLeaves == (pEnd - pStart)) { 3950 PetscInt sMin = PETSC_MAX_INT; 3951 PetscInt sMax = PETSC_MIN_INT; 3952 PetscInt coneSize, supportSize; 3953 3954 for (p = pStart; p < pEnd; ++p) { 3955 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 3956 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 3957 if (!supportSize && coneSize) { 3958 sMin = PetscMin(p, sMin); 3959 sMax = PetscMax(p, sMax); 3960 } 3961 } 3962 PetscCall(DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1)); 3963 } else { 3964 PetscInt level = 0; 3965 PetscInt qStart, qEnd, q; 3966 3967 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3968 while (qEnd > qStart) { 3969 PetscInt sMin = PETSC_MAX_INT; 3970 PetscInt sMax = PETSC_MIN_INT; 3971 3972 for (q = qStart; q < qEnd; ++q) { 3973 const PetscInt *support; 3974 PetscInt supportSize, s; 3975 3976 PetscCall(DMPlexGetSupportSize(dm, q, &supportSize)); 3977 PetscCall(DMPlexGetSupport(dm, q, &support)); 3978 for (s = 0; s < supportSize; ++s) { 3979 sMin = PetscMin(support[s], sMin); 3980 sMax = PetscMax(support[s], sMax); 3981 } 3982 } 3983 PetscCall(DMLabelGetNumValues(label, &level)); 3984 PetscCall(DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1)); 3985 PetscCall(DMLabelGetStratumBounds(label, level, &qStart, &qEnd)); 3986 } 3987 } 3988 { /* just in case there is an empty process */ 3989 PetscInt numValues, maxValues = 0, v; 3990 3991 PetscCall(DMLabelGetNumValues(label, &numValues)); 3992 PetscCallMPI(MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 3993 for (v = numValues; v < maxValues; v++) { 3994 PetscCall(DMLabelAddStratum(label, v)); 3995 } 3996 } 3997 PetscCall(PetscObjectStateGet((PetscObject) label, &mesh->depthState)); 3998 PetscCall(PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0)); 3999 PetscFunctionReturn(0); 4000 } 4001 4002 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 4003 { 4004 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4005 PetscInt dim, depth, pheight, coneSize; 4006 4007 PetscFunctionBeginHot; 4008 PetscCall(DMGetDimension(dm, &dim)); 4009 PetscCall(DMPlexGetDepth(dm, &depth)); 4010 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 4011 pheight = depth - pdepth; 4012 if (depth <= 1) { 4013 switch (pdepth) { 4014 case 0: ct = DM_POLYTOPE_POINT;break; 4015 case 1: 4016 switch (coneSize) { 4017 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4018 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4019 case 4: 4020 switch (dim) { 4021 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 4022 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 4023 default: break; 4024 } 4025 break; 4026 case 5: ct = DM_POLYTOPE_PYRAMID;break; 4027 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4028 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 4029 default: break; 4030 } 4031 } 4032 } else { 4033 if (pdepth == 0) { 4034 ct = DM_POLYTOPE_POINT; 4035 } else if (pheight == 0) { 4036 switch (dim) { 4037 case 1: 4038 switch (coneSize) { 4039 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4040 default: break; 4041 } 4042 break; 4043 case 2: 4044 switch (coneSize) { 4045 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4046 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4047 default: break; 4048 } 4049 break; 4050 case 3: 4051 switch (coneSize) { 4052 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 4053 case 5: 4054 { 4055 const PetscInt *cone; 4056 PetscInt faceConeSize; 4057 4058 PetscCall(DMPlexGetCone(dm, p, &cone)); 4059 PetscCall(DMPlexGetConeSize(dm, cone[0], &faceConeSize)); 4060 switch (faceConeSize) { 4061 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 4062 case 4: ct = DM_POLYTOPE_PYRAMID;break; 4063 } 4064 } 4065 break; 4066 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 4067 default: break; 4068 } 4069 break; 4070 default: break; 4071 } 4072 } else if (pheight > 0) { 4073 switch (coneSize) { 4074 case 2: ct = DM_POLYTOPE_SEGMENT;break; 4075 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 4076 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 4077 default: break; 4078 } 4079 } 4080 } 4081 *pt = ct; 4082 PetscFunctionReturn(0); 4083 } 4084 4085 /*@ 4086 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 4087 4088 Collective on dm 4089 4090 Input Parameter: 4091 . mesh - The DMPlex 4092 4093 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 4094 4095 Level: developer 4096 4097 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 4098 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 4099 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 4100 4101 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel() 4102 @*/ 4103 PetscErrorCode DMPlexComputeCellTypes(DM dm) 4104 { 4105 DM_Plex *mesh; 4106 DMLabel ctLabel; 4107 PetscInt pStart, pEnd, p; 4108 4109 PetscFunctionBegin; 4110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4111 mesh = (DM_Plex *) dm->data; 4112 PetscCall(DMCreateLabel(dm, "celltype")); 4113 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 4114 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4115 for (p = pStart; p < pEnd; ++p) { 4116 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 4117 PetscInt pdepth; 4118 4119 PetscCall(DMPlexGetPointDepth(dm, p, &pdepth)); 4120 PetscCall(DMPlexComputeCellType_Internal(dm, p, pdepth, &ct)); 4121 PetscCheck(ct != DM_POLYTOPE_UNKNOWN,PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %" PetscInt_FMT " is screwed up", p); 4122 PetscCall(DMLabelSetValue(ctLabel, p, ct)); 4123 } 4124 PetscCall(PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState)); 4125 PetscCall(PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view")); 4126 PetscFunctionReturn(0); 4127 } 4128 4129 /*@C 4130 DMPlexGetJoin - Get an array for the join of the set of points 4131 4132 Not Collective 4133 4134 Input Parameters: 4135 + dm - The DMPlex object 4136 . numPoints - The number of input points for the join 4137 - points - The input points 4138 4139 Output Parameters: 4140 + numCoveredPoints - The number of points in the join 4141 - coveredPoints - The points in the join 4142 4143 Level: intermediate 4144 4145 Note: Currently, this is restricted to a single level join 4146 4147 Fortran Notes: 4148 Since it returns an array, this routine is only available in Fortran 90, and you must 4149 include petsc.h90 in your code. 4150 4151 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4152 4153 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 4154 @*/ 4155 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4156 { 4157 DM_Plex *mesh = (DM_Plex*) dm->data; 4158 PetscInt *join[2]; 4159 PetscInt joinSize, i = 0; 4160 PetscInt dof, off, p, c, m; 4161 PetscInt maxSupportSize; 4162 4163 PetscFunctionBegin; 4164 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4165 PetscValidIntPointer(points, 3); 4166 PetscValidIntPointer(numCoveredPoints, 4); 4167 PetscValidPointer(coveredPoints, 5); 4168 PetscCall(PetscSectionGetMaxDof(mesh->supportSection, &maxSupportSize)); 4169 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[0])); 4170 PetscCall(DMGetWorkArray(dm, maxSupportSize, MPIU_INT, &join[1])); 4171 /* Copy in support of first point */ 4172 PetscCall(PetscSectionGetDof(mesh->supportSection, points[0], &dof)); 4173 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[0], &off)); 4174 for (joinSize = 0; joinSize < dof; ++joinSize) { 4175 join[i][joinSize] = mesh->supports[off+joinSize]; 4176 } 4177 /* Check each successive support */ 4178 for (p = 1; p < numPoints; ++p) { 4179 PetscInt newJoinSize = 0; 4180 4181 PetscCall(PetscSectionGetDof(mesh->supportSection, points[p], &dof)); 4182 PetscCall(PetscSectionGetOffset(mesh->supportSection, points[p], &off)); 4183 for (c = 0; c < dof; ++c) { 4184 const PetscInt point = mesh->supports[off+c]; 4185 4186 for (m = 0; m < joinSize; ++m) { 4187 if (point == join[i][m]) { 4188 join[1-i][newJoinSize++] = point; 4189 break; 4190 } 4191 } 4192 } 4193 joinSize = newJoinSize; 4194 i = 1-i; 4195 } 4196 *numCoveredPoints = joinSize; 4197 *coveredPoints = join[i]; 4198 PetscCall(DMRestoreWorkArray(dm, maxSupportSize, MPIU_INT, &join[1-i])); 4199 PetscFunctionReturn(0); 4200 } 4201 4202 /*@C 4203 DMPlexRestoreJoin - Restore an array for the join of the set of points 4204 4205 Not Collective 4206 4207 Input Parameters: 4208 + dm - The DMPlex object 4209 . numPoints - The number of input points for the join 4210 - points - The input points 4211 4212 Output Parameters: 4213 + numCoveredPoints - The number of points in the join 4214 - coveredPoints - The points in the join 4215 4216 Fortran Notes: 4217 Since it returns an array, this routine is only available in Fortran 90, and you must 4218 include petsc.h90 in your code. 4219 4220 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4221 4222 Level: intermediate 4223 4224 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 4225 @*/ 4226 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4227 { 4228 PetscFunctionBegin; 4229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4230 if (points) PetscValidIntPointer(points,3); 4231 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4232 PetscValidPointer(coveredPoints, 5); 4233 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4234 if (numCoveredPoints) *numCoveredPoints = 0; 4235 PetscFunctionReturn(0); 4236 } 4237 4238 /*@C 4239 DMPlexGetFullJoin - Get an array for the join of the set of points 4240 4241 Not Collective 4242 4243 Input Parameters: 4244 + dm - The DMPlex object 4245 . numPoints - The number of input points for the join 4246 - points - The input points 4247 4248 Output Parameters: 4249 + numCoveredPoints - The number of points in the join 4250 - coveredPoints - The points in the join 4251 4252 Fortran Notes: 4253 Since it returns an array, this routine is only available in Fortran 90, and you must 4254 include petsc.h90 in your code. 4255 4256 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4257 4258 Level: intermediate 4259 4260 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 4261 @*/ 4262 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4263 { 4264 PetscInt *offsets, **closures; 4265 PetscInt *join[2]; 4266 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 4267 PetscInt p, d, c, m, ms; 4268 4269 PetscFunctionBegin; 4270 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4271 PetscValidIntPointer(points, 3); 4272 PetscValidIntPointer(numCoveredPoints, 4); 4273 PetscValidPointer(coveredPoints, 5); 4274 4275 PetscCall(DMPlexGetDepth(dm, &depth)); 4276 PetscCall(PetscCalloc1(numPoints, &closures)); 4277 PetscCall(DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4278 PetscCall(DMPlexGetMaxSizes(dm, NULL, &ms)); 4279 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 4280 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0])); 4281 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1])); 4282 4283 for (p = 0; p < numPoints; ++p) { 4284 PetscInt closureSize; 4285 4286 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p])); 4287 4288 offsets[p*(depth+2)+0] = 0; 4289 for (d = 0; d < depth+1; ++d) { 4290 PetscInt pStart, pEnd, i; 4291 4292 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 4293 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 4294 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4295 offsets[p*(depth+2)+d+1] = i; 4296 break; 4297 } 4298 } 4299 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 4300 } 4301 PetscCheck(offsets[p*(depth+2)+depth+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(depth+2)+depth+1], closureSize); 4302 } 4303 for (d = 0; d < depth+1; ++d) { 4304 PetscInt dof; 4305 4306 /* Copy in support of first point */ 4307 dof = offsets[d+1] - offsets[d]; 4308 for (joinSize = 0; joinSize < dof; ++joinSize) { 4309 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 4310 } 4311 /* Check each successive cone */ 4312 for (p = 1; p < numPoints && joinSize; ++p) { 4313 PetscInt newJoinSize = 0; 4314 4315 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 4316 for (c = 0; c < dof; ++c) { 4317 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 4318 4319 for (m = 0; m < joinSize; ++m) { 4320 if (point == join[i][m]) { 4321 join[1-i][newJoinSize++] = point; 4322 break; 4323 } 4324 } 4325 } 4326 joinSize = newJoinSize; 4327 i = 1-i; 4328 } 4329 if (joinSize) break; 4330 } 4331 *numCoveredPoints = joinSize; 4332 *coveredPoints = join[i]; 4333 for (p = 0; p < numPoints; ++p) { 4334 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p])); 4335 } 4336 PetscCall(PetscFree(closures)); 4337 PetscCall(DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets)); 4338 PetscCall(DMRestoreWorkArray(dm, ms, MPIU_INT, &join[1-i])); 4339 PetscFunctionReturn(0); 4340 } 4341 4342 /*@C 4343 DMPlexGetMeet - Get an array for the meet of the set of points 4344 4345 Not Collective 4346 4347 Input Parameters: 4348 + dm - The DMPlex object 4349 . numPoints - The number of input points for the meet 4350 - points - The input points 4351 4352 Output Parameters: 4353 + numCoveredPoints - The number of points in the meet 4354 - coveredPoints - The points in the meet 4355 4356 Level: intermediate 4357 4358 Note: Currently, this is restricted to a single level meet 4359 4360 Fortran Notes: 4361 Since it returns an array, this routine is only available in Fortran 90, and you must 4362 include petsc.h90 in your code. 4363 4364 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4365 4366 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 4367 @*/ 4368 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 4369 { 4370 DM_Plex *mesh = (DM_Plex*) dm->data; 4371 PetscInt *meet[2]; 4372 PetscInt meetSize, i = 0; 4373 PetscInt dof, off, p, c, m; 4374 PetscInt maxConeSize; 4375 4376 PetscFunctionBegin; 4377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4378 PetscValidIntPointer(points, 3); 4379 PetscValidIntPointer(numCoveringPoints, 4); 4380 PetscValidPointer(coveringPoints, 5); 4381 PetscCall(PetscSectionGetMaxDof(mesh->coneSection, &maxConeSize)); 4382 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[0])); 4383 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &meet[1])); 4384 /* Copy in cone of first point */ 4385 PetscCall(PetscSectionGetDof(mesh->coneSection, points[0], &dof)); 4386 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[0], &off)); 4387 for (meetSize = 0; meetSize < dof; ++meetSize) { 4388 meet[i][meetSize] = mesh->cones[off+meetSize]; 4389 } 4390 /* Check each successive cone */ 4391 for (p = 1; p < numPoints; ++p) { 4392 PetscInt newMeetSize = 0; 4393 4394 PetscCall(PetscSectionGetDof(mesh->coneSection, points[p], &dof)); 4395 PetscCall(PetscSectionGetOffset(mesh->coneSection, points[p], &off)); 4396 for (c = 0; c < dof; ++c) { 4397 const PetscInt point = mesh->cones[off+c]; 4398 4399 for (m = 0; m < meetSize; ++m) { 4400 if (point == meet[i][m]) { 4401 meet[1-i][newMeetSize++] = point; 4402 break; 4403 } 4404 } 4405 } 4406 meetSize = newMeetSize; 4407 i = 1-i; 4408 } 4409 *numCoveringPoints = meetSize; 4410 *coveringPoints = meet[i]; 4411 PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &meet[1-i])); 4412 PetscFunctionReturn(0); 4413 } 4414 4415 /*@C 4416 DMPlexRestoreMeet - Restore an array for the meet of the set of points 4417 4418 Not Collective 4419 4420 Input Parameters: 4421 + dm - The DMPlex object 4422 . numPoints - The number of input points for the meet 4423 - points - The input points 4424 4425 Output Parameters: 4426 + numCoveredPoints - The number of points in the meet 4427 - coveredPoints - The points in the meet 4428 4429 Level: intermediate 4430 4431 Fortran Notes: 4432 Since it returns an array, this routine is only available in Fortran 90, and you must 4433 include petsc.h90 in your code. 4434 4435 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4436 4437 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 4438 @*/ 4439 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4440 { 4441 PetscFunctionBegin; 4442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4443 if (points) PetscValidIntPointer(points,3); 4444 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 4445 PetscValidPointer(coveredPoints,5); 4446 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints)); 4447 if (numCoveredPoints) *numCoveredPoints = 0; 4448 PetscFunctionReturn(0); 4449 } 4450 4451 /*@C 4452 DMPlexGetFullMeet - Get an array for the meet of the set of points 4453 4454 Not Collective 4455 4456 Input Parameters: 4457 + dm - The DMPlex object 4458 . numPoints - The number of input points for the meet 4459 - points - The input points 4460 4461 Output Parameters: 4462 + numCoveredPoints - The number of points in the meet 4463 - coveredPoints - The points in the meet 4464 4465 Level: intermediate 4466 4467 Fortran Notes: 4468 Since it returns an array, this routine is only available in Fortran 90, and you must 4469 include petsc.h90 in your code. 4470 4471 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4472 4473 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 4474 @*/ 4475 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4476 { 4477 PetscInt *offsets, **closures; 4478 PetscInt *meet[2]; 4479 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4480 PetscInt p, h, c, m, mc; 4481 4482 PetscFunctionBegin; 4483 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4484 PetscValidIntPointer(points, 3); 4485 PetscValidIntPointer(numCoveredPoints, 4); 4486 PetscValidPointer(coveredPoints, 5); 4487 4488 PetscCall(DMPlexGetDepth(dm, &height)); 4489 PetscCall(PetscMalloc1(numPoints, &closures)); 4490 PetscCall(DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4491 PetscCall(DMPlexGetMaxSizes(dm, &mc, NULL)); 4492 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4493 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0])); 4494 PetscCall(DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1])); 4495 4496 for (p = 0; p < numPoints; ++p) { 4497 PetscInt closureSize; 4498 4499 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p])); 4500 4501 offsets[p*(height+2)+0] = 0; 4502 for (h = 0; h < height+1; ++h) { 4503 PetscInt pStart, pEnd, i; 4504 4505 PetscCall(DMPlexGetHeightStratum(dm, h, &pStart, &pEnd)); 4506 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4507 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4508 offsets[p*(height+2)+h+1] = i; 4509 break; 4510 } 4511 } 4512 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4513 } 4514 PetscCheck(offsets[p*(height+2)+height+1] == closureSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[p*(height+2)+height+1], closureSize); 4515 } 4516 for (h = 0; h < height+1; ++h) { 4517 PetscInt dof; 4518 4519 /* Copy in cone of first point */ 4520 dof = offsets[h+1] - offsets[h]; 4521 for (meetSize = 0; meetSize < dof; ++meetSize) { 4522 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4523 } 4524 /* Check each successive cone */ 4525 for (p = 1; p < numPoints && meetSize; ++p) { 4526 PetscInt newMeetSize = 0; 4527 4528 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4529 for (c = 0; c < dof; ++c) { 4530 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4531 4532 for (m = 0; m < meetSize; ++m) { 4533 if (point == meet[i][m]) { 4534 meet[1-i][newMeetSize++] = point; 4535 break; 4536 } 4537 } 4538 } 4539 meetSize = newMeetSize; 4540 i = 1-i; 4541 } 4542 if (meetSize) break; 4543 } 4544 *numCoveredPoints = meetSize; 4545 *coveredPoints = meet[i]; 4546 for (p = 0; p < numPoints; ++p) { 4547 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p])); 4548 } 4549 PetscCall(PetscFree(closures)); 4550 PetscCall(DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets)); 4551 PetscCall(DMRestoreWorkArray(dm, mc, MPIU_INT, &meet[1-i])); 4552 PetscFunctionReturn(0); 4553 } 4554 4555 /*@C 4556 DMPlexEqual - Determine if two DMs have the same topology 4557 4558 Not Collective 4559 4560 Input Parameters: 4561 + dmA - A DMPlex object 4562 - dmB - A DMPlex object 4563 4564 Output Parameters: 4565 . equal - PETSC_TRUE if the topologies are identical 4566 4567 Level: intermediate 4568 4569 Notes: 4570 We are not solving graph isomorphism, so we do not permutation. 4571 4572 .seealso: DMPlexGetCone() 4573 @*/ 4574 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4575 { 4576 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4577 4578 PetscFunctionBegin; 4579 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4580 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4581 PetscValidBoolPointer(equal, 3); 4582 4583 *equal = PETSC_FALSE; 4584 PetscCall(DMPlexGetDepth(dmA, &depth)); 4585 PetscCall(DMPlexGetDepth(dmB, &depthB)); 4586 if (depth != depthB) PetscFunctionReturn(0); 4587 PetscCall(DMPlexGetChart(dmA, &pStart, &pEnd)); 4588 PetscCall(DMPlexGetChart(dmB, &pStartB, &pEndB)); 4589 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4590 for (p = pStart; p < pEnd; ++p) { 4591 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4592 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4593 4594 PetscCall(DMPlexGetConeSize(dmA, p, &coneSize)); 4595 PetscCall(DMPlexGetCone(dmA, p, &cone)); 4596 PetscCall(DMPlexGetConeOrientation(dmA, p, &ornt)); 4597 PetscCall(DMPlexGetConeSize(dmB, p, &coneSizeB)); 4598 PetscCall(DMPlexGetCone(dmB, p, &coneB)); 4599 PetscCall(DMPlexGetConeOrientation(dmB, p, &orntB)); 4600 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4601 for (c = 0; c < coneSize; ++c) { 4602 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4603 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4604 } 4605 PetscCall(DMPlexGetSupportSize(dmA, p, &supportSize)); 4606 PetscCall(DMPlexGetSupport(dmA, p, &support)); 4607 PetscCall(DMPlexGetSupportSize(dmB, p, &supportSizeB)); 4608 PetscCall(DMPlexGetSupport(dmB, p, &supportB)); 4609 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4610 for (s = 0; s < supportSize; ++s) { 4611 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4612 } 4613 } 4614 *equal = PETSC_TRUE; 4615 PetscFunctionReturn(0); 4616 } 4617 4618 /*@C 4619 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4620 4621 Not Collective 4622 4623 Input Parameters: 4624 + dm - The DMPlex 4625 . cellDim - The cell dimension 4626 - numCorners - The number of vertices on a cell 4627 4628 Output Parameters: 4629 . numFaceVertices - The number of vertices on a face 4630 4631 Level: developer 4632 4633 Notes: 4634 Of course this can only work for a restricted set of symmetric shapes 4635 4636 .seealso: DMPlexGetCone() 4637 @*/ 4638 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4639 { 4640 MPI_Comm comm; 4641 4642 PetscFunctionBegin; 4643 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 4644 PetscValidIntPointer(numFaceVertices,4); 4645 switch (cellDim) { 4646 case 0: 4647 *numFaceVertices = 0; 4648 break; 4649 case 1: 4650 *numFaceVertices = 1; 4651 break; 4652 case 2: 4653 switch (numCorners) { 4654 case 3: /* triangle */ 4655 *numFaceVertices = 2; /* Edge has 2 vertices */ 4656 break; 4657 case 4: /* quadrilateral */ 4658 *numFaceVertices = 2; /* Edge has 2 vertices */ 4659 break; 4660 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4661 *numFaceVertices = 3; /* Edge has 3 vertices */ 4662 break; 4663 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4664 *numFaceVertices = 3; /* Edge has 3 vertices */ 4665 break; 4666 default: 4667 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4668 } 4669 break; 4670 case 3: 4671 switch (numCorners) { 4672 case 4: /* tetradehdron */ 4673 *numFaceVertices = 3; /* Face has 3 vertices */ 4674 break; 4675 case 6: /* tet cohesive cells */ 4676 *numFaceVertices = 4; /* Face has 4 vertices */ 4677 break; 4678 case 8: /* hexahedron */ 4679 *numFaceVertices = 4; /* Face has 4 vertices */ 4680 break; 4681 case 9: /* tet cohesive Lagrange cells */ 4682 *numFaceVertices = 6; /* Face has 6 vertices */ 4683 break; 4684 case 10: /* quadratic tetrahedron */ 4685 *numFaceVertices = 6; /* Face has 6 vertices */ 4686 break; 4687 case 12: /* hex cohesive Lagrange cells */ 4688 *numFaceVertices = 6; /* Face has 6 vertices */ 4689 break; 4690 case 18: /* quadratic tet cohesive Lagrange cells */ 4691 *numFaceVertices = 6; /* Face has 6 vertices */ 4692 break; 4693 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4694 *numFaceVertices = 9; /* Face has 9 vertices */ 4695 break; 4696 default: 4697 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %" PetscInt_FMT " for dimension %" PetscInt_FMT, numCorners, cellDim); 4698 } 4699 break; 4700 default: 4701 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %" PetscInt_FMT, cellDim); 4702 } 4703 PetscFunctionReturn(0); 4704 } 4705 4706 /*@ 4707 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4708 4709 Not Collective 4710 4711 Input Parameter: 4712 . dm - The DMPlex object 4713 4714 Output Parameter: 4715 . depthLabel - The DMLabel recording point depth 4716 4717 Level: developer 4718 4719 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), 4720 @*/ 4721 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4722 { 4723 PetscFunctionBegin; 4724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4725 PetscValidPointer(depthLabel, 2); 4726 *depthLabel = dm->depthLabel; 4727 PetscFunctionReturn(0); 4728 } 4729 4730 /*@ 4731 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4732 4733 Not Collective 4734 4735 Input Parameter: 4736 . dm - The DMPlex object 4737 4738 Output Parameter: 4739 . depth - The number of strata (breadth first levels) in the DAG 4740 4741 Level: developer 4742 4743 Notes: 4744 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4745 The point depth is described more in detail in DMPlexGetDepthStratum(). 4746 An empty mesh gives -1. 4747 4748 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize() 4749 @*/ 4750 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4751 { 4752 DMLabel label; 4753 PetscInt d = 0; 4754 4755 PetscFunctionBegin; 4756 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4757 PetscValidIntPointer(depth, 2); 4758 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4759 if (label) PetscCall(DMLabelGetNumValues(label, &d)); 4760 *depth = d-1; 4761 PetscFunctionReturn(0); 4762 } 4763 4764 /*@ 4765 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4766 4767 Not Collective 4768 4769 Input Parameters: 4770 + dm - The DMPlex object 4771 - stratumValue - The requested depth 4772 4773 Output Parameters: 4774 + start - The first point at this depth 4775 - end - One beyond the last point at this depth 4776 4777 Notes: 4778 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4779 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4780 higher dimension, e.g., "edges". 4781 4782 Level: developer 4783 4784 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate() 4785 @*/ 4786 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4787 { 4788 DMLabel label; 4789 PetscInt pStart, pEnd; 4790 4791 PetscFunctionBegin; 4792 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4793 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4794 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4795 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4796 if (pStart == pEnd) PetscFunctionReturn(0); 4797 if (stratumValue < 0) { 4798 if (start) *start = pStart; 4799 if (end) *end = pEnd; 4800 PetscFunctionReturn(0); 4801 } 4802 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4803 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4804 PetscCall(DMLabelGetStratumBounds(label, stratumValue, start, end)); 4805 PetscFunctionReturn(0); 4806 } 4807 4808 /*@ 4809 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4810 4811 Not Collective 4812 4813 Input Parameters: 4814 + dm - The DMPlex object 4815 - stratumValue - The requested height 4816 4817 Output Parameters: 4818 + start - The first point at this height 4819 - end - One beyond the last point at this height 4820 4821 Notes: 4822 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4823 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4824 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4825 4826 Level: developer 4827 4828 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight() 4829 @*/ 4830 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4831 { 4832 DMLabel label; 4833 PetscInt depth, pStart, pEnd; 4834 4835 PetscFunctionBegin; 4836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4837 if (start) {PetscValidIntPointer(start, 3); *start = 0;} 4838 if (end) {PetscValidIntPointer(end, 4); *end = 0;} 4839 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4840 if (pStart == pEnd) PetscFunctionReturn(0); 4841 if (stratumValue < 0) { 4842 if (start) *start = pStart; 4843 if (end) *end = pEnd; 4844 PetscFunctionReturn(0); 4845 } 4846 PetscCall(DMPlexGetDepthLabel(dm, &label)); 4847 PetscCheck(label,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4848 PetscCall(DMLabelGetNumValues(label, &depth)); 4849 PetscCall(DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end)); 4850 PetscFunctionReturn(0); 4851 } 4852 4853 /*@ 4854 DMPlexGetPointDepth - Get the depth of a given point 4855 4856 Not Collective 4857 4858 Input Parameters: 4859 + dm - The DMPlex object 4860 - point - The point 4861 4862 Output Parameter: 4863 . depth - The depth of the point 4864 4865 Level: intermediate 4866 4867 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight() 4868 @*/ 4869 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4870 { 4871 PetscFunctionBegin; 4872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4873 PetscValidIntPointer(depth, 3); 4874 PetscCall(DMLabelGetValue(dm->depthLabel, point, depth)); 4875 PetscFunctionReturn(0); 4876 } 4877 4878 /*@ 4879 DMPlexGetPointHeight - Get the height of a given point 4880 4881 Not Collective 4882 4883 Input Parameters: 4884 + dm - The DMPlex object 4885 - point - The point 4886 4887 Output Parameter: 4888 . height - The height of the point 4889 4890 Level: intermediate 4891 4892 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth() 4893 @*/ 4894 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4895 { 4896 PetscInt n, pDepth; 4897 4898 PetscFunctionBegin; 4899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4900 PetscValidIntPointer(height, 3); 4901 PetscCall(DMLabelGetNumValues(dm->depthLabel, &n)); 4902 PetscCall(DMLabelGetValue(dm->depthLabel, point, &pDepth)); 4903 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4904 PetscFunctionReturn(0); 4905 } 4906 4907 /*@ 4908 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4909 4910 Not Collective 4911 4912 Input Parameter: 4913 . dm - The DMPlex object 4914 4915 Output Parameter: 4916 . celltypeLabel - The DMLabel recording cell polytope type 4917 4918 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4919 DMCreateLabel(dm, "celltype") beforehand. 4920 4921 Level: developer 4922 4923 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel() 4924 @*/ 4925 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4926 { 4927 PetscFunctionBegin; 4928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4929 PetscValidPointer(celltypeLabel, 2); 4930 if (!dm->celltypeLabel) PetscCall(DMPlexComputeCellTypes(dm)); 4931 *celltypeLabel = dm->celltypeLabel; 4932 PetscFunctionReturn(0); 4933 } 4934 4935 /*@ 4936 DMPlexGetCellType - Get the polytope type of a given cell 4937 4938 Not Collective 4939 4940 Input Parameters: 4941 + dm - The DMPlex object 4942 - cell - The cell 4943 4944 Output Parameter: 4945 . celltype - The polytope type of the cell 4946 4947 Level: intermediate 4948 4949 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth() 4950 @*/ 4951 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4952 { 4953 DMLabel label; 4954 PetscInt ct; 4955 4956 PetscFunctionBegin; 4957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4958 PetscValidPointer(celltype, 3); 4959 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4960 PetscCall(DMLabelGetValue(label, cell, &ct)); 4961 PetscCheck(ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " has not been assigned a cell type", cell); 4962 *celltype = (DMPolytopeType) ct; 4963 PetscFunctionReturn(0); 4964 } 4965 4966 /*@ 4967 DMPlexSetCellType - Set the polytope type of a given cell 4968 4969 Not Collective 4970 4971 Input Parameters: 4972 + dm - The DMPlex object 4973 . cell - The cell 4974 - celltype - The polytope type of the cell 4975 4976 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4977 is executed. This function will override the computed type. However, if automatic classification will not succeed 4978 and a user wants to manually specify all types, the classification must be disabled by calling 4979 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4980 4981 Level: advanced 4982 4983 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel() 4984 @*/ 4985 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 4986 { 4987 DMLabel label; 4988 4989 PetscFunctionBegin; 4990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4991 PetscCall(DMPlexGetCellTypeLabel(dm, &label)); 4992 PetscCall(DMLabelSetValue(label, cell, celltype)); 4993 PetscFunctionReturn(0); 4994 } 4995 4996 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 4997 { 4998 PetscSection section, s; 4999 Mat m; 5000 PetscInt maxHeight; 5001 5002 PetscFunctionBegin; 5003 PetscCall(DMClone(dm, cdm)); 5004 PetscCall(DMPlexGetMaxProjectionHeight(dm, &maxHeight)); 5005 PetscCall(DMPlexSetMaxProjectionHeight(*cdm, maxHeight)); 5006 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 5007 PetscCall(DMSetLocalSection(*cdm, section)); 5008 PetscCall(PetscSectionDestroy(§ion)); 5009 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 5010 PetscCall(MatCreate(PETSC_COMM_SELF, &m)); 5011 PetscCall(DMSetDefaultConstraints(*cdm, s, m, NULL)); 5012 PetscCall(PetscSectionDestroy(&s)); 5013 PetscCall(MatDestroy(&m)); 5014 5015 PetscCall(DMSetNumFields(*cdm, 1)); 5016 PetscCall(DMCreateDS(*cdm)); 5017 PetscFunctionReturn(0); 5018 } 5019 5020 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 5021 { 5022 Vec coordsLocal; 5023 DM coordsDM; 5024 5025 PetscFunctionBegin; 5026 *field = NULL; 5027 PetscCall(DMGetCoordinatesLocal(dm,&coordsLocal)); 5028 PetscCall(DMGetCoordinateDM(dm,&coordsDM)); 5029 if (coordsLocal && coordsDM) { 5030 PetscCall(DMFieldCreateDS(coordsDM, 0, coordsLocal, field)); 5031 } 5032 PetscFunctionReturn(0); 5033 } 5034 5035 /*@C 5036 DMPlexGetConeSection - Return a section which describes the layout of cone data 5037 5038 Not Collective 5039 5040 Input Parameters: 5041 . dm - The DMPlex object 5042 5043 Output Parameter: 5044 . section - The PetscSection object 5045 5046 Level: developer 5047 5048 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations() 5049 @*/ 5050 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 5051 { 5052 DM_Plex *mesh = (DM_Plex*) dm->data; 5053 5054 PetscFunctionBegin; 5055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5056 if (section) *section = mesh->coneSection; 5057 PetscFunctionReturn(0); 5058 } 5059 5060 /*@C 5061 DMPlexGetSupportSection - Return a section which describes the layout of support data 5062 5063 Not Collective 5064 5065 Input Parameters: 5066 . dm - The DMPlex object 5067 5068 Output Parameter: 5069 . section - The PetscSection object 5070 5071 Level: developer 5072 5073 .seealso: DMPlexGetConeSection() 5074 @*/ 5075 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 5076 { 5077 DM_Plex *mesh = (DM_Plex*) dm->data; 5078 5079 PetscFunctionBegin; 5080 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5081 if (section) *section = mesh->supportSection; 5082 PetscFunctionReturn(0); 5083 } 5084 5085 /*@C 5086 DMPlexGetCones - Return cone data 5087 5088 Not Collective 5089 5090 Input Parameters: 5091 . dm - The DMPlex object 5092 5093 Output Parameter: 5094 . cones - The cone for each point 5095 5096 Level: developer 5097 5098 .seealso: DMPlexGetConeSection() 5099 @*/ 5100 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 5101 { 5102 DM_Plex *mesh = (DM_Plex*) dm->data; 5103 5104 PetscFunctionBegin; 5105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5106 if (cones) *cones = mesh->cones; 5107 PetscFunctionReturn(0); 5108 } 5109 5110 /*@C 5111 DMPlexGetConeOrientations - Return cone orientation data 5112 5113 Not Collective 5114 5115 Input Parameters: 5116 . dm - The DMPlex object 5117 5118 Output Parameter: 5119 . coneOrientations - The array of cone orientations for all points 5120 5121 Level: developer 5122 5123 Notes: 5124 The PetscSection returned by DMPlexGetConeSection() partitions coneOrientations into cone orientations of particular points as returned by DMPlexGetConeOrientation(). 5125 5126 The meaning of coneOrientations values is detailed in DMPlexGetConeOrientation(). 5127 5128 .seealso: DMPlexGetConeSection(), DMPlexGetConeOrientation() 5129 @*/ 5130 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 5131 { 5132 DM_Plex *mesh = (DM_Plex*) dm->data; 5133 5134 PetscFunctionBegin; 5135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5136 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 5137 PetscFunctionReturn(0); 5138 } 5139 5140 /******************************** FEM Support **********************************/ 5141 5142 /* 5143 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 5144 representing a line in the section. 5145 */ 5146 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 5147 { 5148 PetscFunctionBeginHot; 5149 PetscCall(PetscSectionGetFieldComponents(section, field, Nc)); 5150 if (line < 0) { 5151 *k = 0; 5152 *Nc = 0; 5153 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 5154 *k = 1; 5155 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 5156 /* An order k SEM disc has k-1 dofs on an edge */ 5157 PetscCall(PetscSectionGetFieldDof(section, line, field, k)); 5158 *k = *k / *Nc + 1; 5159 } 5160 PetscFunctionReturn(0); 5161 } 5162 5163 /*@ 5164 5165 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 5166 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 5167 section provided (or the section of the DM). 5168 5169 Input Parameters: 5170 + dm - The DM 5171 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 5172 - section - The PetscSection to reorder, or NULL for the default section 5173 5174 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 5175 degree of the basis. 5176 5177 Example: 5178 A typical interpolated single-quad mesh might order points as 5179 .vb 5180 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 5181 5182 v4 -- e6 -- v3 5183 | | 5184 e7 c0 e8 5185 | | 5186 v1 -- e5 -- v2 5187 .ve 5188 5189 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 5190 dofs in the order of points, e.g., 5191 .vb 5192 c0 -> [0,1,2,3] 5193 v1 -> [4] 5194 ... 5195 e5 -> [8, 9] 5196 .ve 5197 5198 which corresponds to the dofs 5199 .vb 5200 6 10 11 7 5201 13 2 3 15 5202 12 0 1 14 5203 4 8 9 5 5204 .ve 5205 5206 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 5207 .vb 5208 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 5209 .ve 5210 5211 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 5212 .vb 5213 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 5214 .ve 5215 5216 Level: developer 5217 5218 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection() 5219 @*/ 5220 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 5221 { 5222 DMLabel label; 5223 PetscInt dim, depth = -1, eStart = -1, Nf; 5224 PetscBool vertexchart; 5225 5226 PetscFunctionBegin; 5227 PetscCall(DMGetDimension(dm, &dim)); 5228 if (dim < 1) PetscFunctionReturn(0); 5229 if (point < 0) { 5230 PetscInt sStart,sEnd; 5231 5232 PetscCall(DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd)); 5233 point = sEnd-sStart ? sStart : point; 5234 } 5235 PetscCall(DMPlexGetDepthLabel(dm, &label)); 5236 if (point >= 0) PetscCall(DMLabelGetValue(label, point, &depth)); 5237 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5238 if (depth == 1) {eStart = point;} 5239 else if (depth == dim) { 5240 const PetscInt *cone; 5241 5242 PetscCall(DMPlexGetCone(dm, point, &cone)); 5243 if (dim == 2) eStart = cone[0]; 5244 else if (dim == 3) { 5245 const PetscInt *cone2; 5246 PetscCall(DMPlexGetCone(dm, cone[0], &cone2)); 5247 eStart = cone2[0]; 5248 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5249 } else PetscCheck(depth < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " of depth %" PetscInt_FMT " cannot be used to bootstrap spectral ordering for dim %" PetscInt_FMT, point, depth, dim); 5250 { /* Determine whether the chart covers all points or just vertices. */ 5251 PetscInt pStart,pEnd,cStart,cEnd; 5252 PetscCall(DMPlexGetDepthStratum(dm,0,&pStart,&pEnd)); 5253 PetscCall(PetscSectionGetChart(section,&cStart,&cEnd)); 5254 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Only vertices are in the chart */ 5255 else if (cStart <= point && point < cEnd) vertexchart = PETSC_FALSE; /* Some interpolated points exist in the chart */ 5256 else vertexchart = PETSC_TRUE; /* Some interpolated points are not in chart; assume dofs only at cells and vertices */ 5257 } 5258 PetscCall(PetscSectionGetNumFields(section, &Nf)); 5259 for (PetscInt d=1; d<=dim; d++) { 5260 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 5261 PetscInt *perm; 5262 5263 for (f = 0; f < Nf; ++f) { 5264 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5265 size += PetscPowInt(k+1, d)*Nc; 5266 } 5267 PetscCall(PetscMalloc1(size, &perm)); 5268 for (f = 0; f < Nf; ++f) { 5269 switch (d) { 5270 case 1: 5271 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5272 /* 5273 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 5274 We want [ vtx0; edge of length k-1; vtx1 ] 5275 */ 5276 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 5277 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 5278 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 5279 foffset = offset; 5280 break; 5281 case 2: 5282 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 5283 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5284 /* The SEM order is 5285 5286 v_lb, {e_b}, v_rb, 5287 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 5288 v_lt, reverse {e_t}, v_rt 5289 */ 5290 { 5291 const PetscInt of = 0; 5292 const PetscInt oeb = of + PetscSqr(k-1); 5293 const PetscInt oer = oeb + (k-1); 5294 const PetscInt oet = oer + (k-1); 5295 const PetscInt oel = oet + (k-1); 5296 const PetscInt ovlb = oel + (k-1); 5297 const PetscInt ovrb = ovlb + 1; 5298 const PetscInt ovrt = ovrb + 1; 5299 const PetscInt ovlt = ovrt + 1; 5300 PetscInt o; 5301 5302 /* bottom */ 5303 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 5304 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5305 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 5306 /* middle */ 5307 for (i = 0; i < k-1; ++i) { 5308 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 5309 for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5310 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 5311 } 5312 /* top */ 5313 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 5314 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5315 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 5316 foffset = offset; 5317 } 5318 break; 5319 case 3: 5320 /* The original hex closure is 5321 5322 {c, 5323 f_b, f_t, f_f, f_b, f_r, f_l, 5324 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 5325 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 5326 */ 5327 PetscCall(PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k)); 5328 /* The SEM order is 5329 Bottom Slice 5330 v_blf, {e^{(k-1)-n}_bf}, v_brf, 5331 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 5332 v_blb, {e_bb}, v_brb, 5333 5334 Middle Slice (j) 5335 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 5336 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 5337 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 5338 5339 Top Slice 5340 v_tlf, {e_tf}, v_trf, 5341 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 5342 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 5343 */ 5344 { 5345 const PetscInt oc = 0; 5346 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 5347 const PetscInt oft = ofb + PetscSqr(k-1); 5348 const PetscInt off = oft + PetscSqr(k-1); 5349 const PetscInt ofk = off + PetscSqr(k-1); 5350 const PetscInt ofr = ofk + PetscSqr(k-1); 5351 const PetscInt ofl = ofr + PetscSqr(k-1); 5352 const PetscInt oebl = ofl + PetscSqr(k-1); 5353 const PetscInt oebb = oebl + (k-1); 5354 const PetscInt oebr = oebb + (k-1); 5355 const PetscInt oebf = oebr + (k-1); 5356 const PetscInt oetf = oebf + (k-1); 5357 const PetscInt oetr = oetf + (k-1); 5358 const PetscInt oetb = oetr + (k-1); 5359 const PetscInt oetl = oetb + (k-1); 5360 const PetscInt oerf = oetl + (k-1); 5361 const PetscInt oelf = oerf + (k-1); 5362 const PetscInt oelb = oelf + (k-1); 5363 const PetscInt oerb = oelb + (k-1); 5364 const PetscInt ovblf = oerb + (k-1); 5365 const PetscInt ovblb = ovblf + 1; 5366 const PetscInt ovbrb = ovblb + 1; 5367 const PetscInt ovbrf = ovbrb + 1; 5368 const PetscInt ovtlf = ovbrf + 1; 5369 const PetscInt ovtrf = ovtlf + 1; 5370 const PetscInt ovtrb = ovtrf + 1; 5371 const PetscInt ovtlb = ovtrb + 1; 5372 PetscInt o, n; 5373 5374 /* Bottom Slice */ 5375 /* bottom */ 5376 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 5377 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5378 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 5379 /* middle */ 5380 for (i = 0; i < k-1; ++i) { 5381 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 5382 for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;} 5383 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 5384 } 5385 /* top */ 5386 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 5387 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5388 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 5389 5390 /* Middle Slice */ 5391 for (j = 0; j < k-1; ++j) { 5392 /* bottom */ 5393 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 5394 for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5395 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 5396 /* middle */ 5397 for (i = 0; i < k-1; ++i) { 5398 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 5399 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset; 5400 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 5401 } 5402 /* top */ 5403 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 5404 for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5405 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 5406 } 5407 5408 /* Top Slice */ 5409 /* bottom */ 5410 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 5411 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5412 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 5413 /* middle */ 5414 for (i = 0; i < k-1; ++i) { 5415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 5416 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 5417 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 5418 } 5419 /* top */ 5420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 5421 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 5422 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 5423 5424 foffset = offset; 5425 } 5426 break; 5427 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %" PetscInt_FMT, d); 5428 } 5429 } 5430 PetscCheck(offset == size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %" PetscInt_FMT " != %" PetscInt_FMT, offset, size); 5431 /* Check permutation */ 5432 { 5433 PetscInt *check; 5434 5435 PetscCall(PetscMalloc1(size, &check)); 5436 for (i = 0; i < size; ++i) {check[i] = -1; PetscCheckFalse(perm[i] < 0 || perm[i] >= size,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%" PetscInt_FMT "] = %" PetscInt_FMT, i, perm[i]);} 5437 for (i = 0; i < size; ++i) check[perm[i]] = i; 5438 for (i = 0; i < size; ++i) {PetscCheck(check[i] >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %" PetscInt_FMT, i);} 5439 PetscCall(PetscFree(check)); 5440 } 5441 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm)); 5442 if (d == dim) { // Add permutation for localized (in case this is a coordinate DM) 5443 PetscInt *loc_perm; 5444 PetscCall(PetscMalloc1(size*2, &loc_perm)); 5445 for (PetscInt i=0; i<size; i++) { 5446 loc_perm[i] = perm[i]; 5447 loc_perm[size+i] = size + perm[i]; 5448 } 5449 PetscCall(PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size*2, PETSC_OWN_POINTER, loc_perm)); 5450 } 5451 } 5452 PetscFunctionReturn(0); 5453 } 5454 5455 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5456 { 5457 PetscDS prob; 5458 PetscInt depth, Nf, h; 5459 DMLabel label; 5460 5461 PetscFunctionBeginHot; 5462 PetscCall(DMGetDS(dm, &prob)); 5463 Nf = prob->Nf; 5464 label = dm->depthLabel; 5465 *dspace = NULL; 5466 if (field < Nf) { 5467 PetscObject disc = prob->disc[field]; 5468 5469 if (disc->classid == PETSCFE_CLASSID) { 5470 PetscDualSpace dsp; 5471 5472 PetscCall(PetscFEGetDualSpace((PetscFE)disc,&dsp)); 5473 PetscCall(DMLabelGetNumValues(label,&depth)); 5474 PetscCall(DMLabelGetValue(label,point,&h)); 5475 h = depth - 1 - h; 5476 if (h) { 5477 PetscCall(PetscDualSpaceGetHeightSubspace(dsp,h,dspace)); 5478 } else { 5479 *dspace = dsp; 5480 } 5481 } 5482 } 5483 PetscFunctionReturn(0); 5484 } 5485 5486 static inline PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5487 { 5488 PetscScalar *array, *vArray; 5489 const PetscInt *cone, *coneO; 5490 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5491 5492 PetscFunctionBeginHot; 5493 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5494 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 5495 PetscCall(DMPlexGetCone(dm, point, &cone)); 5496 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 5497 if (!values || !*values) { 5498 if ((point >= pStart) && (point < pEnd)) { 5499 PetscInt dof; 5500 5501 PetscCall(PetscSectionGetDof(section, point, &dof)); 5502 size += dof; 5503 } 5504 for (p = 0; p < numPoints; ++p) { 5505 const PetscInt cp = cone[p]; 5506 PetscInt dof; 5507 5508 if ((cp < pStart) || (cp >= pEnd)) continue; 5509 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5510 size += dof; 5511 } 5512 if (!values) { 5513 if (csize) *csize = size; 5514 PetscFunctionReturn(0); 5515 } 5516 PetscCall(DMGetWorkArray(dm, size, MPIU_SCALAR, &array)); 5517 } else { 5518 array = *values; 5519 } 5520 size = 0; 5521 PetscCall(VecGetArray(v, &vArray)); 5522 if ((point >= pStart) && (point < pEnd)) { 5523 PetscInt dof, off, d; 5524 PetscScalar *varr; 5525 5526 PetscCall(PetscSectionGetDof(section, point, &dof)); 5527 PetscCall(PetscSectionGetOffset(section, point, &off)); 5528 varr = &vArray[off]; 5529 for (d = 0; d < dof; ++d, ++offset) { 5530 array[offset] = varr[d]; 5531 } 5532 size += dof; 5533 } 5534 for (p = 0; p < numPoints; ++p) { 5535 const PetscInt cp = cone[p]; 5536 PetscInt o = coneO[p]; 5537 PetscInt dof, off, d; 5538 PetscScalar *varr; 5539 5540 if ((cp < pStart) || (cp >= pEnd)) continue; 5541 PetscCall(PetscSectionGetDof(section, cp, &dof)); 5542 PetscCall(PetscSectionGetOffset(section, cp, &off)); 5543 varr = &vArray[off]; 5544 if (o >= 0) { 5545 for (d = 0; d < dof; ++d, ++offset) { 5546 array[offset] = varr[d]; 5547 } 5548 } else { 5549 for (d = dof-1; d >= 0; --d, ++offset) { 5550 array[offset] = varr[d]; 5551 } 5552 } 5553 size += dof; 5554 } 5555 PetscCall(VecRestoreArray(v, &vArray)); 5556 if (!*values) { 5557 if (csize) *csize = size; 5558 *values = array; 5559 } else { 5560 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5561 *csize = size; 5562 } 5563 PetscFunctionReturn(0); 5564 } 5565 5566 /* Compress out points not in the section */ 5567 static inline PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5568 { 5569 const PetscInt np = *numPoints; 5570 PetscInt pStart, pEnd, p, q; 5571 5572 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5573 for (p = 0, q = 0; p < np; ++p) { 5574 const PetscInt r = points[p*2]; 5575 if ((r >= pStart) && (r < pEnd)) { 5576 points[q*2] = r; 5577 points[q*2+1] = points[p*2+1]; 5578 ++q; 5579 } 5580 } 5581 *numPoints = q; 5582 return 0; 5583 } 5584 5585 /* Compressed closure does not apply closure permutation */ 5586 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5587 { 5588 const PetscInt *cla = NULL; 5589 PetscInt np, *pts = NULL; 5590 5591 PetscFunctionBeginHot; 5592 PetscCall(PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints)); 5593 if (*clPoints) { 5594 PetscInt dof, off; 5595 5596 PetscCall(PetscSectionGetDof(*clSec, point, &dof)); 5597 PetscCall(PetscSectionGetOffset(*clSec, point, &off)); 5598 PetscCall(ISGetIndices(*clPoints, &cla)); 5599 np = dof/2; 5600 pts = (PetscInt *) &cla[off]; 5601 } else { 5602 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts)); 5603 PetscCall(CompressPoints_Private(section, &np, pts)); 5604 } 5605 *numPoints = np; 5606 *points = pts; 5607 *clp = cla; 5608 PetscFunctionReturn(0); 5609 } 5610 5611 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5612 { 5613 PetscFunctionBeginHot; 5614 if (!*clPoints) { 5615 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points)); 5616 } else { 5617 PetscCall(ISRestoreIndices(*clPoints, clp)); 5618 } 5619 *numPoints = 0; 5620 *points = NULL; 5621 *clSec = NULL; 5622 *clPoints = NULL; 5623 *clp = NULL; 5624 PetscFunctionReturn(0); 5625 } 5626 5627 static inline PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 5628 { 5629 PetscInt offset = 0, p; 5630 const PetscInt **perms = NULL; 5631 const PetscScalar **flips = NULL; 5632 5633 PetscFunctionBeginHot; 5634 *size = 0; 5635 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 5636 for (p = 0; p < numPoints; p++) { 5637 const PetscInt point = points[2*p]; 5638 const PetscInt *perm = perms ? perms[p] : NULL; 5639 const PetscScalar *flip = flips ? flips[p] : NULL; 5640 PetscInt dof, off, d; 5641 const PetscScalar *varr; 5642 5643 PetscCall(PetscSectionGetDof(section, point, &dof)); 5644 PetscCall(PetscSectionGetOffset(section, point, &off)); 5645 varr = &vArray[off]; 5646 if (clperm) { 5647 if (perm) { 5648 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5649 } else { 5650 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5651 } 5652 if (flip) { 5653 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5654 } 5655 } else { 5656 if (perm) { 5657 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5658 } else { 5659 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5660 } 5661 if (flip) { 5662 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5663 } 5664 } 5665 offset += dof; 5666 } 5667 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 5668 *size = offset; 5669 PetscFunctionReturn(0); 5670 } 5671 5672 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[]) 5673 { 5674 PetscInt offset = 0, f; 5675 5676 PetscFunctionBeginHot; 5677 *size = 0; 5678 for (f = 0; f < numFields; ++f) { 5679 PetscInt p; 5680 const PetscInt **perms = NULL; 5681 const PetscScalar **flips = NULL; 5682 5683 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5684 for (p = 0; p < numPoints; p++) { 5685 const PetscInt point = points[2*p]; 5686 PetscInt fdof, foff, b; 5687 const PetscScalar *varr; 5688 const PetscInt *perm = perms ? perms[p] : NULL; 5689 const PetscScalar *flip = flips ? flips[p] : NULL; 5690 5691 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 5692 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 5693 varr = &vArray[foff]; 5694 if (clperm) { 5695 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5696 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5697 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5698 } else { 5699 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5700 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5701 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5702 } 5703 offset += fdof; 5704 } 5705 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 5706 } 5707 *size = offset; 5708 PetscFunctionReturn(0); 5709 } 5710 5711 /*@C 5712 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5713 5714 Not collective 5715 5716 Input Parameters: 5717 + dm - The DM 5718 . section - The section describing the layout in v, or NULL to use the default section 5719 . v - The local vector 5720 - point - The point in the DM 5721 5722 Input/Output Parameters: 5723 + csize - The size of the input values array, or NULL; on output the number of values in the closure 5724 - values - An array to use for the values, or NULL to have it allocated automatically; 5725 if the user provided NULL, it is a borrowed array and should not be freed 5726 5727 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5728 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5729 $ assembly function, and a user may already have allocated storage for this operation. 5730 $ 5731 $ A typical use could be 5732 $ 5733 $ values = NULL; 5734 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5735 $ for (cl = 0; cl < clSize; ++cl) { 5736 $ <Compute on closure> 5737 $ } 5738 $ PetscCall(DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values)); 5739 $ 5740 $ or 5741 $ 5742 $ PetscMalloc1(clMaxSize, &values); 5743 $ for (p = pStart; p < pEnd; ++p) { 5744 $ clSize = clMaxSize; 5745 $ PetscCall(DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values)); 5746 $ for (cl = 0; cl < clSize; ++cl) { 5747 $ <Compute on closure> 5748 $ } 5749 $ } 5750 $ PetscFree(values); 5751 5752 Fortran Notes: 5753 Since it returns an array, this routine is only available in Fortran 90, and you must 5754 include petsc.h90 in your code. 5755 5756 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5757 5758 Level: intermediate 5759 5760 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5761 @*/ 5762 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5763 { 5764 PetscSection clSection; 5765 IS clPoints; 5766 PetscInt *points = NULL; 5767 const PetscInt *clp, *perm; 5768 PetscInt depth, numFields, numPoints, asize; 5769 5770 PetscFunctionBeginHot; 5771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5772 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5773 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5774 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5775 PetscCall(DMPlexGetDepth(dm, &depth)); 5776 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5777 if (depth == 1 && numFields < 2) { 5778 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5779 PetscFunctionReturn(0); 5780 } 5781 /* Get points */ 5782 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5783 /* Get sizes */ 5784 asize = 0; 5785 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5786 PetscInt dof; 5787 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5788 asize += dof; 5789 } 5790 if (values) { 5791 const PetscScalar *vArray; 5792 PetscInt size; 5793 5794 if (*values) { 5795 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); 5796 } else PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, values)); 5797 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm)); 5798 PetscCall(VecGetArrayRead(v, &vArray)); 5799 /* Get values */ 5800 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values)); 5801 else PetscCall(DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values)); 5802 PetscCheck(asize == size,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %" PetscInt_FMT " does not match Vec closure size %" PetscInt_FMT, asize, size); 5803 /* Cleanup array */ 5804 PetscCall(VecRestoreArrayRead(v, &vArray)); 5805 } 5806 if (csize) *csize = asize; 5807 /* Cleanup points */ 5808 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5809 PetscFunctionReturn(0); 5810 } 5811 5812 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5813 { 5814 DMLabel depthLabel; 5815 PetscSection clSection; 5816 IS clPoints; 5817 PetscScalar *array; 5818 const PetscScalar *vArray; 5819 PetscInt *points = NULL; 5820 const PetscInt *clp, *perm = NULL; 5821 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5822 5823 PetscFunctionBeginHot; 5824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5825 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 5826 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5827 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5828 PetscCall(DMPlexGetDepth(dm, &mdepth)); 5829 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5830 PetscCall(PetscSectionGetNumFields(section, &numFields)); 5831 if (mdepth == 1 && numFields < 2) { 5832 PetscCall(DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values)); 5833 PetscFunctionReturn(0); 5834 } 5835 /* Get points */ 5836 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5837 for (clsize=0,p=0; p<Np; p++) { 5838 PetscInt dof; 5839 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 5840 clsize += dof; 5841 } 5842 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm)); 5843 /* Filter points */ 5844 for (p = 0; p < numPoints*2; p += 2) { 5845 PetscInt dep; 5846 5847 PetscCall(DMLabelGetValue(depthLabel, points[p], &dep)); 5848 if (dep != depth) continue; 5849 points[Np*2+0] = points[p]; 5850 points[Np*2+1] = points[p+1]; 5851 ++Np; 5852 } 5853 /* Get array */ 5854 if (!values || !*values) { 5855 PetscInt asize = 0, dof; 5856 5857 for (p = 0; p < Np*2; p += 2) { 5858 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 5859 asize += dof; 5860 } 5861 if (!values) { 5862 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5863 if (csize) *csize = asize; 5864 PetscFunctionReturn(0); 5865 } 5866 PetscCall(DMGetWorkArray(dm, asize, MPIU_SCALAR, &array)); 5867 } else { 5868 array = *values; 5869 } 5870 PetscCall(VecGetArrayRead(v, &vArray)); 5871 /* Get values */ 5872 if (numFields > 0) PetscCall(DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array)); 5873 else PetscCall(DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array)); 5874 /* Cleanup points */ 5875 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 5876 /* Cleanup array */ 5877 PetscCall(VecRestoreArrayRead(v, &vArray)); 5878 if (!*values) { 5879 if (csize) *csize = size; 5880 *values = array; 5881 } else { 5882 PetscCheck(size <= *csize,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %" PetscInt_FMT " < actual size %" PetscInt_FMT, *csize, size); 5883 *csize = size; 5884 } 5885 PetscFunctionReturn(0); 5886 } 5887 5888 /*@C 5889 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5890 5891 Not collective 5892 5893 Input Parameters: 5894 + dm - The DM 5895 . section - The section describing the layout in v, or NULL to use the default section 5896 . v - The local vector 5897 . point - The point in the DM 5898 . csize - The number of values in the closure, or NULL 5899 - values - The array of values, which is a borrowed array and should not be freed 5900 5901 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5902 5903 Fortran Notes: 5904 Since it returns an array, this routine is only available in Fortran 90, and you must 5905 include petsc.h90 in your code. 5906 5907 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5908 5909 Level: intermediate 5910 5911 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5912 @*/ 5913 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5914 { 5915 PetscInt size = 0; 5916 5917 PetscFunctionBegin; 5918 /* Should work without recalculating size */ 5919 PetscCall(DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values)); 5920 *values = NULL; 5921 PetscFunctionReturn(0); 5922 } 5923 5924 static inline void add (PetscScalar *x, PetscScalar y) {*x += y;} 5925 static inline void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5926 5927 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[]) 5928 { 5929 PetscInt cdof; /* The number of constraints on this point */ 5930 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5931 PetscScalar *a; 5932 PetscInt off, cind = 0, k; 5933 5934 PetscFunctionBegin; 5935 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5936 PetscCall(PetscSectionGetOffset(section, point, &off)); 5937 a = &array[off]; 5938 if (!cdof || setBC) { 5939 if (clperm) { 5940 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5941 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5942 } else { 5943 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5944 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5945 } 5946 } else { 5947 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5948 if (clperm) { 5949 if (perm) {for (k = 0; k < dof; ++k) { 5950 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5951 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5952 } 5953 } else { 5954 for (k = 0; k < dof; ++k) { 5955 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5956 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5957 } 5958 } 5959 } else { 5960 if (perm) { 5961 for (k = 0; k < dof; ++k) { 5962 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5963 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5964 } 5965 } else { 5966 for (k = 0; k < dof; ++k) { 5967 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5968 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5969 } 5970 } 5971 } 5972 } 5973 PetscFunctionReturn(0); 5974 } 5975 5976 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[]) 5977 { 5978 PetscInt cdof; /* The number of constraints on this point */ 5979 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5980 PetscScalar *a; 5981 PetscInt off, cind = 0, k; 5982 5983 PetscFunctionBegin; 5984 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 5985 PetscCall(PetscSectionGetOffset(section, point, &off)); 5986 a = &array[off]; 5987 if (cdof) { 5988 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 5989 if (clperm) { 5990 if (perm) { 5991 for (k = 0; k < dof; ++k) { 5992 if ((cind < cdof) && (k == cdofs[cind])) { 5993 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5994 cind++; 5995 } 5996 } 5997 } else { 5998 for (k = 0; k < dof; ++k) { 5999 if ((cind < cdof) && (k == cdofs[cind])) { 6000 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 6001 cind++; 6002 } 6003 } 6004 } 6005 } else { 6006 if (perm) { 6007 for (k = 0; k < dof; ++k) { 6008 if ((cind < cdof) && (k == cdofs[cind])) { 6009 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 6010 cind++; 6011 } 6012 } 6013 } else { 6014 for (k = 0; k < dof; ++k) { 6015 if ((cind < cdof) && (k == cdofs[cind])) { 6016 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 6017 cind++; 6018 } 6019 } 6020 } 6021 } 6022 } 6023 PetscFunctionReturn(0); 6024 } 6025 6026 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[]) 6027 { 6028 PetscScalar *a; 6029 PetscInt fdof, foff, fcdof, foffset = *offset; 6030 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6031 PetscInt cind = 0, b; 6032 6033 PetscFunctionBegin; 6034 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6035 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6036 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6037 a = &array[foff]; 6038 if (!fcdof || setBC) { 6039 if (clperm) { 6040 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 6041 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 6042 } else { 6043 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 6044 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 6045 } 6046 } else { 6047 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6048 if (clperm) { 6049 if (perm) { 6050 for (b = 0; b < fdof; b++) { 6051 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6052 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6053 } 6054 } else { 6055 for (b = 0; b < fdof; b++) { 6056 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6057 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6058 } 6059 } 6060 } else { 6061 if (perm) { 6062 for (b = 0; b < fdof; b++) { 6063 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6064 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6065 } 6066 } else { 6067 for (b = 0; b < fdof; b++) { 6068 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 6069 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6070 } 6071 } 6072 } 6073 } 6074 *offset += fdof; 6075 PetscFunctionReturn(0); 6076 } 6077 6078 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[]) 6079 { 6080 PetscScalar *a; 6081 PetscInt fdof, foff, fcdof, foffset = *offset; 6082 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6083 PetscInt Nc, cind = 0, ncind = 0, b; 6084 PetscBool ncSet, fcSet; 6085 6086 PetscFunctionBegin; 6087 PetscCall(PetscSectionGetFieldComponents(section, f, &Nc)); 6088 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6089 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &fcdof)); 6090 PetscCall(PetscSectionGetFieldOffset(section, point, f, &foff)); 6091 a = &array[foff]; 6092 if (fcdof) { 6093 /* We just override fcdof and fcdofs with Ncc and comps */ 6094 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6095 if (clperm) { 6096 if (perm) { 6097 if (comps) { 6098 for (b = 0; b < fdof; b++) { 6099 ncSet = fcSet = PETSC_FALSE; 6100 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6101 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6102 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 6103 } 6104 } else { 6105 for (b = 0; b < fdof; b++) { 6106 if ((cind < fcdof) && (b == fcdofs[cind])) { 6107 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 6108 ++cind; 6109 } 6110 } 6111 } 6112 } else { 6113 if (comps) { 6114 for (b = 0; b < fdof; b++) { 6115 ncSet = fcSet = PETSC_FALSE; 6116 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6117 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6118 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 6119 } 6120 } else { 6121 for (b = 0; b < fdof; b++) { 6122 if ((cind < fcdof) && (b == fcdofs[cind])) { 6123 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 6124 ++cind; 6125 } 6126 } 6127 } 6128 } 6129 } else { 6130 if (perm) { 6131 if (comps) { 6132 for (b = 0; b < fdof; b++) { 6133 ncSet = fcSet = PETSC_FALSE; 6134 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6135 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6136 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 6137 } 6138 } else { 6139 for (b = 0; b < fdof; b++) { 6140 if ((cind < fcdof) && (b == fcdofs[cind])) { 6141 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 6142 ++cind; 6143 } 6144 } 6145 } 6146 } else { 6147 if (comps) { 6148 for (b = 0; b < fdof; b++) { 6149 ncSet = fcSet = PETSC_FALSE; 6150 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 6151 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 6152 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 6153 } 6154 } else { 6155 for (b = 0; b < fdof; b++) { 6156 if ((cind < fcdof) && (b == fcdofs[cind])) { 6157 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 6158 ++cind; 6159 } 6160 } 6161 } 6162 } 6163 } 6164 } 6165 *offset += fdof; 6166 PetscFunctionReturn(0); 6167 } 6168 6169 static inline PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6170 { 6171 PetscScalar *array; 6172 const PetscInt *cone, *coneO; 6173 PetscInt pStart, pEnd, p, numPoints, off, dof; 6174 6175 PetscFunctionBeginHot; 6176 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6177 PetscCall(DMPlexGetConeSize(dm, point, &numPoints)); 6178 PetscCall(DMPlexGetCone(dm, point, &cone)); 6179 PetscCall(DMPlexGetConeOrientation(dm, point, &coneO)); 6180 PetscCall(VecGetArray(v, &array)); 6181 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 6182 const PetscInt cp = !p ? point : cone[p-1]; 6183 const PetscInt o = !p ? 0 : coneO[p-1]; 6184 6185 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 6186 PetscCall(PetscSectionGetDof(section, cp, &dof)); 6187 /* ADD_VALUES */ 6188 { 6189 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6190 PetscScalar *a; 6191 PetscInt cdof, coff, cind = 0, k; 6192 6193 PetscCall(PetscSectionGetConstraintDof(section, cp, &cdof)); 6194 PetscCall(PetscSectionGetOffset(section, cp, &coff)); 6195 a = &array[coff]; 6196 if (!cdof) { 6197 if (o >= 0) { 6198 for (k = 0; k < dof; ++k) { 6199 a[k] += values[off+k]; 6200 } 6201 } else { 6202 for (k = 0; k < dof; ++k) { 6203 a[k] += values[off+dof-k-1]; 6204 } 6205 } 6206 } else { 6207 PetscCall(PetscSectionGetConstraintIndices(section, cp, &cdofs)); 6208 if (o >= 0) { 6209 for (k = 0; k < dof; ++k) { 6210 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6211 a[k] += values[off+k]; 6212 } 6213 } else { 6214 for (k = 0; k < dof; ++k) { 6215 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 6216 a[k] += values[off+dof-k-1]; 6217 } 6218 } 6219 } 6220 } 6221 } 6222 PetscCall(VecRestoreArray(v, &array)); 6223 PetscFunctionReturn(0); 6224 } 6225 6226 /*@C 6227 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 6228 6229 Not collective 6230 6231 Input Parameters: 6232 + dm - The DM 6233 . section - The section describing the layout in v, or NULL to use the default section 6234 . v - The local vector 6235 . point - The point in the DM 6236 . values - The array of values 6237 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 6238 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 6239 6240 Fortran Notes: 6241 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6242 6243 Level: intermediate 6244 6245 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 6246 @*/ 6247 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 6248 { 6249 PetscSection clSection; 6250 IS clPoints; 6251 PetscScalar *array; 6252 PetscInt *points = NULL; 6253 const PetscInt *clp, *clperm = NULL; 6254 PetscInt depth, numFields, numPoints, p, clsize; 6255 6256 PetscFunctionBeginHot; 6257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6258 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6259 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6260 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6261 PetscCall(DMPlexGetDepth(dm, &depth)); 6262 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6263 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 6264 PetscCall(DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode)); 6265 PetscFunctionReturn(0); 6266 } 6267 /* Get points */ 6268 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6269 for (clsize=0,p=0; p<numPoints; p++) { 6270 PetscInt dof; 6271 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 6272 clsize += dof; 6273 } 6274 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 6275 /* Get array */ 6276 PetscCall(VecGetArray(v, &array)); 6277 /* Get values */ 6278 if (numFields > 0) { 6279 PetscInt offset = 0, f; 6280 for (f = 0; f < numFields; ++f) { 6281 const PetscInt **perms = NULL; 6282 const PetscScalar **flips = NULL; 6283 6284 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6285 switch (mode) { 6286 case INSERT_VALUES: 6287 for (p = 0; p < numPoints; p++) { 6288 const PetscInt point = points[2*p]; 6289 const PetscInt *perm = perms ? perms[p] : NULL; 6290 const PetscScalar *flip = flips ? flips[p] : NULL; 6291 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 6292 } break; 6293 case INSERT_ALL_VALUES: 6294 for (p = 0; p < numPoints; p++) { 6295 const PetscInt point = points[2*p]; 6296 const PetscInt *perm = perms ? perms[p] : NULL; 6297 const PetscScalar *flip = flips ? flips[p] : NULL; 6298 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 6299 } break; 6300 case INSERT_BC_VALUES: 6301 for (p = 0; p < numPoints; p++) { 6302 const PetscInt point = points[2*p]; 6303 const PetscInt *perm = perms ? perms[p] : NULL; 6304 const PetscScalar *flip = flips ? flips[p] : NULL; 6305 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 6306 } break; 6307 case ADD_VALUES: 6308 for (p = 0; p < numPoints; p++) { 6309 const PetscInt point = points[2*p]; 6310 const PetscInt *perm = perms ? perms[p] : NULL; 6311 const PetscScalar *flip = flips ? flips[p] : NULL; 6312 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 6313 } break; 6314 case ADD_ALL_VALUES: 6315 for (p = 0; p < numPoints; p++) { 6316 const PetscInt point = points[2*p]; 6317 const PetscInt *perm = perms ? perms[p] : NULL; 6318 const PetscScalar *flip = flips ? flips[p] : NULL; 6319 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 6320 } break; 6321 case ADD_BC_VALUES: 6322 for (p = 0; p < numPoints; p++) { 6323 const PetscInt point = points[2*p]; 6324 const PetscInt *perm = perms ? perms[p] : NULL; 6325 const PetscScalar *flip = flips ? flips[p] : NULL; 6326 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 6327 } break; 6328 default: 6329 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6330 } 6331 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6332 } 6333 } else { 6334 PetscInt dof, off; 6335 const PetscInt **perms = NULL; 6336 const PetscScalar **flips = NULL; 6337 6338 PetscCall(PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips)); 6339 switch (mode) { 6340 case INSERT_VALUES: 6341 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6342 const PetscInt point = points[2*p]; 6343 const PetscInt *perm = perms ? perms[p] : NULL; 6344 const PetscScalar *flip = flips ? flips[p] : NULL; 6345 PetscCall(PetscSectionGetDof(section, point, &dof)); 6346 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 6347 } break; 6348 case INSERT_ALL_VALUES: 6349 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6350 const PetscInt point = points[2*p]; 6351 const PetscInt *perm = perms ? perms[p] : NULL; 6352 const PetscScalar *flip = flips ? flips[p] : NULL; 6353 PetscCall(PetscSectionGetDof(section, point, &dof)); 6354 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 6355 } break; 6356 case INSERT_BC_VALUES: 6357 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6358 const PetscInt point = points[2*p]; 6359 const PetscInt *perm = perms ? perms[p] : NULL; 6360 const PetscScalar *flip = flips ? flips[p] : NULL; 6361 PetscCall(PetscSectionGetDof(section, point, &dof)); 6362 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 6363 } break; 6364 case ADD_VALUES: 6365 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6366 const PetscInt point = points[2*p]; 6367 const PetscInt *perm = perms ? perms[p] : NULL; 6368 const PetscScalar *flip = flips ? flips[p] : NULL; 6369 PetscCall(PetscSectionGetDof(section, point, &dof)); 6370 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6371 } break; 6372 case ADD_ALL_VALUES: 6373 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6374 const PetscInt point = points[2*p]; 6375 const PetscInt *perm = perms ? perms[p] : NULL; 6376 const PetscScalar *flip = flips ? flips[p] : NULL; 6377 PetscCall(PetscSectionGetDof(section, point, &dof)); 6378 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6379 } break; 6380 case ADD_BC_VALUES: 6381 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6382 const PetscInt point = points[2*p]; 6383 const PetscInt *perm = perms ? perms[p] : NULL; 6384 const PetscScalar *flip = flips ? flips[p] : NULL; 6385 PetscCall(PetscSectionGetDof(section, point, &dof)); 6386 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6387 } break; 6388 default: 6389 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6390 } 6391 PetscCall(PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips)); 6392 } 6393 /* Cleanup points */ 6394 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6395 /* Cleanup array */ 6396 PetscCall(VecRestoreArray(v, &array)); 6397 PetscFunctionReturn(0); 6398 } 6399 6400 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6401 static inline PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6402 { 6403 PetscFunctionBegin; 6404 if (label) { 6405 PetscInt val, fdof; 6406 6407 /* There is a problem with this: 6408 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6409 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6410 Thus I am only going to check val != -1, not val != labelId 6411 */ 6412 PetscCall(DMLabelGetValue(label, point, &val)); 6413 if (val < 0) { 6414 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6415 *offset += fdof; 6416 PetscFunctionReturn(1); 6417 } 6418 } 6419 PetscFunctionReturn(0); 6420 } 6421 6422 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6423 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) 6424 { 6425 PetscSection clSection; 6426 IS clPoints; 6427 PetscScalar *array; 6428 PetscInt *points = NULL; 6429 const PetscInt *clp; 6430 PetscInt numFields, numPoints, p; 6431 PetscInt offset = 0, f; 6432 6433 PetscFunctionBeginHot; 6434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6435 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 6436 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6437 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6438 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6439 /* Get points */ 6440 PetscCall(DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6441 /* Get array */ 6442 PetscCall(VecGetArray(v, &array)); 6443 /* Get values */ 6444 for (f = 0; f < numFields; ++f) { 6445 const PetscInt **perms = NULL; 6446 const PetscScalar **flips = NULL; 6447 6448 if (!fieldActive[f]) { 6449 for (p = 0; p < numPoints*2; p += 2) { 6450 PetscInt fdof; 6451 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 6452 offset += fdof; 6453 } 6454 continue; 6455 } 6456 PetscCall(PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6457 switch (mode) { 6458 case INSERT_VALUES: 6459 for (p = 0; p < numPoints; p++) { 6460 const PetscInt point = points[2*p]; 6461 const PetscInt *perm = perms ? perms[p] : NULL; 6462 const PetscScalar *flip = flips ? flips[p] : NULL; 6463 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6464 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array)); 6465 } break; 6466 case INSERT_ALL_VALUES: 6467 for (p = 0; p < numPoints; p++) { 6468 const PetscInt point = points[2*p]; 6469 const PetscInt *perm = perms ? perms[p] : NULL; 6470 const PetscScalar *flip = flips ? flips[p] : NULL; 6471 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6472 PetscCall(updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array)); 6473 } break; 6474 case INSERT_BC_VALUES: 6475 for (p = 0; p < numPoints; p++) { 6476 const PetscInt point = points[2*p]; 6477 const PetscInt *perm = perms ? perms[p] : NULL; 6478 const PetscScalar *flip = flips ? flips[p] : NULL; 6479 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6480 PetscCall(updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array)); 6481 } break; 6482 case ADD_VALUES: 6483 for (p = 0; p < numPoints; p++) { 6484 const PetscInt point = points[2*p]; 6485 const PetscInt *perm = perms ? perms[p] : NULL; 6486 const PetscScalar *flip = flips ? flips[p] : NULL; 6487 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6488 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array)); 6489 } break; 6490 case ADD_ALL_VALUES: 6491 for (p = 0; p < numPoints; p++) { 6492 const PetscInt point = points[2*p]; 6493 const PetscInt *perm = perms ? perms[p] : NULL; 6494 const PetscScalar *flip = flips ? flips[p] : NULL; 6495 if (CheckPoint_Private(label, labelId, section, point, f, &offset)) continue; 6496 PetscCall(updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array)); 6497 } break; 6498 default: 6499 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6500 } 6501 PetscCall(PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips)); 6502 } 6503 /* Cleanup points */ 6504 PetscCall(DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp)); 6505 /* Cleanup array */ 6506 PetscCall(VecRestoreArray(v, &array)); 6507 PetscFunctionReturn(0); 6508 } 6509 6510 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6511 { 6512 PetscMPIInt rank; 6513 PetscInt i, j; 6514 6515 PetscFunctionBegin; 6516 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 6517 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat for point %" PetscInt_FMT "\n", rank, point)); 6518 for (i = 0; i < numRIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, rindices[i])); 6519 for (i = 0; i < numCIndices; i++) PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, i, cindices[i])); 6520 numCIndices = numCIndices ? numCIndices : numRIndices; 6521 if (!values) PetscFunctionReturn(0); 6522 for (i = 0; i < numRIndices; i++) { 6523 PetscCall(PetscViewerASCIIPrintf(viewer, "[%d]", rank)); 6524 for (j = 0; j < numCIndices; j++) { 6525 #if defined(PETSC_USE_COMPLEX) 6526 PetscCall(PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]))); 6527 #else 6528 PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j])); 6529 #endif 6530 } 6531 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 6532 } 6533 PetscFunctionReturn(0); 6534 } 6535 6536 /* 6537 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6538 6539 Input Parameters: 6540 + section - The section for this data layout 6541 . islocal - Is the section (and thus indices being requested) local or global? 6542 . point - The point contributing dofs with these indices 6543 . off - The global offset of this point 6544 . loff - The local offset of each field 6545 . setBC - The flag determining whether to include indices of boundary values 6546 . perm - A permutation of the dofs on this point, or NULL 6547 - indperm - A permutation of the entire indices array, or NULL 6548 6549 Output Parameter: 6550 . indices - Indices for dofs on this point 6551 6552 Level: developer 6553 6554 Note: The indices could be local or global, depending on the value of 'off'. 6555 */ 6556 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6557 { 6558 PetscInt dof; /* The number of unknowns on this point */ 6559 PetscInt cdof; /* The number of constraints on this point */ 6560 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6561 PetscInt cind = 0, k; 6562 6563 PetscFunctionBegin; 6564 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6565 PetscCall(PetscSectionGetDof(section, point, &dof)); 6566 PetscCall(PetscSectionGetConstraintDof(section, point, &cdof)); 6567 if (!cdof || setBC) { 6568 for (k = 0; k < dof; ++k) { 6569 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6570 const PetscInt ind = indperm ? indperm[preind] : preind; 6571 6572 indices[ind] = off + k; 6573 } 6574 } else { 6575 PetscCall(PetscSectionGetConstraintIndices(section, point, &cdofs)); 6576 for (k = 0; k < dof; ++k) { 6577 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6578 const PetscInt ind = indperm ? indperm[preind] : preind; 6579 6580 if ((cind < cdof) && (k == cdofs[cind])) { 6581 /* Insert check for returning constrained indices */ 6582 indices[ind] = -(off+k+1); 6583 ++cind; 6584 } else { 6585 indices[ind] = off + k - (islocal ? 0 : cind); 6586 } 6587 } 6588 } 6589 *loff += dof; 6590 PetscFunctionReturn(0); 6591 } 6592 6593 /* 6594 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6595 6596 Input Parameters: 6597 + section - a section (global or local) 6598 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6599 . point - point within section 6600 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6601 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6602 . setBC - identify constrained (boundary condition) points via involution. 6603 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6604 . permsoff - offset 6605 - indperm - index permutation 6606 6607 Output Parameter: 6608 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6609 . indices - array to hold indices (as defined by section) of each dof associated with point 6610 6611 Notes: 6612 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6613 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6614 in the local vector. 6615 6616 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6617 significant). It is invalid to call with a global section and setBC=true. 6618 6619 Developer Note: 6620 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6621 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6622 offset could be obtained from the section instead of passing it explicitly as we do now. 6623 6624 Example: 6625 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6626 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6627 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6628 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. 6629 6630 Level: developer 6631 */ 6632 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[]) 6633 { 6634 PetscInt numFields, foff, f; 6635 6636 PetscFunctionBegin; 6637 PetscCheck(islocal || !setBC,PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6638 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6639 for (f = 0, foff = 0; f < numFields; ++f) { 6640 PetscInt fdof, cfdof; 6641 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6642 PetscInt cind = 0, b; 6643 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6644 6645 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6646 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6647 if (!cfdof || setBC) { 6648 for (b = 0; b < fdof; ++b) { 6649 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6650 const PetscInt ind = indperm ? indperm[preind] : preind; 6651 6652 indices[ind] = off+foff+b; 6653 } 6654 } else { 6655 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6656 for (b = 0; b < fdof; ++b) { 6657 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6658 const PetscInt ind = indperm ? indperm[preind] : preind; 6659 6660 if ((cind < cfdof) && (b == fcdofs[cind])) { 6661 indices[ind] = -(off+foff+b+1); 6662 ++cind; 6663 } else { 6664 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6665 } 6666 } 6667 } 6668 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6669 foffs[f] += fdof; 6670 } 6671 PetscFunctionReturn(0); 6672 } 6673 6674 /* 6675 This version believes the globalSection offsets for each field, rather than just the point offset 6676 6677 . foffs - The offset into 'indices' for each field, since it is segregated by field 6678 6679 Notes: 6680 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6681 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6682 */ 6683 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6684 { 6685 PetscInt numFields, foff, f; 6686 6687 PetscFunctionBegin; 6688 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6689 for (f = 0; f < numFields; ++f) { 6690 PetscInt fdof, cfdof; 6691 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6692 PetscInt cind = 0, b; 6693 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6694 6695 PetscCall(PetscSectionGetFieldDof(section, point, f, &fdof)); 6696 PetscCall(PetscSectionGetFieldConstraintDof(section, point, f, &cfdof)); 6697 PetscCall(PetscSectionGetFieldOffset(globalSection, point, f, &foff)); 6698 if (!cfdof) { 6699 for (b = 0; b < fdof; ++b) { 6700 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6701 const PetscInt ind = indperm ? indperm[preind] : preind; 6702 6703 indices[ind] = foff+b; 6704 } 6705 } else { 6706 PetscCall(PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs)); 6707 for (b = 0; b < fdof; ++b) { 6708 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6709 const PetscInt ind = indperm ? indperm[preind] : preind; 6710 6711 if ((cind < cfdof) && (b == fcdofs[cind])) { 6712 indices[ind] = -(foff+b+1); 6713 ++cind; 6714 } else { 6715 indices[ind] = foff+b-cind; 6716 } 6717 } 6718 } 6719 foffs[f] += fdof; 6720 } 6721 PetscFunctionReturn(0); 6722 } 6723 6724 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) 6725 { 6726 Mat cMat; 6727 PetscSection aSec, cSec; 6728 IS aIS; 6729 PetscInt aStart = -1, aEnd = -1; 6730 const PetscInt *anchors; 6731 PetscInt numFields, f, p, q, newP = 0; 6732 PetscInt newNumPoints = 0, newNumIndices = 0; 6733 PetscInt *newPoints, *indices, *newIndices; 6734 PetscInt maxAnchor, maxDof; 6735 PetscInt newOffsets[32]; 6736 PetscInt *pointMatOffsets[32]; 6737 PetscInt *newPointOffsets[32]; 6738 PetscScalar *pointMat[32]; 6739 PetscScalar *newValues=NULL,*tmpValues; 6740 PetscBool anyConstrained = PETSC_FALSE; 6741 6742 PetscFunctionBegin; 6743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6744 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6745 PetscCall(PetscSectionGetNumFields(section, &numFields)); 6746 6747 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 6748 /* if there are point-to-point constraints */ 6749 if (aSec) { 6750 PetscCall(PetscArrayzero(newOffsets, 32)); 6751 PetscCall(ISGetIndices(aIS,&anchors)); 6752 PetscCall(PetscSectionGetChart(aSec,&aStart,&aEnd)); 6753 /* figure out how many points are going to be in the new element matrix 6754 * (we allow double counting, because it's all just going to be summed 6755 * into the global matrix anyway) */ 6756 for (p = 0; p < 2*numPoints; p+=2) { 6757 PetscInt b = points[p]; 6758 PetscInt bDof = 0, bSecDof; 6759 6760 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6761 if (!bSecDof) { 6762 continue; 6763 } 6764 if (b >= aStart && b < aEnd) { 6765 PetscCall(PetscSectionGetDof(aSec,b,&bDof)); 6766 } 6767 if (bDof) { 6768 /* this point is constrained */ 6769 /* it is going to be replaced by its anchors */ 6770 PetscInt bOff, q; 6771 6772 anyConstrained = PETSC_TRUE; 6773 newNumPoints += bDof; 6774 PetscCall(PetscSectionGetOffset(aSec,b,&bOff)); 6775 for (q = 0; q < bDof; q++) { 6776 PetscInt a = anchors[bOff + q]; 6777 PetscInt aDof; 6778 6779 PetscCall(PetscSectionGetDof(section,a,&aDof)); 6780 newNumIndices += aDof; 6781 for (f = 0; f < numFields; ++f) { 6782 PetscInt fDof; 6783 6784 PetscCall(PetscSectionGetFieldDof(section, a, f, &fDof)); 6785 newOffsets[f+1] += fDof; 6786 } 6787 } 6788 } 6789 else { 6790 /* this point is not constrained */ 6791 newNumPoints++; 6792 newNumIndices += bSecDof; 6793 for (f = 0; f < numFields; ++f) { 6794 PetscInt fDof; 6795 6796 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6797 newOffsets[f+1] += fDof; 6798 } 6799 } 6800 } 6801 } 6802 if (!anyConstrained) { 6803 if (outNumPoints) *outNumPoints = 0; 6804 if (outNumIndices) *outNumIndices = 0; 6805 if (outPoints) *outPoints = NULL; 6806 if (outValues) *outValues = NULL; 6807 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6808 PetscFunctionReturn(0); 6809 } 6810 6811 if (outNumPoints) *outNumPoints = newNumPoints; 6812 if (outNumIndices) *outNumIndices = newNumIndices; 6813 6814 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6815 6816 if (!outPoints && !outValues) { 6817 if (offsets) { 6818 for (f = 0; f <= numFields; f++) { 6819 offsets[f] = newOffsets[f]; 6820 } 6821 } 6822 if (aSec) PetscCall(ISRestoreIndices(aIS,&anchors)); 6823 PetscFunctionReturn(0); 6824 } 6825 6826 PetscCheckFalse(numFields && newOffsets[numFields] != newNumIndices,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, newOffsets[numFields], newNumIndices); 6827 6828 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 6829 6830 /* workspaces */ 6831 if (numFields) { 6832 for (f = 0; f < numFields; f++) { 6833 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 6834 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 6835 } 6836 } 6837 else { 6838 PetscCall(DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 6839 PetscCall(DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0])); 6840 } 6841 6842 /* get workspaces for the point-to-point matrices */ 6843 if (numFields) { 6844 PetscInt totalOffset, totalMatOffset; 6845 6846 for (p = 0; p < numPoints; p++) { 6847 PetscInt b = points[2*p]; 6848 PetscInt bDof = 0, bSecDof; 6849 6850 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6851 if (!bSecDof) { 6852 for (f = 0; f < numFields; f++) { 6853 newPointOffsets[f][p + 1] = 0; 6854 pointMatOffsets[f][p + 1] = 0; 6855 } 6856 continue; 6857 } 6858 if (b >= aStart && b < aEnd) { 6859 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6860 } 6861 if (bDof) { 6862 for (f = 0; f < numFields; f++) { 6863 PetscInt fDof, q, bOff, allFDof = 0; 6864 6865 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6866 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6867 for (q = 0; q < bDof; q++) { 6868 PetscInt a = anchors[bOff + q]; 6869 PetscInt aFDof; 6870 6871 PetscCall(PetscSectionGetFieldDof(section, a, f, &aFDof)); 6872 allFDof += aFDof; 6873 } 6874 newPointOffsets[f][p+1] = allFDof; 6875 pointMatOffsets[f][p+1] = fDof * allFDof; 6876 } 6877 } 6878 else { 6879 for (f = 0; f < numFields; f++) { 6880 PetscInt fDof; 6881 6882 PetscCall(PetscSectionGetFieldDof(section, b, f, &fDof)); 6883 newPointOffsets[f][p+1] = fDof; 6884 pointMatOffsets[f][p+1] = 0; 6885 } 6886 } 6887 } 6888 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6889 newPointOffsets[f][0] = totalOffset; 6890 pointMatOffsets[f][0] = totalMatOffset; 6891 for (p = 0; p < numPoints; p++) { 6892 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6893 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6894 } 6895 totalOffset = newPointOffsets[f][numPoints]; 6896 totalMatOffset = pointMatOffsets[f][numPoints]; 6897 PetscCall(DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 6898 } 6899 } 6900 else { 6901 for (p = 0; p < numPoints; p++) { 6902 PetscInt b = points[2*p]; 6903 PetscInt bDof = 0, bSecDof; 6904 6905 PetscCall(PetscSectionGetDof(section,b,&bSecDof)); 6906 if (!bSecDof) { 6907 newPointOffsets[0][p + 1] = 0; 6908 pointMatOffsets[0][p + 1] = 0; 6909 continue; 6910 } 6911 if (b >= aStart && b < aEnd) { 6912 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6913 } 6914 if (bDof) { 6915 PetscInt bOff, q, allDof = 0; 6916 6917 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6918 for (q = 0; q < bDof; q++) { 6919 PetscInt a = anchors[bOff + q], aDof; 6920 6921 PetscCall(PetscSectionGetDof(section, a, &aDof)); 6922 allDof += aDof; 6923 } 6924 newPointOffsets[0][p+1] = allDof; 6925 pointMatOffsets[0][p+1] = bSecDof * allDof; 6926 } 6927 else { 6928 newPointOffsets[0][p+1] = bSecDof; 6929 pointMatOffsets[0][p+1] = 0; 6930 } 6931 } 6932 newPointOffsets[0][0] = 0; 6933 pointMatOffsets[0][0] = 0; 6934 for (p = 0; p < numPoints; p++) { 6935 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6936 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6937 } 6938 PetscCall(DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 6939 } 6940 6941 /* output arrays */ 6942 PetscCall(DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 6943 6944 /* get the point-to-point matrices; construct newPoints */ 6945 PetscCall(PetscSectionGetMaxDof(aSec, &maxAnchor)); 6946 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 6947 PetscCall(DMGetWorkArray(dm,maxDof,MPIU_INT,&indices)); 6948 PetscCall(DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 6949 if (numFields) { 6950 for (p = 0, newP = 0; p < numPoints; p++) { 6951 PetscInt b = points[2*p]; 6952 PetscInt o = points[2*p+1]; 6953 PetscInt bDof = 0, bSecDof; 6954 6955 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 6956 if (!bSecDof) { 6957 continue; 6958 } 6959 if (b >= aStart && b < aEnd) { 6960 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 6961 } 6962 if (bDof) { 6963 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6964 6965 fStart[0] = 0; 6966 fEnd[0] = 0; 6967 for (f = 0; f < numFields; f++) { 6968 PetscInt fDof; 6969 6970 PetscCall(PetscSectionGetFieldDof(cSec, b, f, &fDof)); 6971 fStart[f+1] = fStart[f] + fDof; 6972 fEnd[f+1] = fStart[f+1]; 6973 } 6974 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 6975 PetscCall(DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices)); 6976 6977 fAnchorStart[0] = 0; 6978 fAnchorEnd[0] = 0; 6979 for (f = 0; f < numFields; f++) { 6980 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6981 6982 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 6983 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 6984 } 6985 PetscCall(PetscSectionGetOffset(aSec, b, &bOff)); 6986 for (q = 0; q < bDof; q++) { 6987 PetscInt a = anchors[bOff + q], aOff; 6988 6989 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6990 newPoints[2*(newP + q)] = a; 6991 newPoints[2*(newP + q) + 1] = 0; 6992 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 6993 PetscCall(DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices)); 6994 } 6995 newP += bDof; 6996 6997 if (outValues) { 6998 /* get the point-to-point submatrix */ 6999 for (f = 0; f < numFields; f++) { 7000 PetscCall(MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p])); 7001 } 7002 } 7003 } 7004 else { 7005 newPoints[2 * newP] = b; 7006 newPoints[2 * newP + 1] = o; 7007 newP++; 7008 } 7009 } 7010 } else { 7011 for (p = 0; p < numPoints; p++) { 7012 PetscInt b = points[2*p]; 7013 PetscInt o = points[2*p+1]; 7014 PetscInt bDof = 0, bSecDof; 7015 7016 PetscCall(PetscSectionGetDof(section, b, &bSecDof)); 7017 if (!bSecDof) { 7018 continue; 7019 } 7020 if (b >= aStart && b < aEnd) { 7021 PetscCall(PetscSectionGetDof(aSec, b, &bDof)); 7022 } 7023 if (bDof) { 7024 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 7025 7026 PetscCall(PetscSectionGetOffset(cSec, b, &bOff)); 7027 PetscCall(DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices)); 7028 7029 PetscCall(PetscSectionGetOffset (aSec, b, &bOff)); 7030 for (q = 0; q < bDof; q++) { 7031 PetscInt a = anchors[bOff + q], aOff; 7032 7033 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 7034 7035 newPoints[2*(newP + q)] = a; 7036 newPoints[2*(newP + q) + 1] = 0; 7037 PetscCall(PetscSectionGetOffset(section, a, &aOff)); 7038 PetscCall(DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices)); 7039 } 7040 newP += bDof; 7041 7042 /* get the point-to-point submatrix */ 7043 if (outValues) { 7044 PetscCall(MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p])); 7045 } 7046 } 7047 else { 7048 newPoints[2 * newP] = b; 7049 newPoints[2 * newP + 1] = o; 7050 newP++; 7051 } 7052 } 7053 } 7054 7055 if (outValues) { 7056 PetscCall(DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7057 PetscCall(PetscArrayzero(tmpValues,newNumIndices*numIndices)); 7058 /* multiply constraints on the right */ 7059 if (numFields) { 7060 for (f = 0; f < numFields; f++) { 7061 PetscInt oldOff = offsets[f]; 7062 7063 for (p = 0; p < numPoints; p++) { 7064 PetscInt cStart = newPointOffsets[f][p]; 7065 PetscInt b = points[2 * p]; 7066 PetscInt c, r, k; 7067 PetscInt dof; 7068 7069 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7070 if (!dof) { 7071 continue; 7072 } 7073 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7074 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 7075 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 7076 7077 for (r = 0; r < numIndices; r++) { 7078 for (c = 0; c < nCols; c++) { 7079 for (k = 0; k < dof; k++) { 7080 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 7081 } 7082 } 7083 } 7084 } 7085 else { 7086 /* copy this column as is */ 7087 for (r = 0; r < numIndices; r++) { 7088 for (c = 0; c < dof; c++) { 7089 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7090 } 7091 } 7092 } 7093 oldOff += dof; 7094 } 7095 } 7096 } 7097 else { 7098 PetscInt oldOff = 0; 7099 for (p = 0; p < numPoints; p++) { 7100 PetscInt cStart = newPointOffsets[0][p]; 7101 PetscInt b = points[2 * p]; 7102 PetscInt c, r, k; 7103 PetscInt dof; 7104 7105 PetscCall(PetscSectionGetDof(section,b,&dof)); 7106 if (!dof) { 7107 continue; 7108 } 7109 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7110 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 7111 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 7112 7113 for (r = 0; r < numIndices; r++) { 7114 for (c = 0; c < nCols; c++) { 7115 for (k = 0; k < dof; k++) { 7116 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 7117 } 7118 } 7119 } 7120 } 7121 else { 7122 /* copy this column as is */ 7123 for (r = 0; r < numIndices; r++) { 7124 for (c = 0; c < dof; c++) { 7125 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 7126 } 7127 } 7128 } 7129 oldOff += dof; 7130 } 7131 } 7132 7133 if (multiplyLeft) { 7134 PetscCall(DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues)); 7135 PetscCall(PetscArrayzero(newValues,newNumIndices*newNumIndices)); 7136 /* multiply constraints transpose on the left */ 7137 if (numFields) { 7138 for (f = 0; f < numFields; f++) { 7139 PetscInt oldOff = offsets[f]; 7140 7141 for (p = 0; p < numPoints; p++) { 7142 PetscInt rStart = newPointOffsets[f][p]; 7143 PetscInt b = points[2 * p]; 7144 PetscInt c, r, k; 7145 PetscInt dof; 7146 7147 PetscCall(PetscSectionGetFieldDof(section,b,f,&dof)); 7148 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 7149 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 7150 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 7151 7152 for (r = 0; r < nRows; r++) { 7153 for (c = 0; c < newNumIndices; c++) { 7154 for (k = 0; k < dof; k++) { 7155 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7156 } 7157 } 7158 } 7159 } 7160 else { 7161 /* copy this row as is */ 7162 for (r = 0; r < dof; r++) { 7163 for (c = 0; c < newNumIndices; c++) { 7164 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7165 } 7166 } 7167 } 7168 oldOff += dof; 7169 } 7170 } 7171 } 7172 else { 7173 PetscInt oldOff = 0; 7174 7175 for (p = 0; p < numPoints; p++) { 7176 PetscInt rStart = newPointOffsets[0][p]; 7177 PetscInt b = points[2 * p]; 7178 PetscInt c, r, k; 7179 PetscInt dof; 7180 7181 PetscCall(PetscSectionGetDof(section,b,&dof)); 7182 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 7183 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 7184 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 7185 7186 for (r = 0; r < nRows; r++) { 7187 for (c = 0; c < newNumIndices; c++) { 7188 for (k = 0; k < dof; k++) { 7189 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 7190 } 7191 } 7192 } 7193 } 7194 else { 7195 /* copy this row as is */ 7196 for (r = 0; r < dof; r++) { 7197 for (c = 0; c < newNumIndices; c++) { 7198 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 7199 } 7200 } 7201 } 7202 oldOff += dof; 7203 } 7204 } 7205 7206 PetscCall(DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues)); 7207 } 7208 else { 7209 newValues = tmpValues; 7210 } 7211 } 7212 7213 /* clean up */ 7214 PetscCall(DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices)); 7215 PetscCall(DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices)); 7216 7217 if (numFields) { 7218 for (f = 0; f < numFields; f++) { 7219 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f])); 7220 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f])); 7221 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f])); 7222 } 7223 } 7224 else { 7225 PetscCall(DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0])); 7226 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0])); 7227 PetscCall(DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0])); 7228 } 7229 PetscCall(ISRestoreIndices(aIS,&anchors)); 7230 7231 /* output */ 7232 if (outPoints) { 7233 *outPoints = newPoints; 7234 } 7235 else { 7236 PetscCall(DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints)); 7237 } 7238 if (outValues) { 7239 *outValues = newValues; 7240 } 7241 for (f = 0; f <= numFields; f++) { 7242 offsets[f] = newOffsets[f]; 7243 } 7244 PetscFunctionReturn(0); 7245 } 7246 7247 /*@C 7248 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 7249 7250 Not collective 7251 7252 Input Parameters: 7253 + dm - The DM 7254 . section - The PetscSection describing the points (a local section) 7255 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7256 . point - The point defining the closure 7257 - useClPerm - Use the closure point permutation if available 7258 7259 Output Parameters: 7260 + numIndices - The number of dof indices in the closure of point with the input sections 7261 . indices - The dof indices 7262 . outOffsets - Array to write the field offsets into, or NULL 7263 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7264 7265 Notes: 7266 Must call DMPlexRestoreClosureIndices() to free allocated memory 7267 7268 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7269 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7270 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7271 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7272 indices (with the above semantics) are implied. 7273 7274 Level: advanced 7275 7276 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 7277 @*/ 7278 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7279 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7280 { 7281 /* Closure ordering */ 7282 PetscSection clSection; 7283 IS clPoints; 7284 const PetscInt *clp; 7285 PetscInt *points; 7286 const PetscInt *clperm = NULL; 7287 /* Dof permutation and sign flips */ 7288 const PetscInt **perms[32] = {NULL}; 7289 const PetscScalar **flips[32] = {NULL}; 7290 PetscScalar *valCopy = NULL; 7291 /* Hanging node constraints */ 7292 PetscInt *pointsC = NULL; 7293 PetscScalar *valuesC = NULL; 7294 PetscInt NclC, NiC; 7295 7296 PetscInt *idx; 7297 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 7298 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 7299 7300 PetscFunctionBeginHot; 7301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7302 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7303 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 7304 if (numIndices) PetscValidIntPointer(numIndices, 6); 7305 if (indices) PetscValidPointer(indices, 7); 7306 if (outOffsets) PetscValidIntPointer(outOffsets, 8); 7307 if (values) PetscValidPointer(values, 9); 7308 PetscCall(PetscSectionGetNumFields(section, &Nf)); 7309 PetscCheck(Nf <= 31,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", Nf); 7310 PetscCall(PetscArrayzero(offsets, 32)); 7311 /* 1) Get points in closure */ 7312 PetscCall(DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7313 if (useClPerm) { 7314 PetscInt depth, clsize; 7315 PetscCall(DMPlexGetPointDepth(dm, point, &depth)); 7316 for (clsize=0,p=0; p<Ncl; p++) { 7317 PetscInt dof; 7318 PetscCall(PetscSectionGetDof(section, points[2*p], &dof)); 7319 clsize += dof; 7320 } 7321 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm)); 7322 } 7323 /* 2) Get number of indices on these points and field offsets from section */ 7324 for (p = 0; p < Ncl*2; p += 2) { 7325 PetscInt dof, fdof; 7326 7327 PetscCall(PetscSectionGetDof(section, points[p], &dof)); 7328 for (f = 0; f < Nf; ++f) { 7329 PetscCall(PetscSectionGetFieldDof(section, points[p], f, &fdof)); 7330 offsets[f+1] += fdof; 7331 } 7332 Ni += dof; 7333 } 7334 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 7335 PetscCheckFalse(Nf && offsets[Nf] != Ni,PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, offsets[Nf], Ni); 7336 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 7337 for (f = 0; f < PetscMax(1, Nf); ++f) { 7338 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7339 else PetscCall(PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f])); 7340 /* may need to apply sign changes to the element matrix */ 7341 if (values && flips[f]) { 7342 PetscInt foffset = offsets[f]; 7343 7344 for (p = 0; p < Ncl; ++p) { 7345 PetscInt pnt = points[2*p], fdof; 7346 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 7347 7348 if (!Nf) PetscCall(PetscSectionGetDof(section, pnt, &fdof)); 7349 else PetscCall(PetscSectionGetFieldDof(section, pnt, f, &fdof)); 7350 if (flip) { 7351 PetscInt i, j, k; 7352 7353 if (!valCopy) { 7354 PetscCall(DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7355 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 7356 *values = valCopy; 7357 } 7358 for (i = 0; i < fdof; ++i) { 7359 PetscScalar fval = flip[i]; 7360 7361 for (k = 0; k < Ni; ++k) { 7362 valCopy[Ni * (foffset + i) + k] *= fval; 7363 valCopy[Ni * k + (foffset + i)] *= fval; 7364 } 7365 } 7366 } 7367 foffset += fdof; 7368 } 7369 } 7370 } 7371 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7372 PetscCall(DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE)); 7373 if (NclC) { 7374 if (valCopy) PetscCall(DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy)); 7375 for (f = 0; f < PetscMax(1, Nf); ++f) { 7376 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7377 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7378 } 7379 for (f = 0; f < PetscMax(1, Nf); ++f) { 7380 if (Nf) PetscCall(PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f])); 7381 else PetscCall(PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f])); 7382 } 7383 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7384 Ncl = NclC; 7385 Ni = NiC; 7386 points = pointsC; 7387 if (values) *values = valuesC; 7388 } 7389 /* 5) Calculate indices */ 7390 PetscCall(DMGetWorkArray(dm, Ni, MPIU_INT, &idx)); 7391 if (Nf) { 7392 PetscInt idxOff; 7393 PetscBool useFieldOffsets; 7394 7395 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7396 PetscCall(PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets)); 7397 if (useFieldOffsets) { 7398 for (p = 0; p < Ncl; ++p) { 7399 const PetscInt pnt = points[p*2]; 7400 7401 PetscCall(DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx)); 7402 } 7403 } else { 7404 for (p = 0; p < Ncl; ++p) { 7405 const PetscInt pnt = points[p*2]; 7406 7407 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7408 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7409 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7410 * global section. */ 7411 PetscCall(DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx)); 7412 } 7413 } 7414 } else { 7415 PetscInt off = 0, idxOff; 7416 7417 for (p = 0; p < Ncl; ++p) { 7418 const PetscInt pnt = points[p*2]; 7419 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7420 7421 PetscCall(PetscSectionGetOffset(idxSection, pnt, &idxOff)); 7422 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7423 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7424 PetscCall(DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx)); 7425 } 7426 } 7427 /* 6) Cleanup */ 7428 for (f = 0; f < PetscMax(1, Nf); ++f) { 7429 if (Nf) PetscCall(PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f])); 7430 else PetscCall(PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f])); 7431 } 7432 if (NclC) { 7433 PetscCall(DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC)); 7434 } else { 7435 PetscCall(DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp)); 7436 } 7437 7438 if (numIndices) *numIndices = Ni; 7439 if (indices) *indices = idx; 7440 PetscFunctionReturn(0); 7441 } 7442 7443 /*@C 7444 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7445 7446 Not collective 7447 7448 Input Parameters: 7449 + dm - The DM 7450 . section - The PetscSection describing the points (a local section) 7451 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7452 . point - The point defining the closure 7453 - useClPerm - Use the closure point permutation if available 7454 7455 Output Parameters: 7456 + numIndices - The number of dof indices in the closure of point with the input sections 7457 . indices - The dof indices 7458 . outOffsets - Array to write the field offsets into, or NULL 7459 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7460 7461 Notes: 7462 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7463 7464 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7465 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7466 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7467 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7468 indices (with the above semantics) are implied. 7469 7470 Level: advanced 7471 7472 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 7473 @*/ 7474 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7475 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7476 { 7477 PetscFunctionBegin; 7478 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7479 PetscValidPointer(indices, 7); 7480 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, indices)); 7481 PetscFunctionReturn(0); 7482 } 7483 7484 /*@C 7485 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7486 7487 Not collective 7488 7489 Input Parameters: 7490 + dm - The DM 7491 . section - The section describing the layout in v, or NULL to use the default section 7492 . globalSection - The section describing the layout in v, or NULL to use the default global section 7493 . A - The matrix 7494 . point - The point in the DM 7495 . values - The array of values 7496 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7497 7498 Fortran Notes: 7499 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7500 7501 Level: intermediate 7502 7503 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7504 @*/ 7505 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7506 { 7507 DM_Plex *mesh = (DM_Plex*) dm->data; 7508 PetscInt *indices; 7509 PetscInt numIndices; 7510 const PetscScalar *valuesOrig = values; 7511 PetscErrorCode ierr; 7512 7513 PetscFunctionBegin; 7514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7515 if (!section) PetscCall(DMGetLocalSection(dm, §ion)); 7516 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7517 if (!globalSection) PetscCall(DMGetGlobalSection(dm, &globalSection)); 7518 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7519 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7520 7521 PetscCall(DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7522 7523 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values)); 7524 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7525 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7526 if (ierr) { 7527 PetscMPIInt rank; 7528 7529 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7530 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7531 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values)); 7532 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7533 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7534 SETERRQ(PetscObjectComm((PetscObject)dm),ierr,"Not possible to set matrix values"); 7535 } 7536 if (mesh->printFEM > 1) { 7537 PetscInt i; 7538 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Indices:")); 7539 for (i = 0; i < numIndices; ++i) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, indices[i])); 7540 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 7541 } 7542 7543 PetscCall(DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values)); 7544 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values)); 7545 PetscFunctionReturn(0); 7546 } 7547 7548 /*@C 7549 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7550 7551 Not collective 7552 7553 Input Parameters: 7554 + dmRow - The DM for the row fields 7555 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7556 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7557 . dmCol - The DM for the column fields 7558 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7559 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7560 . A - The matrix 7561 . point - The point in the DMs 7562 . values - The array of values 7563 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7564 7565 Level: intermediate 7566 7567 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7568 @*/ 7569 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7570 { 7571 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7572 PetscInt *indicesRow, *indicesCol; 7573 PetscInt numIndicesRow, numIndicesCol; 7574 const PetscScalar *valuesOrig = values; 7575 PetscErrorCode ierr; 7576 7577 PetscFunctionBegin; 7578 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7579 if (!sectionRow) PetscCall(DMGetLocalSection(dmRow, §ionRow)); 7580 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7581 if (!globalSectionRow) PetscCall(DMGetGlobalSection(dmRow, &globalSectionRow)); 7582 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7583 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7584 if (!sectionCol) PetscCall(DMGetLocalSection(dmCol, §ionCol)); 7585 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7586 if (!globalSectionCol) PetscCall(DMGetGlobalSection(dmCol, &globalSectionCol)); 7587 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7588 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7589 7590 PetscCall(DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7591 PetscCall(DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7592 7593 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7594 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7595 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7596 if (ierr) { 7597 PetscMPIInt rank; 7598 7599 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7600 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7601 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values)); 7602 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7603 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values)); 7604 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7605 } 7606 7607 PetscCall(DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values)); 7608 PetscCall(DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values)); 7609 if (values != valuesOrig) PetscCall(DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values)); 7610 PetscFunctionReturn(0); 7611 } 7612 7613 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7614 { 7615 DM_Plex *mesh = (DM_Plex*) dmf->data; 7616 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7617 PetscInt *cpoints = NULL; 7618 PetscInt *findices, *cindices; 7619 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7620 PetscInt foffsets[32], coffsets[32]; 7621 DMPolytopeType ct; 7622 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7623 PetscErrorCode ierr; 7624 7625 PetscFunctionBegin; 7626 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7627 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7628 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7629 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7630 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7631 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7632 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7633 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7634 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7635 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7636 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7637 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7638 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7639 PetscCall(PetscArrayzero(foffsets, 32)); 7640 PetscCall(PetscArrayzero(coffsets, 32)); 7641 /* Column indices */ 7642 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7643 maxFPoints = numCPoints; 7644 /* Compress out points not in the section */ 7645 /* TODO: Squeeze out points with 0 dof as well */ 7646 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7647 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7648 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7649 cpoints[q*2] = cpoints[p]; 7650 cpoints[q*2+1] = cpoints[p+1]; 7651 ++q; 7652 } 7653 } 7654 numCPoints = q; 7655 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7656 PetscInt fdof; 7657 7658 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7659 if (!dof) continue; 7660 for (f = 0; f < numFields; ++f) { 7661 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7662 coffsets[f+1] += fdof; 7663 } 7664 numCIndices += dof; 7665 } 7666 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7667 /* Row indices */ 7668 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7669 { 7670 DMPlexTransform tr; 7671 DMPolytopeType *rct; 7672 PetscInt *rsize, *rcone, *rornt, Nt; 7673 7674 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7675 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7676 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7677 numSubcells = rsize[Nt-1]; 7678 PetscCall(DMPlexTransformDestroy(&tr)); 7679 } 7680 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7681 for (r = 0, q = 0; r < numSubcells; ++r) { 7682 /* TODO Map from coarse to fine cells */ 7683 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7684 /* Compress out points not in the section */ 7685 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7686 for (p = 0; p < numFPoints*2; p += 2) { 7687 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7688 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7689 if (!dof) continue; 7690 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7691 if (s < q) continue; 7692 ftotpoints[q*2] = fpoints[p]; 7693 ftotpoints[q*2+1] = fpoints[p+1]; 7694 ++q; 7695 } 7696 } 7697 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7698 } 7699 numFPoints = q; 7700 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7701 PetscInt fdof; 7702 7703 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7704 if (!dof) continue; 7705 for (f = 0; f < numFields; ++f) { 7706 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7707 foffsets[f+1] += fdof; 7708 } 7709 numFIndices += dof; 7710 } 7711 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7712 7713 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7714 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7715 PetscCall(DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7716 PetscCall(DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7717 if (numFields) { 7718 const PetscInt **permsF[32] = {NULL}; 7719 const PetscInt **permsC[32] = {NULL}; 7720 7721 for (f = 0; f < numFields; f++) { 7722 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7723 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7724 } 7725 for (p = 0; p < numFPoints; p++) { 7726 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7727 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7728 } 7729 for (p = 0; p < numCPoints; p++) { 7730 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7731 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7732 } 7733 for (f = 0; f < numFields; f++) { 7734 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7735 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7736 } 7737 } else { 7738 const PetscInt **permsF = NULL; 7739 const PetscInt **permsC = NULL; 7740 7741 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7742 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7743 for (p = 0, off = 0; p < numFPoints; p++) { 7744 const PetscInt *perm = permsF ? permsF[p] : NULL; 7745 7746 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7747 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7748 } 7749 for (p = 0, off = 0; p < numCPoints; p++) { 7750 const PetscInt *perm = permsC ? permsC[p] : NULL; 7751 7752 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7753 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7754 } 7755 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7756 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7757 } 7758 if (mesh->printSetValues) PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7759 /* TODO: flips */ 7760 /* TODO: fix this code to not use error codes as handle-able exceptions! */ 7761 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7762 if (ierr) { 7763 PetscMPIInt rank; 7764 7765 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank)); 7766 PetscCall((*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank)); 7767 PetscCall(DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values)); 7768 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7769 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7770 } 7771 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7772 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7773 PetscCall(DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices)); 7774 PetscCall(DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices)); 7775 PetscFunctionReturn(0); 7776 } 7777 7778 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7779 { 7780 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7781 PetscInt *cpoints = NULL; 7782 PetscInt foffsets[32], coffsets[32]; 7783 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7784 DMPolytopeType ct; 7785 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7786 7787 PetscFunctionBegin; 7788 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7789 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7790 if (!fsection) PetscCall(DMGetLocalSection(dmf, &fsection)); 7791 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7792 if (!csection) PetscCall(DMGetLocalSection(dmc, &csection)); 7793 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7794 if (!globalFSection) PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 7795 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7796 if (!globalCSection) PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 7797 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7798 PetscCall(PetscSectionGetNumFields(fsection, &numFields)); 7799 PetscCheck(numFields <= 31,PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %" PetscInt_FMT " limited to 31", numFields); 7800 PetscCall(PetscArrayzero(foffsets, 32)); 7801 PetscCall(PetscArrayzero(coffsets, 32)); 7802 /* Column indices */ 7803 PetscCall(DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7804 maxFPoints = numCPoints; 7805 /* Compress out points not in the section */ 7806 /* TODO: Squeeze out points with 0 dof as well */ 7807 PetscCall(PetscSectionGetChart(csection, &pStart, &pEnd)); 7808 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7809 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7810 cpoints[q*2] = cpoints[p]; 7811 cpoints[q*2+1] = cpoints[p+1]; 7812 ++q; 7813 } 7814 } 7815 numCPoints = q; 7816 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7817 PetscInt fdof; 7818 7819 PetscCall(PetscSectionGetDof(csection, cpoints[p], &dof)); 7820 if (!dof) continue; 7821 for (f = 0; f < numFields; ++f) { 7822 PetscCall(PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof)); 7823 coffsets[f+1] += fdof; 7824 } 7825 numCIndices += dof; 7826 } 7827 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7828 /* Row indices */ 7829 PetscCall(DMPlexGetCellType(dmc, point, &ct)); 7830 { 7831 DMPlexTransform tr; 7832 DMPolytopeType *rct; 7833 PetscInt *rsize, *rcone, *rornt, Nt; 7834 7835 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 7836 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 7837 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nt, &rct, &rsize, &rcone, &rornt)); 7838 numSubcells = rsize[Nt-1]; 7839 PetscCall(DMPlexTransformDestroy(&tr)); 7840 } 7841 PetscCall(DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints)); 7842 for (r = 0, q = 0; r < numSubcells; ++r) { 7843 /* TODO Map from coarse to fine cells */ 7844 PetscCall(DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints)); 7845 /* Compress out points not in the section */ 7846 PetscCall(PetscSectionGetChart(fsection, &pStart, &pEnd)); 7847 for (p = 0; p < numFPoints*2; p += 2) { 7848 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7849 PetscCall(PetscSectionGetDof(fsection, fpoints[p], &dof)); 7850 if (!dof) continue; 7851 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7852 if (s < q) continue; 7853 ftotpoints[q*2] = fpoints[p]; 7854 ftotpoints[q*2+1] = fpoints[p+1]; 7855 ++q; 7856 } 7857 } 7858 PetscCall(DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints)); 7859 } 7860 numFPoints = q; 7861 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7862 PetscInt fdof; 7863 7864 PetscCall(PetscSectionGetDof(fsection, ftotpoints[p], &dof)); 7865 if (!dof) continue; 7866 for (f = 0; f < numFields; ++f) { 7867 PetscCall(PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof)); 7868 foffsets[f+1] += fdof; 7869 } 7870 numFIndices += dof; 7871 } 7872 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7873 7874 PetscCheckFalse(numFields && foffsets[numFields] != numFIndices,PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, foffsets[numFields], numFIndices); 7875 PetscCheckFalse(numFields && coffsets[numFields] != numCIndices,PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %" PetscInt_FMT " should be %" PetscInt_FMT, coffsets[numFields], numCIndices); 7876 if (numFields) { 7877 const PetscInt **permsF[32] = {NULL}; 7878 const PetscInt **permsC[32] = {NULL}; 7879 7880 for (f = 0; f < numFields; f++) { 7881 PetscCall(PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7882 PetscCall(PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7883 } 7884 for (p = 0; p < numFPoints; p++) { 7885 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7886 PetscCall(DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices)); 7887 } 7888 for (p = 0; p < numCPoints; p++) { 7889 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7890 PetscCall(DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices)); 7891 } 7892 for (f = 0; f < numFields; f++) { 7893 PetscCall(PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL)); 7894 PetscCall(PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL)); 7895 } 7896 } else { 7897 const PetscInt **permsF = NULL; 7898 const PetscInt **permsC = NULL; 7899 7900 PetscCall(PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7901 PetscCall(PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7902 for (p = 0, off = 0; p < numFPoints; p++) { 7903 const PetscInt *perm = permsF ? permsF[p] : NULL; 7904 7905 PetscCall(PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff)); 7906 PetscCall(DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices)); 7907 } 7908 for (p = 0, off = 0; p < numCPoints; p++) { 7909 const PetscInt *perm = permsC ? permsC[p] : NULL; 7910 7911 PetscCall(PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff)); 7912 PetscCall(DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices)); 7913 } 7914 PetscCall(PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL)); 7915 PetscCall(PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL)); 7916 } 7917 PetscCall(DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints)); 7918 PetscCall(DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints)); 7919 PetscFunctionReturn(0); 7920 } 7921 7922 /*@C 7923 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7924 7925 Input Parameter: 7926 . dm - The DMPlex object 7927 7928 Output Parameter: 7929 . cellHeight - The height of a cell 7930 7931 Level: developer 7932 7933 .seealso DMPlexSetVTKCellHeight() 7934 @*/ 7935 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7936 { 7937 DM_Plex *mesh = (DM_Plex*) dm->data; 7938 7939 PetscFunctionBegin; 7940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7941 PetscValidIntPointer(cellHeight, 2); 7942 *cellHeight = mesh->vtkCellHeight; 7943 PetscFunctionReturn(0); 7944 } 7945 7946 /*@C 7947 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7948 7949 Input Parameters: 7950 + dm - The DMPlex object 7951 - cellHeight - The height of a cell 7952 7953 Level: developer 7954 7955 .seealso DMPlexGetVTKCellHeight() 7956 @*/ 7957 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7958 { 7959 DM_Plex *mesh = (DM_Plex*) dm->data; 7960 7961 PetscFunctionBegin; 7962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7963 mesh->vtkCellHeight = cellHeight; 7964 PetscFunctionReturn(0); 7965 } 7966 7967 /*@ 7968 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7969 7970 Input Parameter: 7971 . dm - The DMPlex object 7972 7973 Output Parameters: 7974 + gcStart - The first ghost cell, or NULL 7975 - gcEnd - The upper bound on ghost cells, or NULL 7976 7977 Level: advanced 7978 7979 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 7980 @*/ 7981 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7982 { 7983 DMLabel ctLabel; 7984 7985 PetscFunctionBegin; 7986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7987 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 7988 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd)); 7989 PetscFunctionReturn(0); 7990 } 7991 7992 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 7993 { 7994 PetscSection section, globalSection; 7995 PetscInt *numbers, p; 7996 7997 PetscFunctionBegin; 7998 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 7999 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 8000 for (p = pStart; p < pEnd; ++p) { 8001 PetscCall(PetscSectionSetDof(section, p, 1)); 8002 } 8003 PetscCall(PetscSectionSetUp(section)); 8004 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection)); 8005 PetscCall(PetscMalloc1(pEnd - pStart, &numbers)); 8006 for (p = pStart; p < pEnd; ++p) { 8007 PetscCall(PetscSectionGetOffset(globalSection, p, &numbers[p-pStart])); 8008 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 8009 else numbers[p-pStart] += shift; 8010 } 8011 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering)); 8012 if (globalSize) { 8013 PetscLayout layout; 8014 PetscCall(PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout)); 8015 PetscCall(PetscLayoutGetSize(layout, globalSize)); 8016 PetscCall(PetscLayoutDestroy(&layout)); 8017 } 8018 PetscCall(PetscSectionDestroy(§ion)); 8019 PetscCall(PetscSectionDestroy(&globalSection)); 8020 PetscFunctionReturn(0); 8021 } 8022 8023 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 8024 { 8025 PetscInt cellHeight, cStart, cEnd; 8026 8027 PetscFunctionBegin; 8028 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8029 if (includeHybrid) PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8030 else PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 8031 PetscCall(DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers)); 8032 PetscFunctionReturn(0); 8033 } 8034 8035 /*@ 8036 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 8037 8038 Input Parameter: 8039 . dm - The DMPlex object 8040 8041 Output Parameter: 8042 . globalCellNumbers - Global cell numbers for all cells on this process 8043 8044 Level: developer 8045 8046 .seealso DMPlexGetVertexNumbering() 8047 @*/ 8048 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 8049 { 8050 DM_Plex *mesh = (DM_Plex*) dm->data; 8051 8052 PetscFunctionBegin; 8053 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8054 if (!mesh->globalCellNumbers) PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers)); 8055 *globalCellNumbers = mesh->globalCellNumbers; 8056 PetscFunctionReturn(0); 8057 } 8058 8059 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 8060 { 8061 PetscInt vStart, vEnd; 8062 8063 PetscFunctionBegin; 8064 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8065 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8066 PetscCall(DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers)); 8067 PetscFunctionReturn(0); 8068 } 8069 8070 /*@ 8071 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 8072 8073 Input Parameter: 8074 . dm - The DMPlex object 8075 8076 Output Parameter: 8077 . globalVertexNumbers - Global vertex numbers for all vertices on this process 8078 8079 Level: developer 8080 8081 .seealso DMPlexGetCellNumbering() 8082 @*/ 8083 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 8084 { 8085 DM_Plex *mesh = (DM_Plex*) dm->data; 8086 8087 PetscFunctionBegin; 8088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8089 if (!mesh->globalVertexNumbers) PetscCall(DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers)); 8090 *globalVertexNumbers = mesh->globalVertexNumbers; 8091 PetscFunctionReturn(0); 8092 } 8093 8094 /*@ 8095 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 8096 8097 Input Parameter: 8098 . dm - The DMPlex object 8099 8100 Output Parameter: 8101 . globalPointNumbers - Global numbers for all points on this process 8102 8103 Level: developer 8104 8105 .seealso DMPlexGetCellNumbering() 8106 @*/ 8107 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 8108 { 8109 IS nums[4]; 8110 PetscInt depths[4], gdepths[4], starts[4]; 8111 PetscInt depth, d, shift = 0; 8112 8113 PetscFunctionBegin; 8114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8115 PetscCall(DMPlexGetDepth(dm, &depth)); 8116 /* For unstratified meshes use dim instead of depth */ 8117 if (depth < 0) PetscCall(DMGetDimension(dm, &depth)); 8118 for (d = 0; d <= depth; ++d) { 8119 PetscInt end; 8120 8121 depths[d] = depth-d; 8122 PetscCall(DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end)); 8123 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 8124 } 8125 PetscCall(PetscSortIntWithArray(depth+1, starts, depths)); 8126 PetscCall(MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm))); 8127 for (d = 0; d <= depth; ++d) { 8128 PetscCheckFalse(starts[d] >= 0 && depths[d] != gdepths[d],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %" PetscInt_FMT ", found %" PetscInt_FMT,depths[d],gdepths[d]); 8129 } 8130 for (d = 0; d <= depth; ++d) { 8131 PetscInt pStart, pEnd, gsize; 8132 8133 PetscCall(DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd)); 8134 PetscCall(DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d])); 8135 shift += gsize; 8136 } 8137 PetscCall(ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers)); 8138 for (d = 0; d <= depth; ++d) PetscCall(ISDestroy(&nums[d])); 8139 PetscFunctionReturn(0); 8140 } 8141 8142 /*@ 8143 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 8144 8145 Input Parameter: 8146 . dm - The DMPlex object 8147 8148 Output Parameter: 8149 . ranks - The rank field 8150 8151 Options Database Keys: 8152 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 8153 8154 Level: intermediate 8155 8156 .seealso: DMView() 8157 @*/ 8158 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 8159 { 8160 DM rdm; 8161 PetscFE fe; 8162 PetscScalar *r; 8163 PetscMPIInt rank; 8164 DMPolytopeType ct; 8165 PetscInt dim, cStart, cEnd, c; 8166 PetscBool simplex; 8167 8168 PetscFunctionBeginUser; 8169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8170 PetscValidPointer(ranks, 2); 8171 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 8172 PetscCall(DMClone(dm, &rdm)); 8173 PetscCall(DMGetDimension(rdm, &dim)); 8174 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8175 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8176 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 8177 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe)); 8178 PetscCall(PetscObjectSetName((PetscObject) fe, "rank")); 8179 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8180 PetscCall(PetscFEDestroy(&fe)); 8181 PetscCall(DMCreateDS(rdm)); 8182 PetscCall(DMCreateGlobalVector(rdm, ranks)); 8183 PetscCall(PetscObjectSetName((PetscObject) *ranks, "partition")); 8184 PetscCall(VecGetArray(*ranks, &r)); 8185 for (c = cStart; c < cEnd; ++c) { 8186 PetscScalar *lr; 8187 8188 PetscCall(DMPlexPointGlobalRef(rdm, c, r, &lr)); 8189 if (lr) *lr = rank; 8190 } 8191 PetscCall(VecRestoreArray(*ranks, &r)); 8192 PetscCall(DMDestroy(&rdm)); 8193 PetscFunctionReturn(0); 8194 } 8195 8196 /*@ 8197 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 8198 8199 Input Parameters: 8200 + dm - The DMPlex 8201 - label - The DMLabel 8202 8203 Output Parameter: 8204 . val - The label value field 8205 8206 Options Database Keys: 8207 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 8208 8209 Level: intermediate 8210 8211 .seealso: DMView() 8212 @*/ 8213 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 8214 { 8215 DM rdm; 8216 PetscFE fe; 8217 PetscScalar *v; 8218 PetscInt dim, cStart, cEnd, c; 8219 8220 PetscFunctionBeginUser; 8221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8222 PetscValidPointer(label, 2); 8223 PetscValidPointer(val, 3); 8224 PetscCall(DMClone(dm, &rdm)); 8225 PetscCall(DMGetDimension(rdm, &dim)); 8226 PetscCall(PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe)); 8227 PetscCall(PetscObjectSetName((PetscObject) fe, "label_value")); 8228 PetscCall(DMSetField(rdm, 0, NULL, (PetscObject) fe)); 8229 PetscCall(PetscFEDestroy(&fe)); 8230 PetscCall(DMCreateDS(rdm)); 8231 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd)); 8232 PetscCall(DMCreateGlobalVector(rdm, val)); 8233 PetscCall(PetscObjectSetName((PetscObject) *val, "label_value")); 8234 PetscCall(VecGetArray(*val, &v)); 8235 for (c = cStart; c < cEnd; ++c) { 8236 PetscScalar *lv; 8237 PetscInt cval; 8238 8239 PetscCall(DMPlexPointGlobalRef(rdm, c, v, &lv)); 8240 PetscCall(DMLabelGetValue(label, c, &cval)); 8241 *lv = cval; 8242 } 8243 PetscCall(VecRestoreArray(*val, &v)); 8244 PetscCall(DMDestroy(&rdm)); 8245 PetscFunctionReturn(0); 8246 } 8247 8248 /*@ 8249 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 8250 8251 Input Parameter: 8252 . dm - The DMPlex object 8253 8254 Notes: 8255 This is a useful diagnostic when creating meshes programmatically. 8256 8257 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8258 8259 Level: developer 8260 8261 .seealso: DMCreate(), DMSetFromOptions() 8262 @*/ 8263 PetscErrorCode DMPlexCheckSymmetry(DM dm) 8264 { 8265 PetscSection coneSection, supportSection; 8266 const PetscInt *cone, *support; 8267 PetscInt coneSize, c, supportSize, s; 8268 PetscInt pStart, pEnd, p, pp, csize, ssize; 8269 PetscBool storagecheck = PETSC_TRUE; 8270 8271 PetscFunctionBegin; 8272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8273 PetscCall(DMViewFromOptions(dm, NULL, "-sym_dm_view")); 8274 PetscCall(DMPlexGetConeSection(dm, &coneSection)); 8275 PetscCall(DMPlexGetSupportSection(dm, &supportSection)); 8276 /* Check that point p is found in the support of its cone points, and vice versa */ 8277 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8278 for (p = pStart; p < pEnd; ++p) { 8279 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 8280 PetscCall(DMPlexGetCone(dm, p, &cone)); 8281 for (c = 0; c < coneSize; ++c) { 8282 PetscBool dup = PETSC_FALSE; 8283 PetscInt d; 8284 for (d = c-1; d >= 0; --d) { 8285 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 8286 } 8287 PetscCall(DMPlexGetSupportSize(dm, cone[c], &supportSize)); 8288 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 8289 for (s = 0; s < supportSize; ++s) { 8290 if (support[s] == p) break; 8291 } 8292 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 8293 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", p)); 8294 for (s = 0; s < coneSize; ++s) { 8295 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[s])); 8296 } 8297 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8298 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", cone[c])); 8299 for (s = 0; s < supportSize; ++s) { 8300 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[s])); 8301 } 8302 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8303 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]); 8304 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in support of cone point %" PetscInt_FMT, p, cone[c]); 8305 } 8306 } 8307 PetscCall(DMPlexGetTreeParent(dm, p, &pp, NULL)); 8308 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 8309 PetscCall(DMPlexGetSupportSize(dm, p, &supportSize)); 8310 PetscCall(DMPlexGetSupport(dm, p, &support)); 8311 for (s = 0; s < supportSize; ++s) { 8312 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 8313 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 8314 for (c = 0; c < coneSize; ++c) { 8315 PetscCall(DMPlexGetTreeParent(dm, cone[c], &pp, NULL)); 8316 if (cone[c] != pp) { c = 0; break; } 8317 if (cone[c] == p) break; 8318 } 8319 if (c >= coneSize) { 8320 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " support: ", p)); 8321 for (c = 0; c < supportSize; ++c) { 8322 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", support[c])); 8323 } 8324 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8325 PetscCall(PetscPrintf(PETSC_COMM_SELF, "p: %" PetscInt_FMT " cone: ", support[s])); 8326 for (c = 0; c < coneSize; ++c) { 8327 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT ", ", cone[c])); 8328 } 8329 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8330 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " not found in cone of support point %" PetscInt_FMT, p, support[s]); 8331 } 8332 } 8333 } 8334 if (storagecheck) { 8335 PetscCall(PetscSectionGetStorageSize(coneSection, &csize)); 8336 PetscCall(PetscSectionGetStorageSize(supportSection, &ssize)); 8337 PetscCheck(csize == ssize,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %" PetscInt_FMT " != Total support size %" PetscInt_FMT, csize, ssize); 8338 } 8339 PetscFunctionReturn(0); 8340 } 8341 8342 /* 8343 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. 8344 */ 8345 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 8346 { 8347 DMPolytopeType cct; 8348 PetscInt ptpoints[4]; 8349 const PetscInt *cone, *ccone, *ptcone; 8350 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 8351 8352 PetscFunctionBegin; 8353 *unsplit = 0; 8354 switch (ct) { 8355 case DM_POLYTOPE_POINT_PRISM_TENSOR: 8356 ptpoints[npt++] = c; 8357 break; 8358 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8359 PetscCall(DMPlexGetCone(dm, c, &cone)); 8360 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8361 for (cp = 0; cp < coneSize; ++cp) { 8362 PetscCall(DMPlexGetCellType(dm, cone[cp], &cct)); 8363 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8364 } 8365 break; 8366 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8367 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8368 PetscCall(DMPlexGetCone(dm, c, &cone)); 8369 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8370 for (cp = 0; cp < coneSize; ++cp) { 8371 PetscCall(DMPlexGetCone(dm, cone[cp], &ccone)); 8372 PetscCall(DMPlexGetConeSize(dm, cone[cp], &cconeSize)); 8373 for (ccp = 0; ccp < cconeSize; ++ccp) { 8374 PetscCall(DMPlexGetCellType(dm, ccone[ccp], &cct)); 8375 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8376 PetscInt p; 8377 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8378 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8379 } 8380 } 8381 } 8382 break; 8383 default: break; 8384 } 8385 for (pt = 0; pt < npt; ++pt) { 8386 PetscCall(DMPlexGetCone(dm, ptpoints[pt], &ptcone)); 8387 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8388 } 8389 PetscFunctionReturn(0); 8390 } 8391 8392 /*@ 8393 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8394 8395 Input Parameters: 8396 + dm - The DMPlex object 8397 - cellHeight - Normally 0 8398 8399 Notes: 8400 This is a useful diagnostic when creating meshes programmatically. 8401 Currently applicable only to homogeneous simplex or tensor meshes. 8402 8403 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8404 8405 Level: developer 8406 8407 .seealso: DMCreate(), DMSetFromOptions() 8408 @*/ 8409 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8410 { 8411 DMPlexInterpolatedFlag interp; 8412 DMPolytopeType ct; 8413 PetscInt vStart, vEnd, cStart, cEnd, c; 8414 8415 PetscFunctionBegin; 8416 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8417 PetscCall(DMPlexIsInterpolated(dm, &interp)); 8418 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8419 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8420 for (c = cStart; c < cEnd; ++c) { 8421 PetscInt *closure = NULL; 8422 PetscInt coneSize, closureSize, cl, Nv = 0; 8423 8424 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8425 PetscCheck((PetscInt) ct >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " has no cell type", c); 8426 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8427 if (interp == DMPLEX_INTERPOLATED_FULL) { 8428 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8429 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)); 8430 } 8431 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8432 for (cl = 0; cl < closureSize*2; cl += 2) { 8433 const PetscInt p = closure[cl]; 8434 if ((p >= vStart) && (p < vEnd)) ++Nv; 8435 } 8436 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8437 /* Special Case: Tensor faces with identified vertices */ 8438 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8439 PetscInt unsplit; 8440 8441 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8442 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8443 } 8444 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)); 8445 } 8446 PetscFunctionReturn(0); 8447 } 8448 8449 /*@ 8450 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8451 8452 Not Collective 8453 8454 Input Parameters: 8455 + dm - The DMPlex object 8456 - cellHeight - Normally 0 8457 8458 Notes: 8459 This is a useful diagnostic when creating meshes programmatically. 8460 This routine is only relevant for meshes that are fully interpolated across all ranks. 8461 It will error out if a partially interpolated mesh is given on some rank. 8462 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8463 8464 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8465 8466 Level: developer 8467 8468 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 8469 @*/ 8470 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8471 { 8472 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8473 DMPlexInterpolatedFlag interpEnum; 8474 8475 PetscFunctionBegin; 8476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8477 PetscCall(DMPlexIsInterpolated(dm, &interpEnum)); 8478 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8479 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 8480 PetscMPIInt rank; 8481 MPI_Comm comm; 8482 8483 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8484 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8485 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 8486 } 8487 8488 PetscCall(DMGetDimension(dm, &dim)); 8489 PetscCall(DMPlexGetDepth(dm, &depth)); 8490 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 8491 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8492 PetscCall(DMPlexGetHeightStratum(dm, h, &cStart, &cEnd)); 8493 for (c = cStart; c < cEnd; ++c) { 8494 const PetscInt *cone, *ornt, *faceSizes, *faces; 8495 const DMPolytopeType *faceTypes; 8496 DMPolytopeType ct; 8497 PetscInt numFaces, coneSize, f; 8498 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8499 8500 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8501 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8502 if (unsplit) continue; 8503 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 8504 PetscCall(DMPlexGetCone(dm, c, &cone)); 8505 PetscCall(DMPlexGetConeOrientation(dm, c, &ornt)); 8506 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8507 for (cl = 0; cl < closureSize*2; cl += 2) { 8508 const PetscInt p = closure[cl]; 8509 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8510 } 8511 PetscCall(DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8512 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); 8513 for (f = 0; f < numFaces; ++f) { 8514 DMPolytopeType fct; 8515 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8516 8517 PetscCall(DMPlexGetCellType(dm, cone[f], &fct)); 8518 PetscCall(DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8519 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8520 const PetscInt p = fclosure[cl]; 8521 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8522 } 8523 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]); 8524 for (v = 0; v < fnumCorners; ++v) { 8525 if (fclosure[v] != faces[fOff+v]) { 8526 PetscInt v1; 8527 8528 PetscCall(PetscPrintf(PETSC_COMM_SELF, "face closure:")); 8529 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, fclosure[v1])); 8530 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\ncell face:")); 8531 for (v1 = 0; v1 < fnumCorners; ++v1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %" PetscInt_FMT, faces[fOff+v1])); 8532 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 8533 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]); 8534 } 8535 } 8536 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure)); 8537 fOff += faceSizes[f]; 8538 } 8539 PetscCall(DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces)); 8540 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 8541 } 8542 } 8543 PetscFunctionReturn(0); 8544 } 8545 8546 /*@ 8547 DMPlexCheckGeometry - Check the geometry of mesh cells 8548 8549 Input Parameter: 8550 . dm - The DMPlex object 8551 8552 Notes: 8553 This is a useful diagnostic when creating meshes programmatically. 8554 8555 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8556 8557 Level: developer 8558 8559 .seealso: DMCreate(), DMSetFromOptions() 8560 @*/ 8561 PetscErrorCode DMPlexCheckGeometry(DM dm) 8562 { 8563 Vec coordinates; 8564 PetscReal detJ, J[9], refVol = 1.0; 8565 PetscReal vol; 8566 PetscBool periodic; 8567 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8568 8569 PetscFunctionBegin; 8570 PetscCall(DMGetDimension(dm, &dim)); 8571 PetscCall(DMGetCoordinateDim(dm, &dE)); 8572 if (dim != dE) PetscFunctionReturn(0); 8573 PetscCall(DMPlexGetDepth(dm, &depth)); 8574 PetscCall(DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL)); 8575 for (d = 0; d < dim; ++d) refVol *= 2.0; 8576 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 8577 /* Make sure local coordinates are created, because that step is collective */ 8578 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 8579 for (c = cStart; c < cEnd; ++c) { 8580 DMPolytopeType ct; 8581 PetscInt unsplit; 8582 PetscBool ignoreZeroVol = PETSC_FALSE; 8583 8584 PetscCall(DMPlexGetCellType(dm, c, &ct)); 8585 switch (ct) { 8586 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8587 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8588 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8589 ignoreZeroVol = PETSC_TRUE; break; 8590 default: break; 8591 } 8592 switch (ct) { 8593 case DM_POLYTOPE_TRI_PRISM: 8594 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8595 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8596 case DM_POLYTOPE_PYRAMID: 8597 continue; 8598 default: break; 8599 } 8600 PetscCall(DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit)); 8601 if (unsplit) continue; 8602 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ)); 8603 PetscCheckFalse(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); 8604 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FEM Volume %g\n", c, (double)(detJ*refVol))); 8605 if (depth > 1 && !periodic) { 8606 PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL)); 8607 PetscCheckFalse(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); 8608 PetscCall(PetscInfo(dm, "Cell %" PetscInt_FMT " FVM Volume %g\n", c, (double) vol)); 8609 } 8610 } 8611 PetscFunctionReturn(0); 8612 } 8613 8614 /*@ 8615 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 8616 8617 Input Parameters: 8618 . dm - The DMPlex object 8619 8620 Notes: 8621 This is mainly intended for debugging/testing purposes. 8622 It currently checks only meshes with no partition overlapping. 8623 8624 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8625 8626 Level: developer 8627 8628 .seealso: DMGetPointSF(), DMSetFromOptions() 8629 @*/ 8630 PetscErrorCode DMPlexCheckPointSF(DM dm) 8631 { 8632 PetscSF pointSF; 8633 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 8634 const PetscInt *locals, *rootdegree; 8635 PetscBool distributed; 8636 8637 PetscFunctionBegin; 8638 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8639 PetscCall(DMGetPointSF(dm, &pointSF)); 8640 PetscCall(DMPlexIsDistributed(dm, &distributed)); 8641 if (!distributed) PetscFunctionReturn(0); 8642 PetscCall(DMPlexGetOverlap(dm, &overlap)); 8643 if (overlap) { 8644 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping")); 8645 PetscFunctionReturn(0); 8646 } 8647 PetscCheck(pointSF,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 8648 PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL)); 8649 PetscCheck(nroots >= 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 8650 PetscCall(PetscSFComputeDegreeBegin(pointSF, &rootdegree)); 8651 PetscCall(PetscSFComputeDegreeEnd(pointSF, &rootdegree)); 8652 8653 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 8654 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8655 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8656 for (l = 0; l < nleaves; ++l) { 8657 const PetscInt point = locals[l]; 8658 8659 PetscCheckFalse(point >= cStart && point < cEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " which is a cell", point); 8660 } 8661 8662 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8663 for (l = 0; l < nleaves; ++l) { 8664 const PetscInt point = locals[l]; 8665 const PetscInt *cone; 8666 PetscInt coneSize, c, idx; 8667 8668 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 8669 PetscCall(DMPlexGetCone(dm, point, &cone)); 8670 for (c = 0; c < coneSize; ++c) { 8671 if (!rootdegree[cone[c]]) { 8672 PetscCall(PetscFindInt(cone[c], nleaves, locals, &idx)); 8673 PetscCheck(idx >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %" PetscInt_FMT " but not %" PetscInt_FMT " from its cone", point, cone[c]); 8674 } 8675 } 8676 } 8677 PetscFunctionReturn(0); 8678 } 8679 8680 PetscErrorCode DMPlexCheckAll_Internal(DM dm, PetscInt cellHeight) 8681 { 8682 PetscFunctionBegin; 8683 PetscCall(DMPlexCheckSymmetry(dm)); 8684 PetscCall(DMPlexCheckSkeleton(dm, cellHeight)); 8685 PetscCall(DMPlexCheckFaces(dm, cellHeight)); 8686 PetscCall(DMPlexCheckGeometry(dm)); 8687 PetscCall(DMPlexCheckPointSF(dm)); 8688 PetscCall(DMPlexCheckInterfaceCones(dm)); 8689 PetscFunctionReturn(0); 8690 } 8691 8692 typedef struct cell_stats 8693 { 8694 PetscReal min, max, sum, squaresum; 8695 PetscInt count; 8696 } cell_stats_t; 8697 8698 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8699 { 8700 PetscInt i, N = *len; 8701 8702 for (i = 0; i < N; i++) { 8703 cell_stats_t *A = (cell_stats_t *) a; 8704 cell_stats_t *B = (cell_stats_t *) b; 8705 8706 B->min = PetscMin(A->min,B->min); 8707 B->max = PetscMax(A->max,B->max); 8708 B->sum += A->sum; 8709 B->squaresum += A->squaresum; 8710 B->count += A->count; 8711 } 8712 } 8713 8714 /*@ 8715 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8716 8717 Collective on dm 8718 8719 Input Parameters: 8720 + dm - The DMPlex object 8721 . output - If true, statistics will be displayed on stdout 8722 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8723 8724 Notes: 8725 This is mainly intended for debugging/testing purposes. 8726 8727 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8728 8729 Level: developer 8730 8731 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality() 8732 @*/ 8733 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8734 { 8735 DM dmCoarse; 8736 cell_stats_t stats, globalStats; 8737 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8738 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8739 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8740 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8741 PetscMPIInt rank,size; 8742 8743 PetscFunctionBegin; 8744 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8745 stats.min = PETSC_MAX_REAL; 8746 stats.max = PETSC_MIN_REAL; 8747 stats.sum = stats.squaresum = 0.; 8748 stats.count = 0; 8749 8750 PetscCallMPI(MPI_Comm_size(comm, &size)); 8751 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8752 PetscCall(DMGetCoordinateDim(dm,&cdim)); 8753 PetscCall(PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ)); 8754 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 8755 PetscCall(DMPlexGetDepthStratum(dm,1,&eStart,&eEnd)); 8756 for (c = cStart; c < cEnd; c++) { 8757 PetscInt i; 8758 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8759 8760 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ)); 8761 PetscCheck(detJ >= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %" PetscInt_FMT " is inverted", c); 8762 for (i = 0; i < PetscSqr(cdim); ++i) { 8763 frobJ += J[i] * J[i]; 8764 frobInvJ += invJ[i] * invJ[i]; 8765 } 8766 cond2 = frobJ * frobInvJ; 8767 cond = PetscSqrtReal(cond2); 8768 8769 stats.min = PetscMin(stats.min,cond); 8770 stats.max = PetscMax(stats.max,cond); 8771 stats.sum += cond; 8772 stats.squaresum += cond2; 8773 stats.count++; 8774 if (output && cond > limit) { 8775 PetscSection coordSection; 8776 Vec coordsLocal; 8777 PetscScalar *coords = NULL; 8778 PetscInt Nv, d, clSize, cl, *closure = NULL; 8779 8780 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 8781 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 8782 PetscCall(DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8783 PetscCall(PetscSynchronizedPrintf(comm, "[%d] Cell %" PetscInt_FMT " cond %g\n", rank, c, (double) cond)); 8784 for (i = 0; i < Nv/cdim; ++i) { 8785 PetscCall(PetscSynchronizedPrintf(comm, " Vertex %" PetscInt_FMT ": (", i)); 8786 for (d = 0; d < cdim; ++d) { 8787 if (d > 0) PetscCall(PetscSynchronizedPrintf(comm, ", ")); 8788 PetscCall(PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]))); 8789 } 8790 PetscCall(PetscSynchronizedPrintf(comm, ")\n")); 8791 } 8792 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8793 for (cl = 0; cl < clSize*2; cl += 2) { 8794 const PetscInt edge = closure[cl]; 8795 8796 if ((edge >= eStart) && (edge < eEnd)) { 8797 PetscReal len; 8798 8799 PetscCall(DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL)); 8800 PetscCall(PetscSynchronizedPrintf(comm, " Edge %" PetscInt_FMT ": length %g\n", edge, (double) len)); 8801 } 8802 } 8803 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 8804 PetscCall(DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords)); 8805 } 8806 } 8807 if (output) PetscCall(PetscSynchronizedFlush(comm, NULL)); 8808 8809 if (size > 1) { 8810 PetscMPIInt blockLengths[2] = {4,1}; 8811 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8812 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8813 MPI_Op statReduce; 8814 8815 PetscCallMPI(MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType)); 8816 PetscCallMPI(MPI_Type_commit(&statType)); 8817 PetscCallMPI(MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce)); 8818 PetscCallMPI(MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm)); 8819 PetscCallMPI(MPI_Op_free(&statReduce)); 8820 PetscCallMPI(MPI_Type_free(&statType)); 8821 } else { 8822 PetscCall(PetscArraycpy(&globalStats,&stats,1)); 8823 } 8824 if (rank == 0) { 8825 count = globalStats.count; 8826 min = globalStats.min; 8827 max = globalStats.max; 8828 mean = globalStats.sum / globalStats.count; 8829 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8830 } 8831 8832 if (output) { 8833 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)); 8834 } 8835 PetscCall(PetscFree2(J,invJ)); 8836 8837 PetscCall(DMGetCoarseDM(dm,&dmCoarse)); 8838 if (dmCoarse) { 8839 PetscBool isplex; 8840 8841 PetscCall(PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex)); 8842 if (isplex) { 8843 PetscCall(DMPlexCheckCellShape(dmCoarse,output,condLimit)); 8844 } 8845 } 8846 PetscFunctionReturn(0); 8847 } 8848 8849 /*@ 8850 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8851 orthogonal quality below given tolerance. 8852 8853 Collective on dm 8854 8855 Input Parameters: 8856 + dm - The DMPlex object 8857 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8858 - atol - [0, 1] Absolute tolerance for tagging cells. 8859 8860 Output Parameters: 8861 + OrthQual - Vec containing orthogonal quality per cell 8862 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8863 8864 Options Database Keys: 8865 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8866 supported. 8867 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8868 8869 Notes: 8870 Orthogonal quality is given by the following formula: 8871 8872 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8873 8874 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 8875 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8876 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8877 calculating the cosine of the angle between these vectors. 8878 8879 Orthogonal quality ranges from 1 (best) to 0 (worst). 8880 8881 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8882 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8883 8884 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8885 8886 Level: intermediate 8887 8888 .seealso: DMPlexCheckCellShape(), DMCreateLabel() 8889 @*/ 8890 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8891 { 8892 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8893 PetscInt *idx; 8894 PetscScalar *oqVals; 8895 const PetscScalar *cellGeomArr, *faceGeomArr; 8896 PetscReal *ci, *fi, *Ai; 8897 MPI_Comm comm; 8898 Vec cellgeom, facegeom; 8899 DM dmFace, dmCell; 8900 IS glob; 8901 ISLocalToGlobalMapping ltog; 8902 PetscViewer vwr; 8903 8904 PetscFunctionBegin; 8905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8906 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8907 PetscValidPointer(OrthQual, 4); 8908 PetscCheck(atol >= 0.0 && atol <= 1.0,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8909 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 8910 PetscCall(DMGetDimension(dm, &nc)); 8911 PetscCheck(nc >= 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %" PetscInt_FMT ")", nc); 8912 { 8913 DMPlexInterpolatedFlag interpFlag; 8914 8915 PetscCall(DMPlexIsInterpolated(dm, &interpFlag)); 8916 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8917 PetscMPIInt rank; 8918 8919 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8920 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8921 } 8922 } 8923 if (OrthQualLabel) { 8924 PetscValidPointer(OrthQualLabel, 5); 8925 PetscCall(DMCreateLabel(dm, "Orthogonal_Quality")); 8926 PetscCall(DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel)); 8927 } else {*OrthQualLabel = NULL;} 8928 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 8929 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 8930 PetscCall(DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob)); 8931 PetscCall(ISLocalToGlobalMappingCreateIS(glob, <og)); 8932 PetscCall(ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH)); 8933 PetscCall(VecCreate(comm, OrthQual)); 8934 PetscCall(VecSetType(*OrthQual, VECSTANDARD)); 8935 PetscCall(VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE)); 8936 PetscCall(VecSetLocalToGlobalMapping(*OrthQual, ltog)); 8937 PetscCall(VecSetUp(*OrthQual)); 8938 PetscCall(ISDestroy(&glob)); 8939 PetscCall(ISLocalToGlobalMappingDestroy(<og)); 8940 PetscCall(DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL)); 8941 PetscCall(VecGetArrayRead(cellgeom, &cellGeomArr)); 8942 PetscCall(VecGetArrayRead(facegeom, &faceGeomArr)); 8943 PetscCall(VecGetDM(cellgeom, &dmCell)); 8944 PetscCall(VecGetDM(facegeom, &dmFace)); 8945 PetscCall(PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai)); 8946 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 8947 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8948 PetscInt cellarr[2], *adj = NULL; 8949 PetscScalar *cArr, *fArr; 8950 PetscReal minvalc = 1.0, minvalf = 1.0; 8951 PetscFVCellGeom *cg; 8952 8953 idx[cellIter] = cell-cStart; 8954 cellarr[0] = cell; 8955 /* Make indexing into cellGeom easier */ 8956 PetscCall(DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg)); 8957 PetscCall(DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj)); 8958 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8959 PetscCall(PetscCalloc2(adjSize, &cArr, adjSize, &fArr)); 8960 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 8961 PetscInt i; 8962 const PetscInt neigh = adj[cellneigh]; 8963 PetscReal normci = 0, normfi = 0, normai = 0; 8964 PetscFVCellGeom *cgneigh; 8965 PetscFVFaceGeom *fg; 8966 8967 /* Don't count ourselves in the neighbor list */ 8968 if (neigh == cell) continue; 8969 PetscCall(DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh)); 8970 cellarr[1] = neigh; 8971 { 8972 PetscInt numcovpts; 8973 const PetscInt *covpts; 8974 8975 PetscCall(DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8976 PetscCall(DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg)); 8977 PetscCall(DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts)); 8978 } 8979 8980 /* Compute c_i, f_i and their norms */ 8981 for (i = 0; i < nc; i++) { 8982 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8983 fi[i] = fg->centroid[i] - cg->centroid[i]; 8984 Ai[i] = fg->normal[i]; 8985 normci += PetscPowReal(ci[i], 2); 8986 normfi += PetscPowReal(fi[i], 2); 8987 normai += PetscPowReal(Ai[i], 2); 8988 } 8989 normci = PetscSqrtReal(normci); 8990 normfi = PetscSqrtReal(normfi); 8991 normai = PetscSqrtReal(normai); 8992 8993 /* Normalize and compute for each face-cell-normal pair */ 8994 for (i = 0; i < nc; i++) { 8995 ci[i] = ci[i]/normci; 8996 fi[i] = fi[i]/normfi; 8997 Ai[i] = Ai[i]/normai; 8998 /* PetscAbs because I don't know if normals are guaranteed to point out */ 8999 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 9000 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 9001 } 9002 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 9003 minvalc = PetscRealPart(cArr[cellneighiter]); 9004 } 9005 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 9006 minvalf = PetscRealPart(fArr[cellneighiter]); 9007 } 9008 } 9009 PetscCall(PetscFree(adj)); 9010 PetscCall(PetscFree2(cArr, fArr)); 9011 /* Defer to cell if they're equal */ 9012 oqVals[cellIter] = PetscMin(minvalf, minvalc); 9013 if (OrthQualLabel) { 9014 if (PetscRealPart(oqVals[cellIter]) <= atol) PetscCall(DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE)); 9015 } 9016 } 9017 PetscCall(VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES)); 9018 PetscCall(VecAssemblyBegin(*OrthQual)); 9019 PetscCall(VecAssemblyEnd(*OrthQual)); 9020 PetscCall(VecRestoreArrayRead(cellgeom, &cellGeomArr)); 9021 PetscCall(VecRestoreArrayRead(facegeom, &faceGeomArr)); 9022 PetscCall(PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL)); 9023 if (OrthQualLabel) { 9024 if (vwr) PetscCall(DMLabelView(*OrthQualLabel, vwr)); 9025 } 9026 PetscCall(PetscFree5(idx, oqVals, ci, fi, Ai)); 9027 PetscCall(PetscViewerDestroy(&vwr)); 9028 PetscCall(VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view")); 9029 PetscFunctionReturn(0); 9030 } 9031 9032 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 9033 * interpolator construction */ 9034 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 9035 { 9036 PetscSection section, newSection, gsection; 9037 PetscSF sf; 9038 PetscBool hasConstraints, ghasConstraints; 9039 9040 PetscFunctionBegin; 9041 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9042 PetscValidPointer(odm,2); 9043 PetscCall(DMGetLocalSection(dm, §ion)); 9044 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 9045 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 9046 if (!ghasConstraints) { 9047 PetscCall(PetscObjectReference((PetscObject)dm)); 9048 *odm = dm; 9049 PetscFunctionReturn(0); 9050 } 9051 PetscCall(DMClone(dm, odm)); 9052 PetscCall(DMCopyFields(dm, *odm)); 9053 PetscCall(DMGetLocalSection(*odm, &newSection)); 9054 PetscCall(DMGetPointSF(*odm, &sf)); 9055 PetscCall(PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 9056 PetscCall(DMSetGlobalSection(*odm, gsection)); 9057 PetscCall(PetscSectionDestroy(&gsection)); 9058 PetscFunctionReturn(0); 9059 } 9060 9061 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 9062 { 9063 DM dmco, dmfo; 9064 Mat interpo; 9065 Vec rscale; 9066 Vec cglobalo, clocal; 9067 Vec fglobal, fglobalo, flocal; 9068 PetscBool regular; 9069 9070 PetscFunctionBegin; 9071 PetscCall(DMGetFullDM(dmc, &dmco)); 9072 PetscCall(DMGetFullDM(dmf, &dmfo)); 9073 PetscCall(DMSetCoarseDM(dmfo, dmco)); 9074 PetscCall(DMPlexGetRegularRefinement(dmf, ®ular)); 9075 PetscCall(DMPlexSetRegularRefinement(dmfo, regular)); 9076 PetscCall(DMCreateInterpolation(dmco, dmfo, &interpo, &rscale)); 9077 PetscCall(DMCreateGlobalVector(dmco, &cglobalo)); 9078 PetscCall(DMCreateLocalVector(dmc, &clocal)); 9079 PetscCall(VecSet(cglobalo, 0.)); 9080 PetscCall(VecSet(clocal, 0.)); 9081 PetscCall(DMCreateGlobalVector(dmf, &fglobal)); 9082 PetscCall(DMCreateGlobalVector(dmfo, &fglobalo)); 9083 PetscCall(DMCreateLocalVector(dmf, &flocal)); 9084 PetscCall(VecSet(fglobal, 0.)); 9085 PetscCall(VecSet(fglobalo, 0.)); 9086 PetscCall(VecSet(flocal, 0.)); 9087 PetscCall(DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL)); 9088 PetscCall(DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo)); 9089 PetscCall(DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo)); 9090 PetscCall(MatMult(interpo, cglobalo, fglobalo)); 9091 PetscCall(DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal)); 9092 PetscCall(DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal)); 9093 PetscCall(DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal)); 9094 PetscCall(DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal)); 9095 *shift = fglobal; 9096 PetscCall(VecDestroy(&flocal)); 9097 PetscCall(VecDestroy(&fglobalo)); 9098 PetscCall(VecDestroy(&clocal)); 9099 PetscCall(VecDestroy(&cglobalo)); 9100 PetscCall(VecDestroy(&rscale)); 9101 PetscCall(MatDestroy(&interpo)); 9102 PetscCall(DMDestroy(&dmfo)); 9103 PetscCall(DMDestroy(&dmco)); 9104 PetscFunctionReturn(0); 9105 } 9106 9107 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 9108 { 9109 PetscObject shifto; 9110 Vec shift; 9111 9112 PetscFunctionBegin; 9113 if (!interp) { 9114 Vec rscale; 9115 9116 PetscCall(DMCreateInterpolation(coarse, fine, &interp, &rscale)); 9117 PetscCall(VecDestroy(&rscale)); 9118 } else { 9119 PetscCall(PetscObjectReference((PetscObject)interp)); 9120 } 9121 PetscCall(PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto)); 9122 if (!shifto) { 9123 PetscCall(DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift)); 9124 PetscCall(PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift)); 9125 shifto = (PetscObject) shift; 9126 PetscCall(VecDestroy(&shift)); 9127 } 9128 shift = (Vec) shifto; 9129 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 9130 PetscCall(VecAXPY(fineSol, 1.0, shift)); 9131 PetscCall(MatDestroy(&interp)); 9132 PetscFunctionReturn(0); 9133 } 9134 9135 /* Pointwise interpolation 9136 Just code FEM for now 9137 u^f = I u^c 9138 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 9139 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 9140 I_{ij} = psi^f_i phi^c_j 9141 */ 9142 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 9143 { 9144 PetscSection gsc, gsf; 9145 PetscInt m, n; 9146 void *ctx; 9147 DM cdm; 9148 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 9149 9150 PetscFunctionBegin; 9151 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9152 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9153 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9154 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9155 9156 PetscCall(PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis)); 9157 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation)); 9158 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9159 PetscCall(MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype)); 9160 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9161 9162 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9163 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9164 if (!isRefined || (regular && cdm == dmCoarse)) PetscCall(DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx)); 9165 else PetscCall(DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx)); 9166 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 9167 if (scaling) { 9168 /* Use naive scaling */ 9169 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 9170 } 9171 PetscFunctionReturn(0); 9172 } 9173 9174 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 9175 { 9176 VecScatter ctx; 9177 9178 PetscFunctionBegin; 9179 PetscCall(DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL)); 9180 PetscCall(MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat)); 9181 PetscCall(VecScatterDestroy(&ctx)); 9182 PetscFunctionReturn(0); 9183 } 9184 9185 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9186 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9187 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9188 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 9189 { 9190 const PetscInt Nc = uOff[1] - uOff[0]; 9191 PetscInt c; 9192 for (c = 0; c < Nc; ++c) g0[c*Nc+c] = 1.0; 9193 } 9194 9195 PetscErrorCode DMCreateMassMatrixLumped_Plex(DM dm, Vec *mass) 9196 { 9197 DM dmc; 9198 PetscDS ds; 9199 Vec ones, locmass; 9200 IS cellIS; 9201 PetscFormKey key; 9202 PetscInt depth; 9203 9204 PetscFunctionBegin; 9205 PetscCall(DMClone(dm, &dmc)); 9206 PetscCall(DMCopyDisc(dm, dmc)); 9207 PetscCall(DMGetDS(dmc, &ds)); 9208 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9209 PetscCall(DMCreateGlobalVector(dmc, mass)); 9210 PetscCall(DMGetLocalVector(dmc, &ones)); 9211 PetscCall(DMGetLocalVector(dmc, &locmass)); 9212 PetscCall(DMPlexGetDepth(dmc, &depth)); 9213 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9214 PetscCall(VecSet(locmass, 0.0)); 9215 PetscCall(VecSet(ones, 1.0)); 9216 key.label = NULL; 9217 key.value = 0; 9218 key.field = 0; 9219 key.part = 0; 9220 PetscCall(DMPlexComputeJacobian_Action_Internal(dmc, key, cellIS, 0.0, 0.0, ones, NULL, ones, locmass, NULL)); 9221 PetscCall(ISDestroy(&cellIS)); 9222 PetscCall(VecSet(*mass, 0.0)); 9223 PetscCall(DMLocalToGlobalBegin(dmc, locmass, ADD_VALUES, *mass)); 9224 PetscCall(DMLocalToGlobalEnd(dmc, locmass, ADD_VALUES, *mass)); 9225 PetscCall(DMRestoreLocalVector(dmc, &ones)); 9226 PetscCall(DMRestoreLocalVector(dmc, &locmass)); 9227 PetscCall(DMDestroy(&dmc)); 9228 PetscFunctionReturn(0); 9229 } 9230 9231 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 9232 { 9233 PetscSection gsc, gsf; 9234 PetscInt m, n; 9235 void *ctx; 9236 DM cdm; 9237 PetscBool regular; 9238 9239 PetscFunctionBegin; 9240 if (dmFine == dmCoarse) { 9241 DM dmc; 9242 PetscDS ds; 9243 PetscWeakForm wf; 9244 Vec u; 9245 IS cellIS; 9246 PetscFormKey key; 9247 PetscInt depth; 9248 9249 PetscCall(DMClone(dmFine, &dmc)); 9250 PetscCall(DMCopyDisc(dmFine, dmc)); 9251 PetscCall(DMGetDS(dmc, &ds)); 9252 PetscCall(PetscDSGetWeakForm(ds, &wf)); 9253 PetscCall(PetscWeakFormClear(wf)); 9254 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL)); 9255 PetscCall(DMCreateMatrix(dmc, mass)); 9256 PetscCall(DMGetGlobalVector(dmc, &u)); 9257 PetscCall(DMPlexGetDepth(dmc, &depth)); 9258 PetscCall(DMGetStratumIS(dmc, "depth", depth, &cellIS)); 9259 PetscCall(MatZeroEntries(*mass)); 9260 key.label = NULL; 9261 key.value = 0; 9262 key.field = 0; 9263 key.part = 0; 9264 PetscCall(DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL)); 9265 PetscCall(ISDestroy(&cellIS)); 9266 PetscCall(DMRestoreGlobalVector(dmc, &u)); 9267 PetscCall(DMDestroy(&dmc)); 9268 } else { 9269 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 9270 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 9271 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 9272 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 9273 9274 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass)); 9275 PetscCall(MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 9276 PetscCall(MatSetType(*mass, dmCoarse->mattype)); 9277 PetscCall(DMGetApplicationContext(dmFine, &ctx)); 9278 9279 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 9280 PetscCall(DMPlexGetRegularRefinement(dmFine, ®ular)); 9281 if (regular && cdm == dmCoarse) PetscCall(DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx)); 9282 else PetscCall(DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx)); 9283 } 9284 PetscCall(MatViewFromOptions(*mass, NULL, "-mass_mat_view")); 9285 PetscFunctionReturn(0); 9286 } 9287 9288 /*@ 9289 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9290 9291 Input Parameter: 9292 . dm - The DMPlex object 9293 9294 Output Parameter: 9295 . regular - The flag 9296 9297 Level: intermediate 9298 9299 .seealso: DMPlexSetRegularRefinement() 9300 @*/ 9301 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 9302 { 9303 PetscFunctionBegin; 9304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9305 PetscValidBoolPointer(regular, 2); 9306 *regular = ((DM_Plex *) dm->data)->regularRefinement; 9307 PetscFunctionReturn(0); 9308 } 9309 9310 /*@ 9311 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 9312 9313 Input Parameters: 9314 + dm - The DMPlex object 9315 - regular - The flag 9316 9317 Level: intermediate 9318 9319 .seealso: DMPlexGetRegularRefinement() 9320 @*/ 9321 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 9322 { 9323 PetscFunctionBegin; 9324 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9325 ((DM_Plex *) dm->data)->regularRefinement = regular; 9326 PetscFunctionReturn(0); 9327 } 9328 9329 /* anchors */ 9330 /*@ 9331 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 9332 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetDefaultConstraints(). 9333 9334 not collective 9335 9336 Input Parameter: 9337 . dm - The DMPlex object 9338 9339 Output Parameters: 9340 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 9341 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 9342 9343 Level: intermediate 9344 9345 .seealso: DMPlexSetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9346 @*/ 9347 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 9348 { 9349 DM_Plex *plex = (DM_Plex *)dm->data; 9350 9351 PetscFunctionBegin; 9352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9353 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) PetscCall((*plex->createanchors)(dm)); 9354 if (anchorSection) *anchorSection = plex->anchorSection; 9355 if (anchorIS) *anchorIS = plex->anchorIS; 9356 PetscFunctionReturn(0); 9357 } 9358 9359 /*@ 9360 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 9361 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9362 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9363 9364 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9365 DMGetDefaultConstraints() and filling in the entries in the constraint matrix. 9366 9367 collective on dm 9368 9369 Input Parameters: 9370 + dm - The DMPlex object 9371 . 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). 9372 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9373 9374 The reference counts of anchorSection and anchorIS are incremented. 9375 9376 Level: intermediate 9377 9378 .seealso: DMPlexGetAnchors(), DMGetDefaultConstraints(), DMSetDefaultConstraints() 9379 @*/ 9380 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9381 { 9382 DM_Plex *plex = (DM_Plex *)dm->data; 9383 PetscMPIInt result; 9384 9385 PetscFunctionBegin; 9386 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9387 if (anchorSection) { 9388 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9389 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result)); 9390 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9391 } 9392 if (anchorIS) { 9393 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9394 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result)); 9395 PetscCheckFalse(result != MPI_CONGRUENT && result != MPI_IDENT,PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9396 } 9397 9398 PetscCall(PetscObjectReference((PetscObject)anchorSection)); 9399 PetscCall(PetscSectionDestroy(&plex->anchorSection)); 9400 plex->anchorSection = anchorSection; 9401 9402 PetscCall(PetscObjectReference((PetscObject)anchorIS)); 9403 PetscCall(ISDestroy(&plex->anchorIS)); 9404 plex->anchorIS = anchorIS; 9405 9406 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9407 PetscInt size, a, pStart, pEnd; 9408 const PetscInt *anchors; 9409 9410 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9411 PetscCall(ISGetLocalSize(anchorIS,&size)); 9412 PetscCall(ISGetIndices(anchorIS,&anchors)); 9413 for (a = 0; a < size; a++) { 9414 PetscInt p; 9415 9416 p = anchors[a]; 9417 if (p >= pStart && p < pEnd) { 9418 PetscInt dof; 9419 9420 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9421 if (dof) { 9422 9423 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9424 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %" PetscInt_FMT " cannot be constrained and an anchor",p); 9425 } 9426 } 9427 } 9428 PetscCall(ISRestoreIndices(anchorIS,&anchors)); 9429 } 9430 /* reset the generic constraints */ 9431 PetscCall(DMSetDefaultConstraints(dm,NULL,NULL,NULL)); 9432 PetscFunctionReturn(0); 9433 } 9434 9435 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9436 { 9437 PetscSection anchorSection; 9438 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9439 9440 PetscFunctionBegin; 9441 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9442 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9443 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,cSec)); 9444 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9445 if (numFields) { 9446 PetscInt f; 9447 PetscCall(PetscSectionSetNumFields(*cSec,numFields)); 9448 9449 for (f = 0; f < numFields; f++) { 9450 PetscInt numComp; 9451 9452 PetscCall(PetscSectionGetFieldComponents(section,f,&numComp)); 9453 PetscCall(PetscSectionSetFieldComponents(*cSec,f,numComp)); 9454 } 9455 } 9456 PetscCall(PetscSectionGetChart(anchorSection,&pStart,&pEnd)); 9457 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9458 pStart = PetscMax(pStart,sStart); 9459 pEnd = PetscMin(pEnd,sEnd); 9460 pEnd = PetscMax(pStart,pEnd); 9461 PetscCall(PetscSectionSetChart(*cSec,pStart,pEnd)); 9462 for (p = pStart; p < pEnd; p++) { 9463 PetscCall(PetscSectionGetDof(anchorSection,p,&dof)); 9464 if (dof) { 9465 PetscCall(PetscSectionGetDof(section,p,&dof)); 9466 PetscCall(PetscSectionSetDof(*cSec,p,dof)); 9467 for (f = 0; f < numFields; f++) { 9468 PetscCall(PetscSectionGetFieldDof(section,p,f,&dof)); 9469 PetscCall(PetscSectionSetFieldDof(*cSec,p,f,dof)); 9470 } 9471 } 9472 } 9473 PetscCall(PetscSectionSetUp(*cSec)); 9474 PetscCall(PetscObjectSetName((PetscObject) *cSec, "Constraint Section")); 9475 PetscFunctionReturn(0); 9476 } 9477 9478 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9479 { 9480 PetscSection aSec; 9481 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9482 const PetscInt *anchors; 9483 PetscInt numFields, f; 9484 IS aIS; 9485 MatType mtype; 9486 PetscBool iscuda,iskokkos; 9487 9488 PetscFunctionBegin; 9489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9490 PetscCall(PetscSectionGetStorageSize(cSec, &m)); 9491 PetscCall(PetscSectionGetStorageSize(section, &n)); 9492 PetscCall(MatCreate(PETSC_COMM_SELF,cMat)); 9493 PetscCall(MatSetSizes(*cMat,m,n,m,n)); 9494 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda)); 9495 if (!iscuda) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda)); 9496 PetscCall(PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos)); 9497 if (!iskokkos) PetscCall(PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos)); 9498 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9499 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9500 else mtype = MATSEQAIJ; 9501 PetscCall(MatSetType(*cMat,mtype)); 9502 PetscCall(DMPlexGetAnchors(dm,&aSec,&aIS)); 9503 PetscCall(ISGetIndices(aIS,&anchors)); 9504 /* cSec will be a subset of aSec and section */ 9505 PetscCall(PetscSectionGetChart(cSec,&pStart,&pEnd)); 9506 PetscCall(PetscSectionGetChart(section,&sStart,&sEnd)); 9507 PetscCall(PetscMalloc1(m+1,&i)); 9508 i[0] = 0; 9509 PetscCall(PetscSectionGetNumFields(section,&numFields)); 9510 for (p = pStart; p < pEnd; p++) { 9511 PetscInt rDof, rOff, r; 9512 9513 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9514 if (!rDof) continue; 9515 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9516 if (numFields) { 9517 for (f = 0; f < numFields; f++) { 9518 annz = 0; 9519 for (r = 0; r < rDof; r++) { 9520 a = anchors[rOff + r]; 9521 if (a < sStart || a >= sEnd) continue; 9522 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9523 annz += aDof; 9524 } 9525 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9526 PetscCall(PetscSectionGetFieldOffset(cSec,p,f,&off)); 9527 for (q = 0; q < dof; q++) { 9528 i[off + q + 1] = i[off + q] + annz; 9529 } 9530 } 9531 } else { 9532 annz = 0; 9533 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9534 for (q = 0; q < dof; q++) { 9535 a = anchors[rOff + q]; 9536 if (a < sStart || a >= sEnd) continue; 9537 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9538 annz += aDof; 9539 } 9540 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9541 PetscCall(PetscSectionGetOffset(cSec,p,&off)); 9542 for (q = 0; q < dof; q++) { 9543 i[off + q + 1] = i[off + q] + annz; 9544 } 9545 } 9546 } 9547 nnz = i[m]; 9548 PetscCall(PetscMalloc1(nnz,&j)); 9549 offset = 0; 9550 for (p = pStart; p < pEnd; p++) { 9551 if (numFields) { 9552 for (f = 0; f < numFields; f++) { 9553 PetscCall(PetscSectionGetFieldDof(cSec,p,f,&dof)); 9554 for (q = 0; q < dof; q++) { 9555 PetscInt rDof, rOff, r; 9556 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9557 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9558 for (r = 0; r < rDof; r++) { 9559 PetscInt s; 9560 9561 a = anchors[rOff + r]; 9562 if (a < sStart || a >= sEnd) continue; 9563 PetscCall(PetscSectionGetFieldDof(section,a,f,&aDof)); 9564 PetscCall(PetscSectionGetFieldOffset(section,a,f,&aOff)); 9565 for (s = 0; s < aDof; s++) { 9566 j[offset++] = aOff + s; 9567 } 9568 } 9569 } 9570 } 9571 } else { 9572 PetscCall(PetscSectionGetDof(cSec,p,&dof)); 9573 for (q = 0; q < dof; q++) { 9574 PetscInt rDof, rOff, r; 9575 PetscCall(PetscSectionGetDof(aSec,p,&rDof)); 9576 PetscCall(PetscSectionGetOffset(aSec,p,&rOff)); 9577 for (r = 0; r < rDof; r++) { 9578 PetscInt s; 9579 9580 a = anchors[rOff + r]; 9581 if (a < sStart || a >= sEnd) continue; 9582 PetscCall(PetscSectionGetDof(section,a,&aDof)); 9583 PetscCall(PetscSectionGetOffset(section,a,&aOff)); 9584 for (s = 0; s < aDof; s++) { 9585 j[offset++] = aOff + s; 9586 } 9587 } 9588 } 9589 } 9590 } 9591 PetscCall(MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL)); 9592 PetscCall(PetscFree(i)); 9593 PetscCall(PetscFree(j)); 9594 PetscCall(ISRestoreIndices(aIS,&anchors)); 9595 PetscFunctionReturn(0); 9596 } 9597 9598 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9599 { 9600 DM_Plex *plex = (DM_Plex *)dm->data; 9601 PetscSection anchorSection, section, cSec; 9602 Mat cMat; 9603 9604 PetscFunctionBegin; 9605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9606 PetscCall(DMPlexGetAnchors(dm,&anchorSection,NULL)); 9607 if (anchorSection) { 9608 PetscInt Nf; 9609 9610 PetscCall(DMGetLocalSection(dm,§ion)); 9611 PetscCall(DMPlexCreateConstraintSection_Anchors(dm,section,&cSec)); 9612 PetscCall(DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat)); 9613 PetscCall(DMGetNumFields(dm,&Nf)); 9614 if (Nf && plex->computeanchormatrix) PetscCall((*plex->computeanchormatrix)(dm,section,cSec,cMat)); 9615 PetscCall(DMSetDefaultConstraints(dm,cSec,cMat,NULL)); 9616 PetscCall(PetscSectionDestroy(&cSec)); 9617 PetscCall(MatDestroy(&cMat)); 9618 } 9619 PetscFunctionReturn(0); 9620 } 9621 9622 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9623 { 9624 IS subis; 9625 PetscSection section, subsection; 9626 9627 PetscFunctionBegin; 9628 PetscCall(DMGetLocalSection(dm, §ion)); 9629 PetscCheck(section,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9630 PetscCheck(subdm,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9631 /* Create subdomain */ 9632 PetscCall(DMPlexFilter(dm, label, value, subdm)); 9633 /* Create submodel */ 9634 PetscCall(DMPlexGetSubpointIS(*subdm, &subis)); 9635 PetscCall(PetscSectionCreateSubmeshSection(section, subis, &subsection)); 9636 PetscCall(DMSetLocalSection(*subdm, subsection)); 9637 PetscCall(PetscSectionDestroy(&subsection)); 9638 PetscCall(DMCopyDisc(dm, *subdm)); 9639 /* Create map from submodel to global model */ 9640 if (is) { 9641 PetscSection sectionGlobal, subsectionGlobal; 9642 IS spIS; 9643 const PetscInt *spmap; 9644 PetscInt *subIndices; 9645 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9646 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9647 9648 PetscCall(DMPlexGetSubpointIS(*subdm, &spIS)); 9649 PetscCall(ISGetIndices(spIS, &spmap)); 9650 PetscCall(PetscSectionGetNumFields(section, &Nf)); 9651 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 9652 PetscCall(DMGetGlobalSection(*subdm, &subsectionGlobal)); 9653 PetscCall(PetscSectionGetChart(subsection, &pStart, &pEnd)); 9654 for (p = pStart; p < pEnd; ++p) { 9655 PetscInt gdof, pSubSize = 0; 9656 9657 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 9658 if (gdof > 0) { 9659 for (f = 0; f < Nf; ++f) { 9660 PetscInt fdof, fcdof; 9661 9662 PetscCall(PetscSectionGetFieldDof(subsection, p, f, &fdof)); 9663 PetscCall(PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof)); 9664 pSubSize += fdof-fcdof; 9665 } 9666 subSize += pSubSize; 9667 if (pSubSize) { 9668 if (bs < 0) { 9669 bs = pSubSize; 9670 } else if (bs != pSubSize) { 9671 /* Layout does not admit a pointwise block size */ 9672 bs = 1; 9673 } 9674 } 9675 } 9676 } 9677 /* Must have same blocksize on all procs (some might have no points) */ 9678 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9679 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax)); 9680 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9681 else {bs = bsMinMax[0];} 9682 PetscCall(PetscMalloc1(subSize, &subIndices)); 9683 for (p = pStart; p < pEnd; ++p) { 9684 PetscInt gdof, goff; 9685 9686 PetscCall(PetscSectionGetDof(subsectionGlobal, p, &gdof)); 9687 if (gdof > 0) { 9688 const PetscInt point = spmap[p]; 9689 9690 PetscCall(PetscSectionGetOffset(sectionGlobal, point, &goff)); 9691 for (f = 0; f < Nf; ++f) { 9692 PetscInt fdof, fcdof, fc, f2, poff = 0; 9693 9694 /* Can get rid of this loop by storing field information in the global section */ 9695 for (f2 = 0; f2 < f; ++f2) { 9696 PetscCall(PetscSectionGetFieldDof(section, p, f2, &fdof)); 9697 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof)); 9698 poff += fdof-fcdof; 9699 } 9700 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 9701 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 9702 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9703 subIndices[subOff] = goff+poff+fc; 9704 } 9705 } 9706 } 9707 } 9708 PetscCall(ISRestoreIndices(spIS, &spmap)); 9709 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is)); 9710 if (bs > 1) { 9711 /* We need to check that the block size does not come from non-contiguous fields */ 9712 PetscInt i, j, set = 1; 9713 for (i = 0; i < subSize; i += bs) { 9714 for (j = 0; j < bs; ++j) { 9715 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9716 } 9717 } 9718 if (set) PetscCall(ISSetBlockSize(*is, bs)); 9719 } 9720 /* Attach nullspace */ 9721 for (f = 0; f < Nf; ++f) { 9722 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9723 if ((*subdm)->nullspaceConstructors[f]) break; 9724 } 9725 if (f < Nf) { 9726 MatNullSpace nullSpace; 9727 PetscCall((*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace)); 9728 9729 PetscCall(PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace)); 9730 PetscCall(MatNullSpaceDestroy(&nullSpace)); 9731 } 9732 } 9733 PetscFunctionReturn(0); 9734 } 9735 9736 /*@ 9737 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9738 9739 Input Parameter: 9740 - dm - The DM 9741 9742 Level: developer 9743 9744 Options Database Keys: 9745 . -dm_plex_monitor_throughput - Activate the monitor 9746 9747 .seealso: DMSetFromOptions(), DMPlexCreate() 9748 @*/ 9749 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9750 { 9751 #if defined(PETSC_USE_LOG) 9752 PetscStageLog stageLog; 9753 PetscLogEvent event; 9754 PetscLogStage stage; 9755 PetscEventPerfInfo eventInfo; 9756 PetscReal cellRate, flopRate; 9757 PetscInt cStart, cEnd, Nf, N; 9758 const char *name; 9759 #endif 9760 9761 PetscFunctionBegin; 9762 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9763 #if defined(PETSC_USE_LOG) 9764 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 9765 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 9766 PetscCall(DMGetNumFields(dm, &Nf)); 9767 PetscCall(PetscLogGetStageLog(&stageLog)); 9768 PetscCall(PetscStageLogGetCurrent(stageLog, &stage)); 9769 PetscCall(PetscLogEventGetId("DMPlexResidualFE", &event)); 9770 PetscCall(PetscLogEventGetPerfInfo(stage, event, &eventInfo)); 9771 N = (cEnd - cStart)*Nf*eventInfo.count; 9772 flopRate = eventInfo.flops/eventInfo.time; 9773 cellRate = N/eventInfo.time; 9774 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))); 9775 #else 9776 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9777 #endif 9778 PetscFunctionReturn(0); 9779 } 9780