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