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 10 /* Logging support */ 11 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; 12 13 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 14 15 /*@ 16 DMPlexRefineSimplexToTensor - Uniformly refines simplicial cells into tensor product cells. 17 3 quadrilaterals per triangle in 2D and 4 hexahedra per tetrahedron in 3D. 18 19 Collective 20 21 Input Parameters: 22 . dm - The DMPlex object 23 24 Output Parameters: 25 . dmRefined - The refined DMPlex object 26 27 Note: Returns NULL if the mesh is already a tensor product mesh. 28 29 Level: intermediate 30 31 .seealso: DMPlexCreate(), DMPlexSetRefinementUniform() 32 @*/ 33 PetscErrorCode DMPlexRefineSimplexToTensor(DM dm, DM *dmRefined) 34 { 35 CellRefiner cellRefiner; 36 DMPolytopeType ct; 37 PetscInt dim, cMax, fMax, cStart, cEnd; 38 PetscBool lop, allnoop, localized; 39 PetscErrorCode ierr; 40 41 PetscFunctionBegin; 42 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 43 PetscValidPointer(dmRefined, 1); 44 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 45 ierr = DMPlexGetHybridBounds(dm,&cMax,&fMax,NULL,NULL);CHKERRQ(ierr); 46 ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); 47 if (!(cEnd - cStart)) cellRefiner = REFINER_NOOP; 48 else { 49 ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 50 switch (ct) { 51 case DM_POLYTOPE_POINT: 52 case DM_POLYTOPE_SEGMENT: 53 cellRefiner = REFINER_NOOP;break; 54 case DM_POLYTOPE_TRIANGLE: 55 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D; 56 else cellRefiner = REFINER_SIMPLEX_TO_HEX_2D; 57 break; 58 case DM_POLYTOPE_QUADRILATERAL: 59 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_2D; 60 else cellRefiner = REFINER_NOOP; 61 break; 62 case DM_POLYTOPE_TETRAHEDRON: 63 if (cMax >= 0) cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D; 64 else cellRefiner = REFINER_SIMPLEX_TO_HEX_3D; 65 break; 66 case DM_POLYTOPE_TRI_PRISM_TENSOR: 67 cellRefiner = REFINER_HYBRID_SIMPLEX_TO_HEX_3D;break; 68 case DM_POLYTOPE_HEXAHEDRON: 69 if (cMax >= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Simplex2Tensor in 3D with Hybrid mesh not yet done"); 70 else cellRefiner = REFINER_NOOP; 71 break; 72 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot handle cell polytope type %s", DMPolytopeTypes[ct]); 73 } 74 } 75 /* return if we don't need to refine */ 76 lop = (cellRefiner == REFINER_NOOP) ? PETSC_TRUE : PETSC_FALSE; 77 ierr = MPIU_Allreduce(&lop,&allnoop,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 78 if (allnoop) { 79 *dmRefined = NULL; 80 PetscFunctionReturn(0); 81 } 82 ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr); 83 ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr); 84 ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr); 85 if (localized) { 86 ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr); 87 } 88 PetscFunctionReturn(0); 89 } 90 91 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 92 { 93 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cMax; 94 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 95 PetscErrorCode ierr; 96 97 PetscFunctionBegin; 98 *ft = PETSC_VTK_INVALID; 99 ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr); 100 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 101 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 102 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 103 cEnd = cMax < 0 ? cEnd : cMax; 104 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 105 if (field >= 0) { 106 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);} 107 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);} 108 } else { 109 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);} 110 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);} 111 } 112 ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 113 if (globalvcdof[0]) { 114 *sStart = vStart; 115 *sEnd = vEnd; 116 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 117 else *ft = PETSC_VTK_POINT_FIELD; 118 } else if (globalvcdof[1]) { 119 *sStart = cStart; 120 *sEnd = cEnd; 121 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 122 else *ft = PETSC_VTK_CELL_FIELD; 123 } else { 124 if (field >= 0) { 125 const char *fieldname; 126 127 ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr); 128 ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr); 129 } else { 130 ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output typp of section\"%s\"\n");CHKERRQ(ierr); 131 } 132 } 133 PetscFunctionReturn(0); 134 } 135 136 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 137 { 138 DM dm; 139 PetscSection s; 140 PetscDraw draw, popup; 141 DM cdm; 142 PetscSection coordSection; 143 Vec coordinates; 144 const PetscScalar *coords, *array; 145 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 146 PetscReal vbound[2], time; 147 PetscBool isnull, flg; 148 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 149 const char *name; 150 char title[PETSC_MAX_PATH_LEN]; 151 PetscErrorCode ierr; 152 153 PetscFunctionBegin; 154 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 155 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 156 if (isnull) PetscFunctionReturn(0); 157 158 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 159 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 160 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim); 161 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 162 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 163 ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr); 164 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 165 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 166 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 167 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 168 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 169 170 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 171 ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr); 172 173 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 174 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 175 for (c = 0; c < N; c += dim) { 176 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 177 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 178 } 179 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 180 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 181 182 /* Could implement something like DMDASelectFields() */ 183 for (f = 0; f < Nf; ++f) { 184 DM fdm = dm; 185 Vec fv = v; 186 IS fis; 187 char prefix[PETSC_MAX_PATH_LEN]; 188 const char *fname; 189 190 ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr); 191 ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr); 192 193 if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);} 194 else {prefix[0] = '\0';} 195 if (Nf > 1) { 196 ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr); 197 ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr); 198 ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr); 199 ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr); 200 } 201 for (comp = 0; comp < Nc; ++comp, ++w) { 202 PetscInt nmax = 2; 203 204 ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr); 205 if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);} 206 else {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);} 207 ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr); 208 209 /* TODO Get max and min only for this component */ 210 ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr); 211 if (!flg) { 212 ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr); 213 ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr); 214 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 215 } 216 ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr); 217 ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr); 218 ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr); 219 220 ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr); 221 for (c = cStart; c < cEnd; ++c) { 222 PetscScalar *coords = NULL, *a = NULL; 223 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 224 225 ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr); 226 if (a) { 227 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 228 color[1] = color[2] = color[3] = color[0]; 229 } else { 230 PetscScalar *vals = NULL; 231 PetscInt numVals, va; 232 233 ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 234 if (numVals % Nc) SETERRQ2(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); 235 switch (numVals/Nc) { 236 case 3: /* P1 Triangle */ 237 case 4: /* P1 Quadrangle */ 238 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 239 break; 240 case 6: /* P2 Triangle */ 241 case 8: /* P2 Quadrangle */ 242 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 243 break; 244 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc); 245 } 246 ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 247 } 248 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 249 switch (numCoords) { 250 case 6: 251 ierr = 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]);CHKERRQ(ierr); 252 break; 253 case 8: 254 ierr = 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]);CHKERRQ(ierr); 255 ierr = 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]);CHKERRQ(ierr); 256 break; 257 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 258 } 259 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 260 } 261 ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr); 262 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 263 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 264 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 265 } 266 if (Nf > 1) { 267 ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr); 268 ierr = ISDestroy(&fis);CHKERRQ(ierr); 269 ierr = DMDestroy(&fdm);CHKERRQ(ierr); 270 } 271 } 272 PetscFunctionReturn(0); 273 } 274 275 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 276 { 277 DM dm; 278 Vec locv; 279 const char *name; 280 PetscSection section; 281 PetscInt pStart, pEnd; 282 PetscInt numFields; 283 PetscViewerVTKFieldType ft; 284 PetscErrorCode ierr; 285 286 PetscFunctionBegin; 287 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 288 ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */ 289 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 290 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 291 ierr = VecCopy(v, locv);CHKERRQ(ierr); 292 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 293 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 294 if (!numFields) { 295 ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr); 296 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 297 } else { 298 PetscInt f; 299 300 for (f = 0; f < numFields; f++) { 301 ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr); 302 if (ft == PETSC_VTK_INVALID) continue; 303 ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr); 304 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 305 } 306 ierr = VecDestroy(&locv);CHKERRQ(ierr); 307 } 308 PetscFunctionReturn(0); 309 } 310 311 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 312 { 313 DM dm; 314 PetscBool isvtk, ishdf5, isdraw, isglvis; 315 PetscErrorCode ierr; 316 317 PetscFunctionBegin; 318 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 319 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 320 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 321 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 322 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 323 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 324 if (isvtk || ishdf5 || isdraw || isglvis) { 325 PetscInt i,numFields; 326 PetscObject fe; 327 PetscBool fem = PETSC_FALSE; 328 Vec locv = v; 329 const char *name; 330 PetscInt step; 331 PetscReal time; 332 333 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 334 for (i=0; i<numFields; i++) { 335 ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr); 336 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 337 } 338 if (fem) { 339 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 340 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 341 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 342 ierr = VecCopy(v, locv);CHKERRQ(ierr); 343 ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr); 344 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr); 345 } 346 if (isvtk) { 347 ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr); 348 } else if (ishdf5) { 349 #if defined(PETSC_HAVE_HDF5) 350 ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr); 351 #else 352 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 353 #endif 354 } else if (isdraw) { 355 ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr); 356 } else if (isglvis) { 357 ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr); 358 ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr); 359 ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr); 360 } 361 if (fem) {ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);} 362 } else { 363 PetscBool isseq; 364 365 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 366 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 367 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 368 } 369 PetscFunctionReturn(0); 370 } 371 372 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 373 { 374 DM dm; 375 PetscBool isvtk, ishdf5, isdraw, isglvis; 376 PetscErrorCode ierr; 377 378 PetscFunctionBegin; 379 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 380 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 381 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 382 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 383 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 384 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 385 if (isvtk || isdraw || isglvis) { 386 Vec locv; 387 const char *name; 388 389 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 390 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 391 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 392 ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 393 ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 394 ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr); 395 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 396 } else if (ishdf5) { 397 #if defined(PETSC_HAVE_HDF5) 398 ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 399 #else 400 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 401 #endif 402 } else { 403 PetscBool isseq; 404 405 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 406 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 407 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 408 } 409 PetscFunctionReturn(0); 410 } 411 412 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 413 { 414 DM dm; 415 MPI_Comm comm; 416 PetscViewerFormat format; 417 Vec v; 418 PetscBool isvtk, ishdf5; 419 PetscErrorCode ierr; 420 421 PetscFunctionBegin; 422 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 423 ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr); 424 if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 425 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 426 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 427 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 428 if (format == PETSC_VIEWER_NATIVE) { 429 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 430 /* this need a better fix */ 431 if (dm->useNatural) { 432 if (dm->sfNatural) { 433 const char *vecname; 434 PetscInt n, nroots; 435 436 ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr); 437 ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 438 if (n == nroots) { 439 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 440 ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr); 441 ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr); 442 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 443 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 444 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 445 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 446 } else v = originalv; 447 } else v = originalv; 448 449 if (ishdf5) { 450 #if defined(PETSC_HAVE_HDF5) 451 ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 452 #else 453 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 454 #endif 455 } else if (isvtk) { 456 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 457 } else { 458 PetscBool isseq; 459 460 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 461 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 462 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 463 } 464 if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);} 465 PetscFunctionReturn(0); 466 } 467 468 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 469 { 470 DM dm; 471 PetscBool ishdf5; 472 PetscErrorCode ierr; 473 474 PetscFunctionBegin; 475 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 476 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 477 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 478 if (ishdf5) { 479 DM dmBC; 480 Vec gv; 481 const char *name; 482 483 ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr); 484 ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr); 485 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 486 ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr); 487 ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr); 488 ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 489 ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 490 ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr); 491 } else { 492 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 493 } 494 PetscFunctionReturn(0); 495 } 496 497 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 498 { 499 DM dm; 500 PetscBool ishdf5; 501 PetscErrorCode ierr; 502 503 PetscFunctionBegin; 504 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 505 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 506 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 507 if (ishdf5) { 508 #if defined(PETSC_HAVE_HDF5) 509 ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 510 #else 511 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 512 #endif 513 } else { 514 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 515 } 516 PetscFunctionReturn(0); 517 } 518 519 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 520 { 521 DM dm; 522 PetscViewerFormat format; 523 PetscBool ishdf5; 524 PetscErrorCode ierr; 525 526 PetscFunctionBegin; 527 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 528 if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 529 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 530 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 531 if (format == PETSC_VIEWER_NATIVE) { 532 if (dm->useNatural) { 533 if (dm->sfNatural) { 534 if (ishdf5) { 535 #if defined(PETSC_HAVE_HDF5) 536 Vec v; 537 const char *vecname; 538 539 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 540 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 541 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 542 ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 543 ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr); 544 ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr); 545 ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr); 546 #else 547 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 548 #endif 549 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 550 } 551 } else { 552 ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr); 553 } 554 } 555 PetscFunctionReturn(0); 556 } 557 558 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 559 { 560 PetscSection coordSection; 561 Vec coordinates; 562 DMLabel depthLabel, celltypeLabel; 563 const char *name[4]; 564 const PetscScalar *a; 565 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 566 PetscErrorCode ierr; 567 568 PetscFunctionBegin; 569 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 570 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 571 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 572 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 573 ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr); 574 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 575 ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr); 576 ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr); 577 name[0] = "vertex"; 578 name[1] = "edge"; 579 name[dim-1] = "face"; 580 name[dim] = "cell"; 581 for (c = cStart; c < cEnd; ++c) { 582 PetscInt *closure = NULL; 583 PetscInt closureSize, cl, ct; 584 585 ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr); 586 ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr); 587 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 588 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 589 for (cl = 0; cl < closureSize*2; cl += 2) { 590 PetscInt point = closure[cl], depth, dof, off, d, p; 591 592 if ((point < pStart) || (point >= pEnd)) continue; 593 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 594 if (!dof) continue; 595 ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr); 596 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 597 ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr); 598 for (p = 0; p < dof/dim; ++p) { 599 ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr); 600 for (d = 0; d < dim; ++d) { 601 if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 602 ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr); 603 } 604 ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr); 605 } 606 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 607 } 608 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 609 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 610 } 611 ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr); 612 PetscFunctionReturn(0); 613 } 614 615 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 616 { 617 DM_Plex *mesh = (DM_Plex*) dm->data; 618 DM cdm; 619 DMLabel markers; 620 PetscSection coordSection; 621 Vec coordinates; 622 PetscViewerFormat format; 623 PetscErrorCode ierr; 624 625 PetscFunctionBegin; 626 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 627 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 628 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 629 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 630 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 631 const char *name; 632 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 633 PetscInt pStart, pEnd, p; 634 PetscMPIInt rank, size; 635 636 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 637 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 638 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 639 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 640 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 641 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 642 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 643 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 644 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 645 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 646 ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr); 647 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 648 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr); 649 for (p = pStart; p < pEnd; ++p) { 650 PetscInt dof, off, s; 651 652 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 653 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 654 for (s = off; s < off+dof; ++s) { 655 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr); 656 } 657 } 658 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 659 ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr); 660 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr); 661 for (p = pStart; p < pEnd; ++p) { 662 PetscInt dof, off, c; 663 664 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 665 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 666 for (c = off; c < off+dof; ++c) { 667 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr); 668 } 669 } 670 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 671 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 672 if (coordSection && coordinates) { 673 ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr); 674 } 675 ierr = DMGetLabel(dm, "marker", &markers);CHKERRQ(ierr); 676 if (markers) {ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);} 677 if (size > 1) { 678 PetscSF sf; 679 680 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 681 ierr = PetscSFView(sf, viewer);CHKERRQ(ierr); 682 } 683 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 684 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 685 const char *name, *color; 686 const char *defcolors[3] = {"gray", "orange", "green"}; 687 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 688 char lname[PETSC_MAX_PATH_LEN]; 689 PetscReal scale = 2.0; 690 PetscReal tikzscale = 1.0; 691 PetscBool useNumbers = PETSC_TRUE, useLabels, useColors; 692 double tcoords[3]; 693 PetscScalar *coords; 694 PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p; 695 PetscMPIInt rank, size; 696 char **names, **colors, **lcolors; 697 PetscBool plotEdges, flg, lflg; 698 PetscBT wp = NULL; 699 PetscInt pEnd, pStart; 700 701 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 702 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 703 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 704 numLabels = PetscMax(numLabels, 10); 705 numColors = 10; 706 numLColors = 10; 707 ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr); 708 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr); 709 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr); 710 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr); 711 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr); 712 if (!useLabels) numLabels = 0; 713 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr); 714 if (!useColors) { 715 numColors = 3; 716 for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);} 717 } 718 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr); 719 if (!useColors) { 720 numLColors = 4; 721 for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);} 722 } 723 ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, PETSC_MAX_PATH_LEN, &lflg);CHKERRQ(ierr); 724 plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3); 725 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr); 726 if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 727 if (depth < dim) plotEdges = PETSC_FALSE; 728 729 /* filter points with labelvalue != labeldefaultvalue */ 730 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 731 if (lflg) { 732 DMLabel lbl; 733 734 ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr); 735 if (lbl) { 736 PetscInt val, defval; 737 738 ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr); 739 ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr); 740 for (c = pStart; c < pEnd; c++) { 741 PetscInt *closure = NULL; 742 PetscInt closureSize; 743 744 ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr); 745 if (val == defval) continue; 746 747 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 748 for (p = 0; p < closureSize*2; p += 2) { 749 ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr); 750 } 751 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 752 } 753 } 754 } 755 756 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 757 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 758 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 759 ierr = PetscViewerASCIIPrintf(viewer, "\ 760 \\documentclass[tikz]{standalone}\n\n\ 761 \\usepackage{pgflibraryshapes}\n\ 762 \\usetikzlibrary{backgrounds}\n\ 763 \\usetikzlibrary{arrows}\n\ 764 \\begin{document}\n");CHKERRQ(ierr); 765 if (size > 1) { 766 ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr); 767 for (p = 0; p < size; ++p) { 768 if (p > 0 && p == size-1) { 769 ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr); 770 } else if (p > 0) { 771 ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr); 772 } 773 ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr); 774 } 775 ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr); 776 } 777 ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr); 778 779 /* Plot vertices */ 780 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 781 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 782 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 783 for (v = vStart; v < vEnd; ++v) { 784 PetscInt off, dof, d; 785 PetscBool isLabeled = PETSC_FALSE; 786 787 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 788 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 789 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 790 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 791 if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof); 792 for (d = 0; d < dof; ++d) { 793 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 794 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 795 } 796 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 797 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 798 for (d = 0; d < dof; ++d) { 799 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 800 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr); 801 } 802 color = colors[rank%numColors]; 803 for (l = 0; l < numLabels; ++l) { 804 PetscInt val; 805 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 806 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 807 } 808 if (useNumbers) { 809 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr); 810 } else { 811 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 812 } 813 } 814 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 815 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 816 /* Plot cells */ 817 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 818 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr); 819 if (dim == 3 || !useNumbers) { 820 for (e = eStart; e < eEnd; ++e) { 821 const PetscInt *cone; 822 823 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 824 color = colors[rank%numColors]; 825 for (l = 0; l < numLabels; ++l) { 826 PetscInt val; 827 ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr); 828 if (val >= 0) {color = lcolors[l%numLColors]; break;} 829 } 830 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 831 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr); 832 } 833 } else { 834 for (c = cStart; c < cEnd; ++c) { 835 PetscInt *closure = NULL; 836 PetscInt closureSize, firstPoint = -1; 837 838 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 839 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 840 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr); 841 for (p = 0; p < closureSize*2; p += 2) { 842 const PetscInt point = closure[p]; 843 844 if ((point < vStart) || (point >= vEnd)) continue; 845 if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);} 846 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr); 847 if (firstPoint < 0) firstPoint = point; 848 } 849 /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */ 850 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr); 851 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 852 } 853 } 854 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 855 for (c = cStart; c < cEnd; ++c) { 856 double ccoords[3] = {0.0, 0.0, 0.0}; 857 PetscBool isLabeled = PETSC_FALSE; 858 PetscInt *closure = NULL; 859 PetscInt closureSize, dof, d, n = 0; 860 861 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 862 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 863 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 864 for (p = 0; p < closureSize*2; p += 2) { 865 const PetscInt point = closure[p]; 866 PetscInt off; 867 868 if ((point < vStart) || (point >= vEnd)) continue; 869 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 870 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 871 for (d = 0; d < dof; ++d) { 872 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 873 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 874 } 875 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 876 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 877 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 878 ++n; 879 } 880 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 881 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 882 for (d = 0; d < dof; ++d) { 883 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 884 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr); 885 } 886 color = colors[rank%numColors]; 887 for (l = 0; l < numLabels; ++l) { 888 PetscInt val; 889 ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr); 890 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 891 } 892 if (useNumbers) { 893 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr); 894 } else { 895 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 896 } 897 } 898 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 899 /* Plot edges */ 900 if (plotEdges) { 901 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 902 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 903 for (e = eStart; e < eEnd; ++e) { 904 const PetscInt *cone; 905 PetscInt coneSize, offA, offB, dof, d; 906 907 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 908 ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr); 909 if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize); 910 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 911 ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr); 912 ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr); 913 ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr); 914 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 915 for (d = 0; d < dof; ++d) { 916 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 917 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 918 } 919 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 920 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 921 for (d = 0; d < dof; ++d) { 922 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 923 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr); 924 } 925 color = colors[rank%numColors]; 926 for (l = 0; l < numLabels; ++l) { 927 PetscInt val; 928 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 929 if (val >= 0) {color = lcolors[l%numLColors]; break;} 930 } 931 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr); 932 } 933 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 934 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 935 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 936 } 937 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 938 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 939 ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr); 940 ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr); 941 for (l = 0; l < numLabels; ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);} 942 for (c = 0; c < numColors; ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);} 943 for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);} 944 ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr); 945 ierr = PetscBTDestroy(&wp);CHKERRQ(ierr); 946 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 947 Vec cown,acown; 948 VecScatter sct; 949 ISLocalToGlobalMapping g2l; 950 IS gid,acis; 951 MPI_Comm comm,ncomm = MPI_COMM_NULL; 952 MPI_Group ggroup,ngroup; 953 PetscScalar *array,nid; 954 const PetscInt *idxs; 955 PetscInt *idxs2,*start,*adjacency,*work; 956 PetscInt64 lm[3],gm[3]; 957 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 958 PetscMPIInt d1,d2,rank; 959 960 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 961 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 962 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 963 ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRQ(ierr); 964 #endif 965 if (ncomm != MPI_COMM_NULL) { 966 ierr = MPI_Comm_group(comm,&ggroup);CHKERRQ(ierr); 967 ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRQ(ierr); 968 d1 = 0; 969 ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRQ(ierr); 970 nid = d2; 971 ierr = MPI_Group_free(&ggroup);CHKERRQ(ierr); 972 ierr = MPI_Group_free(&ngroup);CHKERRQ(ierr); 973 ierr = MPI_Comm_free(&ncomm);CHKERRQ(ierr); 974 } else nid = 0.0; 975 976 /* Get connectivity */ 977 ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr); 978 ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr); 979 980 /* filter overlapped local cells */ 981 ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr); 982 ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr); 983 ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr); 984 ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr); 985 for (c = cStart, cum = 0; c < cEnd; c++) { 986 if (idxs[c-cStart] < 0) continue; 987 idxs2[cum++] = idxs[c-cStart]; 988 } 989 ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr); 990 if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum); 991 ierr = ISDestroy(&gid);CHKERRQ(ierr); 992 ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr); 993 994 /* support for node-aware cell locality */ 995 ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr); 996 ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr); 997 ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr); 998 ierr = VecGetArray(cown,&array);CHKERRQ(ierr); 999 for (c = 0; c < numVertices; c++) array[c] = nid; 1000 ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr); 1001 ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr); 1002 ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1003 ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1004 ierr = ISDestroy(&acis);CHKERRQ(ierr); 1005 ierr = VecScatterDestroy(&sct);CHKERRQ(ierr); 1006 ierr = VecDestroy(&cown);CHKERRQ(ierr); 1007 1008 /* compute edgeCut */ 1009 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1010 ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr); 1011 ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr); 1012 ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr); 1013 ierr = ISDestroy(&gid);CHKERRQ(ierr); 1014 ierr = VecGetArray(acown,&array);CHKERRQ(ierr); 1015 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1016 PetscInt totl; 1017 1018 totl = start[c+1]-start[c]; 1019 ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr); 1020 for (i = 0; i < totl; i++) { 1021 if (work[i] < 0) { 1022 ect += 1; 1023 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1024 } 1025 } 1026 } 1027 ierr = PetscFree(work);CHKERRQ(ierr); 1028 ierr = VecRestoreArray(acown,&array);CHKERRQ(ierr); 1029 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1030 lm[1] = -numVertices; 1031 ierr = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRQ(ierr); 1032 ierr = PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr); 1033 lm[0] = ect; /* edgeCut */ 1034 lm[1] = ectn; /* node-aware edgeCut */ 1035 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1036 ierr = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRQ(ierr); 1037 ierr = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr); 1038 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1039 ierr = PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),gm[0] ? ((double)(gm[1]))/((double)gm[0]) : 1.);CHKERRQ(ierr); 1040 #else 1041 ierr = PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr); 1042 #endif 1043 ierr = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr); 1044 ierr = PetscFree(start);CHKERRQ(ierr); 1045 ierr = PetscFree(adjacency);CHKERRQ(ierr); 1046 ierr = VecDestroy(&acown);CHKERRQ(ierr); 1047 } else { 1048 MPI_Comm comm; 1049 PetscInt *sizes, *hybsizes, *ghostsizes; 1050 PetscInt locDepth, depth, cellHeight, dim, d, pMax[4]; 1051 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1052 PetscInt numLabels, l; 1053 const char *name; 1054 PetscMPIInt size; 1055 1056 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 1057 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 1058 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1059 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1060 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 1061 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1062 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1063 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 1064 ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr); 1065 ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 1066 ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, depth > 1 ? &pMax[depth - 2] : NULL, &pMax[0]);CHKERRQ(ierr); 1067 ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr); 1068 gcNum = gcEnd - gcStart; 1069 ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr); 1070 if (depth == 1) { 1071 ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 1072 pEnd = pEnd - pStart; 1073 pMax[0] -= pStart; 1074 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1075 ierr = MPI_Gather(&pMax[0], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1076 ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1077 ierr = PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);CHKERRQ(ierr); 1078 for (p = 0; p < size; ++p) { 1079 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1080 else {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 1081 } 1082 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1083 ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 1084 pEnd = pEnd - pStart; 1085 pMax[depth] -= pStart; 1086 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1087 ierr = MPI_Gather(&pMax[depth], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1088 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);CHKERRQ(ierr); 1089 for (p = 0; p < size; ++p) { 1090 ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr); 1091 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1092 if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);} 1093 } 1094 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1095 } else { 1096 PetscMPIInt rank; 1097 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1098 for (d = 0; d <= dim; d++) { 1099 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 1100 pEnd -= pStart; 1101 pMax[d] -= pStart; 1102 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1103 ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 1104 if (d == dim) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);} 1105 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", d);CHKERRQ(ierr); 1106 for (p = 0; p < size; ++p) { 1107 if (!rank) { 1108 ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr); 1109 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 1110 if (d == dim && ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);} 1111 } 1112 } 1113 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1114 } 1115 } 1116 ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr); 1117 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 1118 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 1119 for (l = 0; l < numLabels; ++l) { 1120 DMLabel label; 1121 const char *name; 1122 IS valueIS; 1123 const PetscInt *values; 1124 PetscInt numValues, v; 1125 1126 ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr); 1127 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1128 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 1129 ierr = PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr); 1130 ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr); 1131 ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr); 1132 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 1133 for (v = 0; v < numValues; ++v) { 1134 PetscInt size; 1135 1136 ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr); 1137 if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 1138 ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr); 1139 } 1140 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 1141 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 1142 ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr); 1143 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 1144 } 1145 /* If no fields are specified, people do not want to see adjacency */ 1146 if (dm->Nf) { 1147 PetscInt f; 1148 1149 for (f = 0; f < dm->Nf; ++f) { 1150 const char *name; 1151 1152 ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr); 1153 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);} 1154 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1155 if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);} 1156 if (dm->fields[f].adjacency[0]) { 1157 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);} 1158 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);} 1159 } else { 1160 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);} 1161 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);} 1162 } 1163 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1164 } 1165 } 1166 ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr); 1167 if (cdm) { 1168 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1169 ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr); 1170 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1171 } 1172 } 1173 PetscFunctionReturn(0); 1174 } 1175 1176 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1177 { 1178 PetscDraw draw; 1179 DM cdm; 1180 PetscSection coordSection; 1181 Vec coordinates; 1182 const PetscScalar *coords; 1183 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1184 PetscBool isnull; 1185 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N; 1186 PetscMPIInt rank; 1187 PetscErrorCode ierr; 1188 1189 PetscFunctionBegin; 1190 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 1191 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 1192 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 1193 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 1194 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1195 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1196 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1197 1198 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 1199 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 1200 if (isnull) PetscFunctionReturn(0); 1201 ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr); 1202 1203 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 1204 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 1205 for (c = 0; c < N; c += dim) { 1206 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1207 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1208 } 1209 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 1210 ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1211 ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1212 ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr); 1213 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 1214 1215 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 1216 for (c = cStart; c < cEnd; ++c) { 1217 PetscScalar *coords = NULL; 1218 DMPolytopeType ct; 1219 PetscInt numCoords; 1220 1221 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 1222 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1223 switch (ct) { 1224 case DM_POLYTOPE_TRIANGLE: 1225 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1226 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1227 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1228 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1229 break; 1230 case DM_POLYTOPE_QUADRILATERAL: 1231 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1232 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1233 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1234 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1235 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1236 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1237 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1238 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1239 break; 1240 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1241 } 1242 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1243 } 1244 for (c = cStart; c < cEnd; ++c) { 1245 PetscScalar *coords = NULL; 1246 DMPolytopeType ct; 1247 PetscInt numCoords; 1248 1249 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 1250 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1251 switch (ct) { 1252 case DM_POLYTOPE_TRIANGLE: 1253 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1254 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1255 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1256 break; 1257 case DM_POLYTOPE_QUADRILATERAL: 1258 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1259 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1260 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1261 ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1262 break; 1263 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1264 } 1265 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1266 } 1267 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 1268 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 1269 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 1270 PetscFunctionReturn(0); 1271 } 1272 1273 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1274 { 1275 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis; 1276 char name[PETSC_MAX_PATH_LEN]; 1277 PetscErrorCode ierr; 1278 1279 PetscFunctionBegin; 1280 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1281 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1282 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1283 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 1284 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1285 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 1286 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 1287 if (iascii) { 1288 PetscViewerFormat format; 1289 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1290 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1291 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1292 } else { 1293 ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr); 1294 } 1295 } else if (ishdf5) { 1296 #if defined(PETSC_HAVE_HDF5) 1297 ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1298 #else 1299 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1300 #endif 1301 } else if (isvtk) { 1302 ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr); 1303 } else if (isdraw) { 1304 ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr); 1305 } else if (isglvis) { 1306 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1307 } else { 1308 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1309 } 1310 /* Optionally view the partition */ 1311 ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr); 1312 if (flg) { 1313 Vec ranks; 1314 ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr); 1315 ierr = VecView(ranks, viewer);CHKERRQ(ierr); 1316 ierr = VecDestroy(&ranks);CHKERRQ(ierr); 1317 } 1318 /* Optionally view a label */ 1319 ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, PETSC_MAX_PATH_LEN, &flg);CHKERRQ(ierr); 1320 if (flg) { 1321 DMLabel label; 1322 Vec val; 1323 1324 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1325 if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1326 ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr); 1327 ierr = VecView(val, viewer);CHKERRQ(ierr); 1328 ierr = VecDestroy(&val);CHKERRQ(ierr); 1329 } 1330 PetscFunctionReturn(0); 1331 } 1332 1333 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 1334 { 1335 PetscBool ishdf5; 1336 PetscErrorCode ierr; 1337 1338 PetscFunctionBegin; 1339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1340 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1341 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1342 if (ishdf5) { 1343 #if defined(PETSC_HAVE_HDF5) 1344 PetscViewerFormat format; 1345 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1346 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 1347 ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr); 1348 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1349 ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1350 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1351 #else 1352 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1353 #endif 1354 } else { 1355 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 1356 } 1357 PetscFunctionReturn(0); 1358 } 1359 1360 PetscErrorCode DMDestroy_Plex(DM dm) 1361 { 1362 DM_Plex *mesh = (DM_Plex*) dm->data; 1363 PetscErrorCode ierr; 1364 1365 PetscFunctionBegin; 1366 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr); 1367 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr); 1368 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr); 1369 if (--mesh->refct > 0) PetscFunctionReturn(0); 1370 ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr); 1371 ierr = PetscFree(mesh->cones);CHKERRQ(ierr); 1372 ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr); 1373 ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); 1374 ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr); 1375 ierr = PetscFree(mesh->supports);CHKERRQ(ierr); 1376 ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr); 1377 ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr); 1378 ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr); 1379 ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); 1380 ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr); 1381 ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr); 1382 ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr); 1383 ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr); 1384 ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr); 1385 ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr); 1386 ierr = PetscFree(mesh->parents);CHKERRQ(ierr); 1387 ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr); 1388 ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr); 1389 ierr = PetscFree(mesh->children);CHKERRQ(ierr); 1390 ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr); 1391 ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr); 1392 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 1393 ierr = PetscFree(mesh);CHKERRQ(ierr); 1394 PetscFunctionReturn(0); 1395 } 1396 1397 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 1398 { 1399 PetscSection sectionGlobal; 1400 PetscInt bs = -1, mbs; 1401 PetscInt localSize; 1402 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 1403 PetscErrorCode ierr; 1404 MatType mtype; 1405 ISLocalToGlobalMapping ltog; 1406 1407 PetscFunctionBegin; 1408 ierr = MatInitializePackage();CHKERRQ(ierr); 1409 mtype = dm->mattype; 1410 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 1411 /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */ 1412 ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); 1413 ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr); 1414 ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 1415 ierr = MatSetType(*J, mtype);CHKERRQ(ierr); 1416 ierr = MatSetFromOptions(*J);CHKERRQ(ierr); 1417 ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr); 1418 if (mbs > 1) bs = mbs; 1419 ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr); 1420 ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr); 1421 ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr); 1422 ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr); 1423 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 1424 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 1425 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 1426 ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr); 1427 if (!isShell) { 1428 PetscSection subSection; 1429 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 1430 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize; 1431 PetscInt pStart, pEnd, p, dof, cdof; 1432 1433 /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */ 1434 if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */ 1435 PetscSection section; 1436 PetscInt size; 1437 1438 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1439 ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr); 1440 ierr = PetscMalloc1(size,<ogidx);CHKERRQ(ierr); 1441 ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr); 1442 } else { 1443 ierr = DMGetLocalToGlobalMapping(dm,<og);CHKERRQ(ierr); 1444 } 1445 ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr); 1446 for (p = pStart, lsize = 0; p < pEnd; ++p) { 1447 PetscInt bdof; 1448 1449 ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr); 1450 ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr); 1451 dof = dof < 0 ? -(dof+1) : dof; 1452 bdof = cdof && (dof-cdof) ? 1 : dof; 1453 if (dof) { 1454 if (bs < 0) {bs = bdof;} 1455 else if (bs != bdof) {bs = 1; if (!isMatIS) break;} 1456 } 1457 if (isMatIS) { 1458 PetscInt loff,c,off; 1459 ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr); 1460 ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr); 1461 for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c; 1462 } 1463 } 1464 /* Must have same blocksize on all procs (some might have no points) */ 1465 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 1466 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 1467 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 1468 else {bs = bsMinMax[0];} 1469 bs = PetscMax(1,bs); 1470 if (isMatIS) { /* Must reduce indices by blocksize */ 1471 PetscInt l; 1472 1473 lsize = lsize/bs; 1474 if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs; 1475 ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);CHKERRQ(ierr); 1476 } 1477 ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr); 1478 if (isMatIS) { 1479 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 1480 } 1481 ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr); 1482 ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr); 1483 ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr); 1484 } 1485 ierr = MatSetDM(*J, dm);CHKERRQ(ierr); 1486 PetscFunctionReturn(0); 1487 } 1488 1489 /*@ 1490 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 1491 1492 Not collective 1493 1494 Input Parameter: 1495 . mesh - The DMPlex 1496 1497 Output Parameters: 1498 . subsection - The subdomain section 1499 1500 Level: developer 1501 1502 .seealso: 1503 @*/ 1504 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 1505 { 1506 DM_Plex *mesh = (DM_Plex*) dm->data; 1507 PetscErrorCode ierr; 1508 1509 PetscFunctionBegin; 1510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1511 if (!mesh->subdomainSection) { 1512 PetscSection section; 1513 PetscSF sf; 1514 1515 ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr); 1516 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 1517 ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr); 1518 ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); 1519 } 1520 *subsection = mesh->subdomainSection; 1521 PetscFunctionReturn(0); 1522 } 1523 1524 /*@ 1525 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 1526 1527 Not collective 1528 1529 Input Parameter: 1530 . mesh - The DMPlex 1531 1532 Output Parameters: 1533 + pStart - The first mesh point 1534 - pEnd - The upper bound for mesh points 1535 1536 Level: beginner 1537 1538 .seealso: DMPlexCreate(), DMPlexSetChart() 1539 @*/ 1540 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 1541 { 1542 DM_Plex *mesh = (DM_Plex*) dm->data; 1543 PetscErrorCode ierr; 1544 1545 PetscFunctionBegin; 1546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1547 ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1548 PetscFunctionReturn(0); 1549 } 1550 1551 /*@ 1552 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 1553 1554 Not collective 1555 1556 Input Parameters: 1557 + mesh - The DMPlex 1558 . pStart - The first mesh point 1559 - pEnd - The upper bound for mesh points 1560 1561 Output Parameters: 1562 1563 Level: beginner 1564 1565 .seealso: DMPlexCreate(), DMPlexGetChart() 1566 @*/ 1567 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 1568 { 1569 DM_Plex *mesh = (DM_Plex*) dm->data; 1570 PetscErrorCode ierr; 1571 1572 PetscFunctionBegin; 1573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1574 ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1575 ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 1576 PetscFunctionReturn(0); 1577 } 1578 1579 /*@ 1580 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 1581 1582 Not collective 1583 1584 Input Parameters: 1585 + mesh - The DMPlex 1586 - p - The point, which must lie in the chart set with DMPlexSetChart() 1587 1588 Output Parameter: 1589 . size - The cone size for point p 1590 1591 Level: beginner 1592 1593 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 1594 @*/ 1595 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 1596 { 1597 DM_Plex *mesh = (DM_Plex*) dm->data; 1598 PetscErrorCode ierr; 1599 1600 PetscFunctionBegin; 1601 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1602 PetscValidPointer(size, 3); 1603 ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1604 PetscFunctionReturn(0); 1605 } 1606 1607 /*@ 1608 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 1609 1610 Not collective 1611 1612 Input Parameters: 1613 + mesh - The DMPlex 1614 . p - The point, which must lie in the chart set with DMPlexSetChart() 1615 - size - The cone size for point p 1616 1617 Output Parameter: 1618 1619 Note: 1620 This should be called after DMPlexSetChart(). 1621 1622 Level: beginner 1623 1624 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 1625 @*/ 1626 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 1627 { 1628 DM_Plex *mesh = (DM_Plex*) dm->data; 1629 PetscErrorCode ierr; 1630 1631 PetscFunctionBegin; 1632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1633 ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1634 1635 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 1636 PetscFunctionReturn(0); 1637 } 1638 1639 /*@ 1640 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 1641 1642 Not collective 1643 1644 Input Parameters: 1645 + mesh - The DMPlex 1646 . p - The point, which must lie in the chart set with DMPlexSetChart() 1647 - size - The additional cone size for point p 1648 1649 Output Parameter: 1650 1651 Note: 1652 This should be called after DMPlexSetChart(). 1653 1654 Level: beginner 1655 1656 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 1657 @*/ 1658 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 1659 { 1660 DM_Plex *mesh = (DM_Plex*) dm->data; 1661 PetscInt csize; 1662 PetscErrorCode ierr; 1663 1664 PetscFunctionBegin; 1665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1666 ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1667 ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr); 1668 1669 mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize); 1670 PetscFunctionReturn(0); 1671 } 1672 1673 /*@C 1674 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 1675 1676 Not collective 1677 1678 Input Parameters: 1679 + dm - The DMPlex 1680 - p - The point, which must lie in the chart set with DMPlexSetChart() 1681 1682 Output Parameter: 1683 . cone - An array of points which are on the in-edges for point p 1684 1685 Level: beginner 1686 1687 Fortran Notes: 1688 Since it returns an array, this routine is only available in Fortran 90, and you must 1689 include petsc.h90 in your code. 1690 You must also call DMPlexRestoreCone() after you finish using the returned array. 1691 DMPlexRestoreCone() is not needed/available in C. 1692 1693 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart() 1694 @*/ 1695 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 1696 { 1697 DM_Plex *mesh = (DM_Plex*) dm->data; 1698 PetscInt off; 1699 PetscErrorCode ierr; 1700 1701 PetscFunctionBegin; 1702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1703 PetscValidPointer(cone, 3); 1704 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1705 *cone = &mesh->cones[off]; 1706 PetscFunctionReturn(0); 1707 } 1708 1709 /*@C 1710 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 1711 1712 Not collective 1713 1714 Input Parameters: 1715 + dm - The DMPlex 1716 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 1717 1718 Output Parameter: 1719 + pConesSection - PetscSection describing the layout of pCones 1720 - pCones - An array of points which are on the in-edges for the point set p 1721 1722 Level: intermediate 1723 1724 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart() 1725 @*/ 1726 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 1727 { 1728 PetscSection cs, newcs; 1729 PetscInt *cones; 1730 PetscInt *newarr=NULL; 1731 PetscInt n; 1732 PetscErrorCode ierr; 1733 1734 PetscFunctionBegin; 1735 ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); 1736 ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr); 1737 ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr); 1738 if (pConesSection) *pConesSection = newcs; 1739 if (pCones) { 1740 ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr); 1741 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr); 1742 } 1743 PetscFunctionReturn(0); 1744 } 1745 1746 /*@ 1747 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 1748 1749 Not collective 1750 1751 Input Parameters: 1752 + dm - The DMPlex 1753 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1754 1755 Output Parameter: 1756 . expandedPoints - An array of vertices recursively expanded from input points 1757 1758 Level: advanced 1759 1760 Notes: 1761 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 1762 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 1763 1764 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth() 1765 @*/ 1766 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 1767 { 1768 IS *expandedPointsAll; 1769 PetscInt depth; 1770 PetscErrorCode ierr; 1771 1772 PetscFunctionBegin; 1773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1774 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 1775 PetscValidPointer(expandedPoints, 3); 1776 ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 1777 *expandedPoints = expandedPointsAll[0]; 1778 ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]); 1779 ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 1780 PetscFunctionReturn(0); 1781 } 1782 1783 /*@ 1784 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). 1785 1786 Not collective 1787 1788 Input Parameters: 1789 + dm - The DMPlex 1790 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1791 1792 Output Parameter: 1793 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 1794 . expandedPoints - (optional) An array of index sets with recursively expanded cones 1795 - sections - (optional) An array of sections which describe mappings from points to their cone points 1796 1797 Level: advanced 1798 1799 Notes: 1800 Like DMPlexGetConeTuple() but recursive. 1801 1802 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. 1803 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 1804 1805 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: 1806 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 1807 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 1808 1809 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 1810 @*/ 1811 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 1812 { 1813 const PetscInt *arr0=NULL, *cone=NULL; 1814 PetscInt *arr=NULL, *newarr=NULL; 1815 PetscInt d, depth_, i, n, newn, cn, co, start, end; 1816 IS *expandedPoints_; 1817 PetscSection *sections_; 1818 PetscErrorCode ierr; 1819 1820 PetscFunctionBegin; 1821 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1822 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 1823 if (depth) PetscValidIntPointer(depth, 3); 1824 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 1825 if (sections) PetscValidPointer(sections, 5); 1826 ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr); 1827 ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr); 1828 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 1829 ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr); 1830 ierr = PetscCalloc1(depth_, §ions_);CHKERRQ(ierr); 1831 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 1832 for (d=depth_-1; d>=0; d--) { 1833 ierr = PetscSectionCreate(PETSC_COMM_SELF, §ions_[d]);CHKERRQ(ierr); 1834 ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr); 1835 for (i=0; i<n; i++) { 1836 ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr); 1837 if (arr[i] >= start && arr[i] < end) { 1838 ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr); 1839 ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr); 1840 } else { 1841 ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr); 1842 } 1843 } 1844 ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr); 1845 ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr); 1846 ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr); 1847 for (i=0; i<n; i++) { 1848 ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr); 1849 ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr); 1850 if (cn > 1) { 1851 ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr); 1852 ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr); 1853 } else { 1854 newarr[co] = arr[i]; 1855 } 1856 } 1857 ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr); 1858 arr = newarr; 1859 n = newn; 1860 } 1861 ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr); 1862 *depth = depth_; 1863 if (expandedPoints) *expandedPoints = expandedPoints_; 1864 else { 1865 for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);} 1866 ierr = PetscFree(expandedPoints_);CHKERRQ(ierr); 1867 } 1868 if (sections) *sections = sections_; 1869 else { 1870 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(§ions_[d]);CHKERRQ(ierr);} 1871 ierr = PetscFree(sections_);CHKERRQ(ierr); 1872 } 1873 PetscFunctionReturn(0); 1874 } 1875 1876 /*@ 1877 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 1878 1879 Not collective 1880 1881 Input Parameters: 1882 + dm - The DMPlex 1883 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 1884 1885 Output Parameter: 1886 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 1887 . expandedPoints - (optional) An array of recursively expanded cones 1888 - sections - (optional) An array of sections which describe mappings from points to their cone points 1889 1890 Level: advanced 1891 1892 Notes: 1893 See DMPlexGetConeRecursive() for details. 1894 1895 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 1896 @*/ 1897 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 1898 { 1899 PetscInt d, depth_; 1900 PetscErrorCode ierr; 1901 1902 PetscFunctionBegin; 1903 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 1904 if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 1905 if (depth) *depth = 0; 1906 if (expandedPoints) { 1907 for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);} 1908 ierr = PetscFree(*expandedPoints);CHKERRQ(ierr); 1909 } 1910 if (sections) { 1911 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);} 1912 ierr = PetscFree(*sections);CHKERRQ(ierr); 1913 } 1914 PetscFunctionReturn(0); 1915 } 1916 1917 /*@ 1918 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 1919 1920 Not collective 1921 1922 Input Parameters: 1923 + mesh - The DMPlex 1924 . p - The point, which must lie in the chart set with DMPlexSetChart() 1925 - cone - An array of points which are on the in-edges for point p 1926 1927 Output Parameter: 1928 1929 Note: 1930 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 1931 1932 Developer Note: Why not call this DMPlexSetCover() 1933 1934 Level: beginner 1935 1936 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize() 1937 @*/ 1938 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 1939 { 1940 DM_Plex *mesh = (DM_Plex*) dm->data; 1941 PetscInt pStart, pEnd; 1942 PetscInt dof, off, c; 1943 PetscErrorCode ierr; 1944 1945 PetscFunctionBegin; 1946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1947 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1948 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1949 if (dof) PetscValidPointer(cone, 3); 1950 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1951 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1952 for (c = 0; c < dof; ++c) { 1953 if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd); 1954 mesh->cones[off+c] = cone[c]; 1955 } 1956 PetscFunctionReturn(0); 1957 } 1958 1959 /*@C 1960 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 1961 1962 Not collective 1963 1964 Input Parameters: 1965 + mesh - The DMPlex 1966 - p - The point, which must lie in the chart set with DMPlexSetChart() 1967 1968 Output Parameter: 1969 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 1970 integer giving the prescription for cone traversal. If it is negative, the cone is 1971 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 1972 the index of the cone point on which to start. 1973 1974 Level: beginner 1975 1976 Fortran Notes: 1977 Since it returns an array, this routine is only available in Fortran 90, and you must 1978 include petsc.h90 in your code. 1979 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 1980 DMPlexRestoreConeOrientation() is not needed/available in C. 1981 1982 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 1983 @*/ 1984 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 1985 { 1986 DM_Plex *mesh = (DM_Plex*) dm->data; 1987 PetscInt off; 1988 PetscErrorCode ierr; 1989 1990 PetscFunctionBegin; 1991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1992 #if defined(PETSC_USE_DEBUG) 1993 { 1994 PetscInt dof; 1995 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1996 if (dof) PetscValidPointer(coneOrientation, 3); 1997 } 1998 #endif 1999 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2000 2001 *coneOrientation = &mesh->coneOrientations[off]; 2002 PetscFunctionReturn(0); 2003 } 2004 2005 /*@ 2006 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 2007 2008 Not collective 2009 2010 Input Parameters: 2011 + mesh - The DMPlex 2012 . p - The point, which must lie in the chart set with DMPlexSetChart() 2013 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 2014 integer giving the prescription for cone traversal. If it is negative, the cone is 2015 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 2016 the index of the cone point on which to start. 2017 2018 Output Parameter: 2019 2020 Note: 2021 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2022 2023 Level: beginner 2024 2025 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2026 @*/ 2027 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 2028 { 2029 DM_Plex *mesh = (DM_Plex*) dm->data; 2030 PetscInt pStart, pEnd; 2031 PetscInt dof, off, c; 2032 PetscErrorCode ierr; 2033 2034 PetscFunctionBegin; 2035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2036 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2037 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2038 if (dof) PetscValidPointer(coneOrientation, 3); 2039 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2040 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 2041 for (c = 0; c < dof; ++c) { 2042 PetscInt cdof, o = coneOrientation[c]; 2043 2044 ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr); 2045 if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof); 2046 mesh->coneOrientations[off+c] = o; 2047 } 2048 PetscFunctionReturn(0); 2049 } 2050 2051 /*@ 2052 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 2053 2054 Not collective 2055 2056 Input Parameters: 2057 + mesh - The DMPlex 2058 . p - The point, which must lie in the chart set with DMPlexSetChart() 2059 . conePos - The local index in the cone where the point should be put 2060 - conePoint - The mesh point to insert 2061 2062 Level: beginner 2063 2064 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2065 @*/ 2066 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 2067 { 2068 DM_Plex *mesh = (DM_Plex*) dm->data; 2069 PetscInt pStart, pEnd; 2070 PetscInt dof, off; 2071 PetscErrorCode ierr; 2072 2073 PetscFunctionBegin; 2074 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2075 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2076 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 2077 if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd); 2078 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2079 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2080 if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 2081 mesh->cones[off+conePos] = conePoint; 2082 PetscFunctionReturn(0); 2083 } 2084 2085 /*@ 2086 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 2087 2088 Not collective 2089 2090 Input Parameters: 2091 + mesh - The DMPlex 2092 . p - The point, which must lie in the chart set with DMPlexSetChart() 2093 . conePos - The local index in the cone where the point should be put 2094 - coneOrientation - The point orientation to insert 2095 2096 Level: beginner 2097 2098 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2099 @*/ 2100 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 2101 { 2102 DM_Plex *mesh = (DM_Plex*) dm->data; 2103 PetscInt pStart, pEnd; 2104 PetscInt dof, off; 2105 PetscErrorCode ierr; 2106 2107 PetscFunctionBegin; 2108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2109 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2110 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 2111 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2112 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2113 if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 2114 mesh->coneOrientations[off+conePos] = coneOrientation; 2115 PetscFunctionReturn(0); 2116 } 2117 2118 /*@ 2119 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 2120 2121 Not collective 2122 2123 Input Parameters: 2124 + mesh - The DMPlex 2125 - p - The point, which must lie in the chart set with DMPlexSetChart() 2126 2127 Output Parameter: 2128 . size - The support size for point p 2129 2130 Level: beginner 2131 2132 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 2133 @*/ 2134 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 2135 { 2136 DM_Plex *mesh = (DM_Plex*) dm->data; 2137 PetscErrorCode ierr; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 PetscValidPointer(size, 3); 2142 ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2143 PetscFunctionReturn(0); 2144 } 2145 2146 /*@ 2147 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 2148 2149 Not collective 2150 2151 Input Parameters: 2152 + mesh - The DMPlex 2153 . p - The point, which must lie in the chart set with DMPlexSetChart() 2154 - size - The support size for point p 2155 2156 Output Parameter: 2157 2158 Note: 2159 This should be called after DMPlexSetChart(). 2160 2161 Level: beginner 2162 2163 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 2164 @*/ 2165 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 2166 { 2167 DM_Plex *mesh = (DM_Plex*) dm->data; 2168 PetscErrorCode ierr; 2169 2170 PetscFunctionBegin; 2171 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2172 ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2173 2174 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 2175 PetscFunctionReturn(0); 2176 } 2177 2178 /*@C 2179 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 2180 2181 Not collective 2182 2183 Input Parameters: 2184 + mesh - The DMPlex 2185 - p - The point, which must lie in the chart set with DMPlexSetChart() 2186 2187 Output Parameter: 2188 . support - An array of points which are on the out-edges for point p 2189 2190 Level: beginner 2191 2192 Fortran Notes: 2193 Since it returns an array, this routine is only available in Fortran 90, and you must 2194 include petsc.h90 in your code. 2195 You must also call DMPlexRestoreSupport() after you finish using the returned array. 2196 DMPlexRestoreSupport() is not needed/available in C. 2197 2198 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2199 @*/ 2200 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 2201 { 2202 DM_Plex *mesh = (DM_Plex*) dm->data; 2203 PetscInt off; 2204 PetscErrorCode ierr; 2205 2206 PetscFunctionBegin; 2207 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2208 PetscValidPointer(support, 3); 2209 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2210 *support = &mesh->supports[off]; 2211 PetscFunctionReturn(0); 2212 } 2213 2214 /*@ 2215 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 2216 2217 Not collective 2218 2219 Input Parameters: 2220 + mesh - The DMPlex 2221 . p - The point, which must lie in the chart set with DMPlexSetChart() 2222 - support - An array of points which are on the out-edges for point p 2223 2224 Output Parameter: 2225 2226 Note: 2227 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 2228 2229 Level: beginner 2230 2231 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 2232 @*/ 2233 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 2234 { 2235 DM_Plex *mesh = (DM_Plex*) dm->data; 2236 PetscInt pStart, pEnd; 2237 PetscInt dof, off, c; 2238 PetscErrorCode ierr; 2239 2240 PetscFunctionBegin; 2241 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2242 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2243 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2244 if (dof) PetscValidPointer(support, 3); 2245 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2246 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 2247 for (c = 0; c < dof; ++c) { 2248 if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd); 2249 mesh->supports[off+c] = support[c]; 2250 } 2251 PetscFunctionReturn(0); 2252 } 2253 2254 /*@ 2255 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 2256 2257 Not collective 2258 2259 Input Parameters: 2260 + mesh - The DMPlex 2261 . p - The point, which must lie in the chart set with DMPlexSetChart() 2262 . supportPos - The local index in the cone where the point should be put 2263 - supportPoint - The mesh point to insert 2264 2265 Level: beginner 2266 2267 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2268 @*/ 2269 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 2270 { 2271 DM_Plex *mesh = (DM_Plex*) dm->data; 2272 PetscInt pStart, pEnd; 2273 PetscInt dof, off; 2274 PetscErrorCode ierr; 2275 2276 PetscFunctionBegin; 2277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2278 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2279 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2280 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2281 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 2282 if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd); 2283 if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof); 2284 mesh->supports[off+supportPos] = supportPoint; 2285 PetscFunctionReturn(0); 2286 } 2287 2288 /*@C 2289 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 2290 2291 Not collective 2292 2293 Input Parameters: 2294 + mesh - The DMPlex 2295 . p - The point, which must lie in the chart set with DMPlexSetChart() 2296 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2297 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 2298 2299 Output Parameters: 2300 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 2301 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 2302 2303 Note: 2304 If using internal storage (points is NULL on input), each call overwrites the last output. 2305 2306 Fortran Notes: 2307 Since it returns an array, this routine is only available in Fortran 90, and you must 2308 include petsc.h90 in your code. 2309 2310 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2311 2312 Level: beginner 2313 2314 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2315 @*/ 2316 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2317 { 2318 DM_Plex *mesh = (DM_Plex*) dm->data; 2319 PetscInt *closure, *fifo; 2320 const PetscInt *tmp = NULL, *tmpO = NULL; 2321 PetscInt tmpSize, t; 2322 PetscInt depth = 0, maxSize; 2323 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 2324 PetscErrorCode ierr; 2325 2326 PetscFunctionBegin; 2327 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2328 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2329 /* This is only 1-level */ 2330 if (useCone) { 2331 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 2332 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 2333 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 2334 } else { 2335 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 2336 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 2337 } 2338 if (depth == 1) { 2339 if (*points) { 2340 closure = *points; 2341 } else { 2342 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 2343 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2344 } 2345 closure[0] = p; closure[1] = 0; 2346 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 2347 closure[closureSize] = tmp[t]; 2348 closure[closureSize+1] = tmpO ? tmpO[t] : 0; 2349 } 2350 if (numPoints) *numPoints = closureSize/2; 2351 if (points) *points = closure; 2352 PetscFunctionReturn(0); 2353 } 2354 { 2355 PetscInt c, coneSeries, s,supportSeries; 2356 2357 c = mesh->maxConeSize; 2358 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 2359 s = mesh->maxSupportSize; 2360 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 2361 maxSize = 2*PetscMax(coneSeries,supportSeries); 2362 } 2363 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2364 if (*points) { 2365 closure = *points; 2366 } else { 2367 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2368 } 2369 closure[0] = p; closure[1] = 0; 2370 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 2371 const PetscInt cp = tmp[t]; 2372 const PetscInt co = tmpO ? tmpO[t] : 0; 2373 2374 closure[closureSize] = cp; 2375 closure[closureSize+1] = co; 2376 fifo[fifoSize] = cp; 2377 fifo[fifoSize+1] = co; 2378 } 2379 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 2380 while (fifoSize - fifoStart) { 2381 const PetscInt q = fifo[fifoStart]; 2382 const PetscInt o = fifo[fifoStart+1]; 2383 const PetscInt rev = o >= 0 ? 0 : 1; 2384 const PetscInt off = rev ? -(o+1) : o; 2385 2386 if (useCone) { 2387 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 2388 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 2389 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 2390 } else { 2391 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 2392 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 2393 tmpO = NULL; 2394 } 2395 for (t = 0; t < tmpSize; ++t) { 2396 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 2397 const PetscInt cp = tmp[i]; 2398 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 2399 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 2400 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 2401 PetscInt co = tmpO ? tmpO[i] : 0; 2402 PetscInt c; 2403 2404 if (rev) { 2405 PetscInt childSize, coff; 2406 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2407 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 2408 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2409 } 2410 /* Check for duplicate */ 2411 for (c = 0; c < closureSize; c += 2) { 2412 if (closure[c] == cp) break; 2413 } 2414 if (c == closureSize) { 2415 closure[closureSize] = cp; 2416 closure[closureSize+1] = co; 2417 fifo[fifoSize] = cp; 2418 fifo[fifoSize+1] = co; 2419 closureSize += 2; 2420 fifoSize += 2; 2421 } 2422 } 2423 fifoStart += 2; 2424 } 2425 if (numPoints) *numPoints = closureSize/2; 2426 if (points) *points = closure; 2427 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2428 PetscFunctionReturn(0); 2429 } 2430 2431 /*@C 2432 DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG with a specified initial orientation 2433 2434 Not collective 2435 2436 Input Parameters: 2437 + mesh - The DMPlex 2438 . p - The point, which must lie in the chart set with DMPlexSetChart() 2439 . orientation - The orientation of the point 2440 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2441 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 2442 2443 Output Parameters: 2444 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 2445 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 2446 2447 Note: 2448 If using internal storage (points is NULL on input), each call overwrites the last output. 2449 2450 Fortran Notes: 2451 Since it returns an array, this routine is only available in Fortran 90, and you must 2452 include petsc.h90 in your code. 2453 2454 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2455 2456 Level: beginner 2457 2458 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2459 @*/ 2460 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2461 { 2462 DM_Plex *mesh = (DM_Plex*) dm->data; 2463 PetscInt *closure, *fifo; 2464 const PetscInt *tmp = NULL, *tmpO = NULL; 2465 PetscInt tmpSize, t; 2466 PetscInt depth = 0, maxSize; 2467 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 2468 PetscErrorCode ierr; 2469 2470 PetscFunctionBegin; 2471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2472 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2473 /* This is only 1-level */ 2474 if (useCone) { 2475 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 2476 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 2477 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 2478 } else { 2479 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 2480 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 2481 } 2482 if (depth == 1) { 2483 if (*points) { 2484 closure = *points; 2485 } else { 2486 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 2487 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2488 } 2489 closure[0] = p; closure[1] = ornt; 2490 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 2491 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 2492 closure[closureSize] = tmp[i]; 2493 closure[closureSize+1] = tmpO ? tmpO[i] : 0; 2494 } 2495 if (numPoints) *numPoints = closureSize/2; 2496 if (points) *points = closure; 2497 PetscFunctionReturn(0); 2498 } 2499 { 2500 PetscInt c, coneSeries, s,supportSeries; 2501 2502 c = mesh->maxConeSize; 2503 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 2504 s = mesh->maxSupportSize; 2505 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 2506 maxSize = 2*PetscMax(coneSeries,supportSeries); 2507 } 2508 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2509 if (*points) { 2510 closure = *points; 2511 } else { 2512 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2513 } 2514 closure[0] = p; closure[1] = ornt; 2515 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 2516 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 2517 const PetscInt cp = tmp[i]; 2518 PetscInt co = tmpO ? tmpO[i] : 0; 2519 2520 if (ornt < 0) { 2521 PetscInt childSize, coff; 2522 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2523 coff = co < 0 ? -(tmpO[i]+1) : tmpO[i]; 2524 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2525 } 2526 closure[closureSize] = cp; 2527 closure[closureSize+1] = co; 2528 fifo[fifoSize] = cp; 2529 fifo[fifoSize+1] = co; 2530 } 2531 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 2532 while (fifoSize - fifoStart) { 2533 const PetscInt q = fifo[fifoStart]; 2534 const PetscInt o = fifo[fifoStart+1]; 2535 const PetscInt rev = o >= 0 ? 0 : 1; 2536 const PetscInt off = rev ? -(o+1) : o; 2537 2538 if (useCone) { 2539 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 2540 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 2541 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 2542 } else { 2543 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 2544 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 2545 tmpO = NULL; 2546 } 2547 for (t = 0; t < tmpSize; ++t) { 2548 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 2549 const PetscInt cp = tmp[i]; 2550 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 2551 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 2552 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 2553 PetscInt co = tmpO ? tmpO[i] : 0; 2554 PetscInt c; 2555 2556 if (rev) { 2557 PetscInt childSize, coff; 2558 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2559 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 2560 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2561 } 2562 /* Check for duplicate */ 2563 for (c = 0; c < closureSize; c += 2) { 2564 if (closure[c] == cp) break; 2565 } 2566 if (c == closureSize) { 2567 closure[closureSize] = cp; 2568 closure[closureSize+1] = co; 2569 fifo[fifoSize] = cp; 2570 fifo[fifoSize+1] = co; 2571 closureSize += 2; 2572 fifoSize += 2; 2573 } 2574 } 2575 fifoStart += 2; 2576 } 2577 if (numPoints) *numPoints = closureSize/2; 2578 if (points) *points = closure; 2579 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2580 PetscFunctionReturn(0); 2581 } 2582 2583 /*@C 2584 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 2585 2586 Not collective 2587 2588 Input Parameters: 2589 + mesh - The DMPlex 2590 . p - The point, which must lie in the chart set with DMPlexSetChart() 2591 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2592 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit 2593 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit 2594 2595 Note: 2596 If not using internal storage (points is not NULL on input), this call is unnecessary 2597 2598 Fortran Notes: 2599 Since it returns an array, this routine is only available in Fortran 90, and you must 2600 include petsc.h90 in your code. 2601 2602 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2603 2604 Level: beginner 2605 2606 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2607 @*/ 2608 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2609 { 2610 PetscErrorCode ierr; 2611 2612 PetscFunctionBegin; 2613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2614 if (numPoints) PetscValidIntPointer(numPoints,4); 2615 if (points) PetscValidPointer(points,5); 2616 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr); 2617 if (numPoints) *numPoints = 0; 2618 PetscFunctionReturn(0); 2619 } 2620 2621 /*@ 2622 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 2623 2624 Not collective 2625 2626 Input Parameter: 2627 . mesh - The DMPlex 2628 2629 Output Parameters: 2630 + maxConeSize - The maximum number of in-edges 2631 - maxSupportSize - The maximum number of out-edges 2632 2633 Level: beginner 2634 2635 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 2636 @*/ 2637 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 2638 { 2639 DM_Plex *mesh = (DM_Plex*) dm->data; 2640 2641 PetscFunctionBegin; 2642 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2643 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 2644 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 2645 PetscFunctionReturn(0); 2646 } 2647 2648 PetscErrorCode DMSetUp_Plex(DM dm) 2649 { 2650 DM_Plex *mesh = (DM_Plex*) dm->data; 2651 PetscInt size; 2652 PetscErrorCode ierr; 2653 2654 PetscFunctionBegin; 2655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2656 ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr); 2657 ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr); 2658 ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr); 2659 ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr); 2660 if (mesh->maxSupportSize) { 2661 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 2662 ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr); 2663 ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr); 2664 } 2665 PetscFunctionReturn(0); 2666 } 2667 2668 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 2669 { 2670 PetscErrorCode ierr; 2671 2672 PetscFunctionBegin; 2673 if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);} 2674 ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr); 2675 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 2676 if (dm->useNatural && dm->sfMigration) { 2677 PetscSF sfMigrationInv,sfNatural; 2678 PetscSection section, sectionSeq; 2679 2680 (*subdm)->sfMigration = dm->sfMigration; 2681 ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr); 2682 ierr = DMGetLocalSection((*subdm), §ion);CHKERRQ(ierr); 2683 ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 2684 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);CHKERRQ(ierr); 2685 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 2686 2687 ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 2688 (*subdm)->sfNatural = sfNatural; 2689 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 2690 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 2691 } 2692 PetscFunctionReturn(0); 2693 } 2694 2695 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 2696 { 2697 PetscErrorCode ierr; 2698 PetscInt i = 0; 2699 2700 PetscFunctionBegin; 2701 ierr = DMClone(dms[0], superdm);CHKERRQ(ierr); 2702 ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr); 2703 (*superdm)->useNatural = PETSC_FALSE; 2704 for (i = 0; i < len; i++){ 2705 if (dms[i]->useNatural && dms[i]->sfMigration) { 2706 PetscSF sfMigrationInv,sfNatural; 2707 PetscSection section, sectionSeq; 2708 2709 (*superdm)->sfMigration = dms[i]->sfMigration; 2710 ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr); 2711 (*superdm)->useNatural = PETSC_TRUE; 2712 ierr = DMGetLocalSection((*superdm), §ion);CHKERRQ(ierr); 2713 ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 2714 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);CHKERRQ(ierr); 2715 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 2716 2717 ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 2718 (*superdm)->sfNatural = sfNatural; 2719 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 2720 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 2721 break; 2722 } 2723 } 2724 PetscFunctionReturn(0); 2725 } 2726 2727 /*@ 2728 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 2729 2730 Not collective 2731 2732 Input Parameter: 2733 . mesh - The DMPlex 2734 2735 Output Parameter: 2736 2737 Note: 2738 This should be called after all calls to DMPlexSetCone() 2739 2740 Level: beginner 2741 2742 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 2743 @*/ 2744 PetscErrorCode DMPlexSymmetrize(DM dm) 2745 { 2746 DM_Plex *mesh = (DM_Plex*) dm->data; 2747 PetscInt *offsets; 2748 PetscInt supportSize; 2749 PetscInt pStart, pEnd, p; 2750 PetscErrorCode ierr; 2751 2752 PetscFunctionBegin; 2753 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2754 if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 2755 ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 2756 /* Calculate support sizes */ 2757 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2758 for (p = pStart; p < pEnd; ++p) { 2759 PetscInt dof, off, c; 2760 2761 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2762 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2763 for (c = off; c < off+dof; ++c) { 2764 ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr); 2765 } 2766 } 2767 for (p = pStart; p < pEnd; ++p) { 2768 PetscInt dof; 2769 2770 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2771 2772 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 2773 } 2774 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 2775 /* Calculate supports */ 2776 ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr); 2777 ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr); 2778 ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr); 2779 for (p = pStart; p < pEnd; ++p) { 2780 PetscInt dof, off, c; 2781 2782 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2783 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2784 for (c = off; c < off+dof; ++c) { 2785 const PetscInt q = mesh->cones[c]; 2786 PetscInt offS; 2787 2788 ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr); 2789 2790 mesh->supports[offS+offsets[q]] = p; 2791 ++offsets[q]; 2792 } 2793 } 2794 ierr = PetscFree(offsets);CHKERRQ(ierr); 2795 ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 2796 PetscFunctionReturn(0); 2797 } 2798 2799 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 2800 { 2801 IS stratumIS; 2802 PetscErrorCode ierr; 2803 2804 PetscFunctionBegin; 2805 if (pStart >= pEnd) PetscFunctionReturn(0); 2806 #if defined(PETSC_USE_DEBUG) 2807 { 2808 PetscInt qStart, qEnd, numLevels, level; 2809 PetscBool overlap = PETSC_FALSE; 2810 ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr); 2811 for (level = 0; level < numLevels; level++) { 2812 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2813 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 2814 } 2815 if (overlap) SETERRQ6(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); 2816 } 2817 #endif 2818 ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr); 2819 ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr); 2820 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 2821 PetscFunctionReturn(0); 2822 } 2823 2824 static PetscErrorCode DMPlexCreateDimStratum(DM,DMLabel,DMLabel,PetscInt,PetscInt); 2825 2826 /*@ 2827 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 2828 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 2829 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 2830 the DAG. 2831 2832 Collective on dm 2833 2834 Input Parameter: 2835 . mesh - The DMPlex 2836 2837 Output Parameter: 2838 2839 Notes: 2840 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 2841 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 2842 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 2843 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 2844 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 2845 2846 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 2847 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 2848 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 2849 to interpolate only that one (e0), so that 2850 $ cone(c0) = {e0, v2} 2851 $ cone(e0) = {v0, v1} 2852 If DMPlexStratify() is run on this mesh, it will give depths 2853 $ depth 0 = {v0, v1, v2} 2854 $ depth 1 = {e0, c0} 2855 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 2856 2857 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 2858 2859 Level: beginner 2860 2861 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes() 2862 @*/ 2863 PetscErrorCode DMPlexStratify(DM dm) 2864 { 2865 DM_Plex *mesh = (DM_Plex*) dm->data; 2866 DMLabel label; 2867 PetscInt pStart, pEnd, p; 2868 PetscInt numRoots = 0, numLeaves = 0; 2869 PetscInt cMax, fMax, eMax, vMax; 2870 PetscErrorCode ierr; 2871 2872 PetscFunctionBegin; 2873 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2874 ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2875 2876 /* Create depth label */ 2877 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2878 ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr); 2879 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2880 2881 { 2882 /* Initialize roots and count leaves */ 2883 PetscInt sMin = PETSC_MAX_INT; 2884 PetscInt sMax = PETSC_MIN_INT; 2885 PetscInt coneSize, supportSize; 2886 2887 for (p = pStart; p < pEnd; ++p) { 2888 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2889 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2890 if (!coneSize && supportSize) { 2891 sMin = PetscMin(p, sMin); 2892 sMax = PetscMax(p, sMax); 2893 ++numRoots; 2894 } else if (!supportSize && coneSize) { 2895 ++numLeaves; 2896 } else if (!supportSize && !coneSize) { 2897 /* Isolated points */ 2898 sMin = PetscMin(p, sMin); 2899 sMax = PetscMax(p, sMax); 2900 } 2901 } 2902 ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr); 2903 } 2904 2905 if (numRoots + numLeaves == (pEnd - pStart)) { 2906 PetscInt sMin = PETSC_MAX_INT; 2907 PetscInt sMax = PETSC_MIN_INT; 2908 PetscInt coneSize, supportSize; 2909 2910 for (p = pStart; p < pEnd; ++p) { 2911 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2912 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2913 if (!supportSize && coneSize) { 2914 sMin = PetscMin(p, sMin); 2915 sMax = PetscMax(p, sMax); 2916 } 2917 } 2918 ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr); 2919 } else { 2920 PetscInt level = 0; 2921 PetscInt qStart, qEnd, q; 2922 2923 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2924 while (qEnd > qStart) { 2925 PetscInt sMin = PETSC_MAX_INT; 2926 PetscInt sMax = PETSC_MIN_INT; 2927 2928 for (q = qStart; q < qEnd; ++q) { 2929 const PetscInt *support; 2930 PetscInt supportSize, s; 2931 2932 ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr); 2933 ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr); 2934 for (s = 0; s < supportSize; ++s) { 2935 sMin = PetscMin(support[s], sMin); 2936 sMax = PetscMax(support[s], sMax); 2937 } 2938 } 2939 ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr); 2940 ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr); 2941 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 2942 } 2943 } 2944 { /* just in case there is an empty process */ 2945 PetscInt numValues, maxValues = 0, v; 2946 2947 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 2948 ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 2949 for (v = numValues; v < maxValues; v++) { 2950 ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr); 2951 } 2952 } 2953 ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr); 2954 2955 ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr); 2956 if (cMax >= 0 || fMax >= 0 || eMax >= 0 || vMax >= 0) { 2957 PetscInt dim; 2958 DMLabel dimLabel; 2959 2960 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2961 ierr = DMCreateLabel(dm, "dim");CHKERRQ(ierr); 2962 ierr = DMGetLabel(dm, "dim", &dimLabel);CHKERRQ(ierr); 2963 if (cMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim, cMax);CHKERRQ(ierr);} 2964 if (fMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, dim - 1, fMax);CHKERRQ(ierr);} 2965 if (eMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 1, eMax);CHKERRQ(ierr);} 2966 if (vMax >= 0) {ierr = DMPlexCreateDimStratum(dm, label, dimLabel, 0, vMax);CHKERRQ(ierr);} 2967 } 2968 ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2969 PetscFunctionReturn(0); 2970 } 2971 2972 /*@ 2973 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 2974 2975 Collective on dm 2976 2977 Input Parameter: 2978 . mesh - The DMPlex 2979 2980 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 2981 2982 Level: beginner 2983 2984 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify() 2985 @*/ 2986 PetscErrorCode DMPlexComputeCellTypes(DM dm) 2987 { 2988 DM_Plex *mesh; 2989 DMLabel label; 2990 PetscInt dim, depth, gcStart, gcEnd, pStart, pEnd, p; 2991 PetscErrorCode ierr; 2992 2993 PetscFunctionBegin; 2994 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2995 mesh = (DM_Plex *) dm->data; 2996 ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr); 2997 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 2998 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2999 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3000 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3001 ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr); 3002 for (p = pStart; p < pEnd; ++p) { 3003 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3004 PetscInt pdepth, pheight, coneSize; 3005 3006 ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr); 3007 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 3008 pheight = depth - pdepth; 3009 if (depth <= 1) { 3010 switch (pdepth) { 3011 case 0: ct = DM_POLYTOPE_POINT;break; 3012 case 1: 3013 switch (coneSize) { 3014 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3015 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3016 case 4: 3017 switch (dim) { 3018 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 3019 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 3020 default: break; 3021 } 3022 break; 3023 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3024 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 3025 default: break; 3026 } 3027 } 3028 } else { 3029 if (pdepth == 0) { 3030 ct = DM_POLYTOPE_POINT; 3031 } else if (pheight == 0) { 3032 if ((p >= gcStart) && (p < gcEnd)) { 3033 if (coneSize == 1) ct = DM_POLYTOPE_FV_GHOST; 3034 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ghost cell %D should have a cone size of 1, not %D", p, coneSize); 3035 } else { 3036 switch (dim) { 3037 case 1: 3038 switch (coneSize) { 3039 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3040 default: break; 3041 } 3042 break; 3043 case 2: 3044 switch (coneSize) { 3045 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3046 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3047 default: break; 3048 } 3049 break; 3050 case 3: 3051 switch (coneSize) { 3052 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 3053 case 5: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3054 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 3055 default: break; 3056 } 3057 break; 3058 default: break; 3059 } 3060 } 3061 } else if (pheight > 0) { 3062 switch (coneSize) { 3063 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3064 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3065 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3066 default: break; 3067 } 3068 } 3069 } 3070 if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p); 3071 ierr = DMLabelSetValue(label, p, ct);CHKERRQ(ierr); 3072 } 3073 ierr = PetscObjectStateGet((PetscObject) label, &mesh->celltypeState);CHKERRQ(ierr); 3074 ierr = PetscObjectViewFromOptions((PetscObject) label, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr); 3075 PetscFunctionReturn(0); 3076 } 3077 3078 /*@C 3079 DMPlexGetJoin - Get an array for the join of the set of points 3080 3081 Not Collective 3082 3083 Input Parameters: 3084 + dm - The DMPlex object 3085 . numPoints - The number of input points for the join 3086 - points - The input points 3087 3088 Output Parameters: 3089 + numCoveredPoints - The number of points in the join 3090 - coveredPoints - The points in the join 3091 3092 Level: intermediate 3093 3094 Note: Currently, this is restricted to a single level join 3095 3096 Fortran Notes: 3097 Since it returns an array, this routine is only available in Fortran 90, and you must 3098 include petsc.h90 in your code. 3099 3100 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3101 3102 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 3103 @*/ 3104 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3105 { 3106 DM_Plex *mesh = (DM_Plex*) dm->data; 3107 PetscInt *join[2]; 3108 PetscInt joinSize, i = 0; 3109 PetscInt dof, off, p, c, m; 3110 PetscErrorCode ierr; 3111 3112 PetscFunctionBegin; 3113 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3114 PetscValidIntPointer(points, 3); 3115 PetscValidIntPointer(numCoveredPoints, 4); 3116 PetscValidPointer(coveredPoints, 5); 3117 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3118 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3119 /* Copy in support of first point */ 3120 ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr); 3121 ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr); 3122 for (joinSize = 0; joinSize < dof; ++joinSize) { 3123 join[i][joinSize] = mesh->supports[off+joinSize]; 3124 } 3125 /* Check each successive support */ 3126 for (p = 1; p < numPoints; ++p) { 3127 PetscInt newJoinSize = 0; 3128 3129 ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr); 3130 ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr); 3131 for (c = 0; c < dof; ++c) { 3132 const PetscInt point = mesh->supports[off+c]; 3133 3134 for (m = 0; m < joinSize; ++m) { 3135 if (point == join[i][m]) { 3136 join[1-i][newJoinSize++] = point; 3137 break; 3138 } 3139 } 3140 } 3141 joinSize = newJoinSize; 3142 i = 1-i; 3143 } 3144 *numCoveredPoints = joinSize; 3145 *coveredPoints = join[i]; 3146 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3147 PetscFunctionReturn(0); 3148 } 3149 3150 /*@C 3151 DMPlexRestoreJoin - Restore an array for the join of the set of points 3152 3153 Not Collective 3154 3155 Input Parameters: 3156 + dm - The DMPlex object 3157 . numPoints - The number of input points for the join 3158 - points - The input points 3159 3160 Output Parameters: 3161 + numCoveredPoints - The number of points in the join 3162 - coveredPoints - The points in the join 3163 3164 Fortran Notes: 3165 Since it returns an array, this routine is only available in Fortran 90, and you must 3166 include petsc.h90 in your code. 3167 3168 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3169 3170 Level: intermediate 3171 3172 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 3173 @*/ 3174 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3175 { 3176 PetscErrorCode ierr; 3177 3178 PetscFunctionBegin; 3179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3180 if (points) PetscValidIntPointer(points,3); 3181 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3182 PetscValidPointer(coveredPoints, 5); 3183 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3184 if (numCoveredPoints) *numCoveredPoints = 0; 3185 PetscFunctionReturn(0); 3186 } 3187 3188 /*@C 3189 DMPlexGetFullJoin - Get an array for the join of the set of points 3190 3191 Not Collective 3192 3193 Input Parameters: 3194 + dm - The DMPlex object 3195 . numPoints - The number of input points for the join 3196 - points - The input points 3197 3198 Output Parameters: 3199 + numCoveredPoints - The number of points in the join 3200 - coveredPoints - The points in the join 3201 3202 Fortran Notes: 3203 Since it returns an array, this routine is only available in Fortran 90, and you must 3204 include petsc.h90 in your code. 3205 3206 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3207 3208 Level: intermediate 3209 3210 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 3211 @*/ 3212 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3213 { 3214 DM_Plex *mesh = (DM_Plex*) dm->data; 3215 PetscInt *offsets, **closures; 3216 PetscInt *join[2]; 3217 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 3218 PetscInt p, d, c, m, ms; 3219 PetscErrorCode ierr; 3220 3221 PetscFunctionBegin; 3222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3223 PetscValidIntPointer(points, 3); 3224 PetscValidIntPointer(numCoveredPoints, 4); 3225 PetscValidPointer(coveredPoints, 5); 3226 3227 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3228 ierr = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr); 3229 ierr = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3230 ms = mesh->maxSupportSize; 3231 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 3232 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3233 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3234 3235 for (p = 0; p < numPoints; ++p) { 3236 PetscInt closureSize; 3237 3238 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr); 3239 3240 offsets[p*(depth+2)+0] = 0; 3241 for (d = 0; d < depth+1; ++d) { 3242 PetscInt pStart, pEnd, i; 3243 3244 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 3245 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 3246 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 3247 offsets[p*(depth+2)+d+1] = i; 3248 break; 3249 } 3250 } 3251 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 3252 } 3253 if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize); 3254 } 3255 for (d = 0; d < depth+1; ++d) { 3256 PetscInt dof; 3257 3258 /* Copy in support of first point */ 3259 dof = offsets[d+1] - offsets[d]; 3260 for (joinSize = 0; joinSize < dof; ++joinSize) { 3261 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 3262 } 3263 /* Check each successive cone */ 3264 for (p = 1; p < numPoints && joinSize; ++p) { 3265 PetscInt newJoinSize = 0; 3266 3267 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 3268 for (c = 0; c < dof; ++c) { 3269 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 3270 3271 for (m = 0; m < joinSize; ++m) { 3272 if (point == join[i][m]) { 3273 join[1-i][newJoinSize++] = point; 3274 break; 3275 } 3276 } 3277 } 3278 joinSize = newJoinSize; 3279 i = 1-i; 3280 } 3281 if (joinSize) break; 3282 } 3283 *numCoveredPoints = joinSize; 3284 *coveredPoints = join[i]; 3285 for (p = 0; p < numPoints; ++p) { 3286 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr); 3287 } 3288 ierr = PetscFree(closures);CHKERRQ(ierr); 3289 ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3290 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3291 PetscFunctionReturn(0); 3292 } 3293 3294 /*@C 3295 DMPlexGetMeet - Get an array for the meet of the set of points 3296 3297 Not Collective 3298 3299 Input Parameters: 3300 + dm - The DMPlex object 3301 . numPoints - The number of input points for the meet 3302 - points - The input points 3303 3304 Output Parameters: 3305 + numCoveredPoints - The number of points in the meet 3306 - coveredPoints - The points in the meet 3307 3308 Level: intermediate 3309 3310 Note: Currently, this is restricted to a single level meet 3311 3312 Fortran Notes: 3313 Since it returns an array, this routine is only available in Fortran 90, and you must 3314 include petsc.h90 in your code. 3315 3316 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3317 3318 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 3319 @*/ 3320 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 3321 { 3322 DM_Plex *mesh = (DM_Plex*) dm->data; 3323 PetscInt *meet[2]; 3324 PetscInt meetSize, i = 0; 3325 PetscInt dof, off, p, c, m; 3326 PetscErrorCode ierr; 3327 3328 PetscFunctionBegin; 3329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3330 PetscValidPointer(points, 2); 3331 PetscValidPointer(numCoveringPoints, 3); 3332 PetscValidPointer(coveringPoints, 4); 3333 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 3334 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 3335 /* Copy in cone of first point */ 3336 ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr); 3337 ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr); 3338 for (meetSize = 0; meetSize < dof; ++meetSize) { 3339 meet[i][meetSize] = mesh->cones[off+meetSize]; 3340 } 3341 /* Check each successive cone */ 3342 for (p = 1; p < numPoints; ++p) { 3343 PetscInt newMeetSize = 0; 3344 3345 ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr); 3346 ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr); 3347 for (c = 0; c < dof; ++c) { 3348 const PetscInt point = mesh->cones[off+c]; 3349 3350 for (m = 0; m < meetSize; ++m) { 3351 if (point == meet[i][m]) { 3352 meet[1-i][newMeetSize++] = point; 3353 break; 3354 } 3355 } 3356 } 3357 meetSize = newMeetSize; 3358 i = 1-i; 3359 } 3360 *numCoveringPoints = meetSize; 3361 *coveringPoints = meet[i]; 3362 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 3363 PetscFunctionReturn(0); 3364 } 3365 3366 /*@C 3367 DMPlexRestoreMeet - Restore an array for the meet of the set of points 3368 3369 Not Collective 3370 3371 Input Parameters: 3372 + dm - The DMPlex object 3373 . numPoints - The number of input points for the meet 3374 - points - The input points 3375 3376 Output Parameters: 3377 + numCoveredPoints - The number of points in the meet 3378 - coveredPoints - The points in the meet 3379 3380 Level: intermediate 3381 3382 Fortran Notes: 3383 Since it returns an array, this routine is only available in Fortran 90, and you must 3384 include petsc.h90 in your code. 3385 3386 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3387 3388 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 3389 @*/ 3390 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3391 { 3392 PetscErrorCode ierr; 3393 3394 PetscFunctionBegin; 3395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3396 if (points) PetscValidIntPointer(points,3); 3397 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3398 PetscValidPointer(coveredPoints,5); 3399 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3400 if (numCoveredPoints) *numCoveredPoints = 0; 3401 PetscFunctionReturn(0); 3402 } 3403 3404 /*@C 3405 DMPlexGetFullMeet - Get an array for the meet of the set of points 3406 3407 Not Collective 3408 3409 Input Parameters: 3410 + dm - The DMPlex object 3411 . numPoints - The number of input points for the meet 3412 - points - The input points 3413 3414 Output Parameters: 3415 + numCoveredPoints - The number of points in the meet 3416 - coveredPoints - The points in the meet 3417 3418 Level: intermediate 3419 3420 Fortran Notes: 3421 Since it returns an array, this routine is only available in Fortran 90, and you must 3422 include petsc.h90 in your code. 3423 3424 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3425 3426 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 3427 @*/ 3428 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3429 { 3430 DM_Plex *mesh = (DM_Plex*) dm->data; 3431 PetscInt *offsets, **closures; 3432 PetscInt *meet[2]; 3433 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 3434 PetscInt p, h, c, m, mc; 3435 PetscErrorCode ierr; 3436 3437 PetscFunctionBegin; 3438 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3439 PetscValidPointer(points, 2); 3440 PetscValidPointer(numCoveredPoints, 3); 3441 PetscValidPointer(coveredPoints, 4); 3442 3443 ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr); 3444 ierr = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr); 3445 ierr = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3446 mc = mesh->maxConeSize; 3447 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 3448 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 3449 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 3450 3451 for (p = 0; p < numPoints; ++p) { 3452 PetscInt closureSize; 3453 3454 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr); 3455 3456 offsets[p*(height+2)+0] = 0; 3457 for (h = 0; h < height+1; ++h) { 3458 PetscInt pStart, pEnd, i; 3459 3460 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 3461 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 3462 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 3463 offsets[p*(height+2)+h+1] = i; 3464 break; 3465 } 3466 } 3467 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 3468 } 3469 if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize); 3470 } 3471 for (h = 0; h < height+1; ++h) { 3472 PetscInt dof; 3473 3474 /* Copy in cone of first point */ 3475 dof = offsets[h+1] - offsets[h]; 3476 for (meetSize = 0; meetSize < dof; ++meetSize) { 3477 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 3478 } 3479 /* Check each successive cone */ 3480 for (p = 1; p < numPoints && meetSize; ++p) { 3481 PetscInt newMeetSize = 0; 3482 3483 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 3484 for (c = 0; c < dof; ++c) { 3485 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 3486 3487 for (m = 0; m < meetSize; ++m) { 3488 if (point == meet[i][m]) { 3489 meet[1-i][newMeetSize++] = point; 3490 break; 3491 } 3492 } 3493 } 3494 meetSize = newMeetSize; 3495 i = 1-i; 3496 } 3497 if (meetSize) break; 3498 } 3499 *numCoveredPoints = meetSize; 3500 *coveredPoints = meet[i]; 3501 for (p = 0; p < numPoints; ++p) { 3502 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr); 3503 } 3504 ierr = PetscFree(closures);CHKERRQ(ierr); 3505 ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3506 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 3507 PetscFunctionReturn(0); 3508 } 3509 3510 /*@C 3511 DMPlexEqual - Determine if two DMs have the same topology 3512 3513 Not Collective 3514 3515 Input Parameters: 3516 + dmA - A DMPlex object 3517 - dmB - A DMPlex object 3518 3519 Output Parameters: 3520 . equal - PETSC_TRUE if the topologies are identical 3521 3522 Level: intermediate 3523 3524 Notes: 3525 We are not solving graph isomorphism, so we do not permutation. 3526 3527 .seealso: DMPlexGetCone() 3528 @*/ 3529 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 3530 { 3531 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 3532 PetscErrorCode ierr; 3533 3534 PetscFunctionBegin; 3535 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 3536 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 3537 PetscValidPointer(equal, 3); 3538 3539 *equal = PETSC_FALSE; 3540 ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr); 3541 ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr); 3542 if (depth != depthB) PetscFunctionReturn(0); 3543 ierr = DMPlexGetChart(dmA, &pStart, &pEnd);CHKERRQ(ierr); 3544 ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr); 3545 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 3546 for (p = pStart; p < pEnd; ++p) { 3547 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 3548 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 3549 3550 ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr); 3551 ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr); 3552 ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr); 3553 ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr); 3554 ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr); 3555 ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr); 3556 if (coneSize != coneSizeB) PetscFunctionReturn(0); 3557 for (c = 0; c < coneSize; ++c) { 3558 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 3559 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 3560 } 3561 ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr); 3562 ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr); 3563 ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr); 3564 ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr); 3565 if (supportSize != supportSizeB) PetscFunctionReturn(0); 3566 for (s = 0; s < supportSize; ++s) { 3567 if (support[s] != supportB[s]) PetscFunctionReturn(0); 3568 } 3569 } 3570 *equal = PETSC_TRUE; 3571 PetscFunctionReturn(0); 3572 } 3573 3574 /*@C 3575 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 3576 3577 Not Collective 3578 3579 Input Parameters: 3580 + dm - The DMPlex 3581 . cellDim - The cell dimension 3582 - numCorners - The number of vertices on a cell 3583 3584 Output Parameters: 3585 . numFaceVertices - The number of vertices on a face 3586 3587 Level: developer 3588 3589 Notes: 3590 Of course this can only work for a restricted set of symmetric shapes 3591 3592 .seealso: DMPlexGetCone() 3593 @*/ 3594 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 3595 { 3596 MPI_Comm comm; 3597 PetscErrorCode ierr; 3598 3599 PetscFunctionBegin; 3600 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3601 PetscValidPointer(numFaceVertices,3); 3602 switch (cellDim) { 3603 case 0: 3604 *numFaceVertices = 0; 3605 break; 3606 case 1: 3607 *numFaceVertices = 1; 3608 break; 3609 case 2: 3610 switch (numCorners) { 3611 case 3: /* triangle */ 3612 *numFaceVertices = 2; /* Edge has 2 vertices */ 3613 break; 3614 case 4: /* quadrilateral */ 3615 *numFaceVertices = 2; /* Edge has 2 vertices */ 3616 break; 3617 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 3618 *numFaceVertices = 3; /* Edge has 3 vertices */ 3619 break; 3620 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 3621 *numFaceVertices = 3; /* Edge has 3 vertices */ 3622 break; 3623 default: 3624 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 3625 } 3626 break; 3627 case 3: 3628 switch (numCorners) { 3629 case 4: /* tetradehdron */ 3630 *numFaceVertices = 3; /* Face has 3 vertices */ 3631 break; 3632 case 6: /* tet cohesive cells */ 3633 *numFaceVertices = 4; /* Face has 4 vertices */ 3634 break; 3635 case 8: /* hexahedron */ 3636 *numFaceVertices = 4; /* Face has 4 vertices */ 3637 break; 3638 case 9: /* tet cohesive Lagrange cells */ 3639 *numFaceVertices = 6; /* Face has 6 vertices */ 3640 break; 3641 case 10: /* quadratic tetrahedron */ 3642 *numFaceVertices = 6; /* Face has 6 vertices */ 3643 break; 3644 case 12: /* hex cohesive Lagrange cells */ 3645 *numFaceVertices = 6; /* Face has 6 vertices */ 3646 break; 3647 case 18: /* quadratic tet cohesive Lagrange cells */ 3648 *numFaceVertices = 6; /* Face has 6 vertices */ 3649 break; 3650 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 3651 *numFaceVertices = 9; /* Face has 9 vertices */ 3652 break; 3653 default: 3654 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 3655 } 3656 break; 3657 default: 3658 SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim); 3659 } 3660 PetscFunctionReturn(0); 3661 } 3662 3663 /*@ 3664 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 3665 3666 Not Collective 3667 3668 Input Parameter: 3669 . dm - The DMPlex object 3670 3671 Output Parameter: 3672 . depthLabel - The DMLabel recording point depth 3673 3674 Level: developer 3675 3676 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 3677 @*/ 3678 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 3679 { 3680 PetscFunctionBegin; 3681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3682 PetscValidPointer(depthLabel, 2); 3683 *depthLabel = dm->depthLabel; 3684 PetscFunctionReturn(0); 3685 } 3686 3687 /*@ 3688 DMPlexGetDepth - Get the depth of the DAG representing this mesh 3689 3690 Not Collective 3691 3692 Input Parameter: 3693 . dm - The DMPlex object 3694 3695 Output Parameter: 3696 . depth - The number of strata (breadth first levels) in the DAG 3697 3698 Level: developer 3699 3700 Notes: 3701 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 3702 The point depth is described more in detail in DMPlexSymmetrize(). 3703 3704 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexSymmetrize() 3705 @*/ 3706 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 3707 { 3708 DMLabel label; 3709 PetscInt d = 0; 3710 PetscErrorCode ierr; 3711 3712 PetscFunctionBegin; 3713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3714 PetscValidPointer(depth, 2); 3715 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3716 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 3717 *depth = d-1; 3718 PetscFunctionReturn(0); 3719 } 3720 3721 /*@ 3722 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 3723 3724 Not Collective 3725 3726 Input Parameters: 3727 + dm - The DMPlex object 3728 - stratumValue - The requested depth 3729 3730 Output Parameters: 3731 + start - The first point at this depth 3732 - end - One beyond the last point at this depth 3733 3734 Notes: 3735 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 3736 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 3737 higher dimension, e.g., "edges". 3738 3739 Level: developer 3740 3741 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth() 3742 @*/ 3743 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3744 { 3745 DMLabel label; 3746 PetscInt pStart, pEnd; 3747 PetscErrorCode ierr; 3748 3749 PetscFunctionBegin; 3750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3751 if (start) {PetscValidPointer(start, 3); *start = 0;} 3752 if (end) {PetscValidPointer(end, 4); *end = 0;} 3753 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3754 if (pStart == pEnd) PetscFunctionReturn(0); 3755 if (stratumValue < 0) { 3756 if (start) *start = pStart; 3757 if (end) *end = pEnd; 3758 PetscFunctionReturn(0); 3759 } 3760 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3761 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 3762 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 3763 PetscFunctionReturn(0); 3764 } 3765 3766 /*@ 3767 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 3768 3769 Not Collective 3770 3771 Input Parameters: 3772 + dm - The DMPlex object 3773 - stratumValue - The requested height 3774 3775 Output Parameters: 3776 + start - The first point at this height 3777 - end - One beyond the last point at this height 3778 3779 Notes: 3780 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 3781 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 3782 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 3783 3784 Level: developer 3785 3786 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth() 3787 @*/ 3788 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3789 { 3790 DMLabel label; 3791 PetscInt depth, pStart, pEnd; 3792 PetscErrorCode ierr; 3793 3794 PetscFunctionBegin; 3795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3796 if (start) {PetscValidPointer(start, 3); *start = 0;} 3797 if (end) {PetscValidPointer(end, 4); *end = 0;} 3798 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3799 if (pStart == pEnd) PetscFunctionReturn(0); 3800 if (stratumValue < 0) { 3801 if (start) *start = pStart; 3802 if (end) *end = pEnd; 3803 PetscFunctionReturn(0); 3804 } 3805 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3806 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 3807 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 3808 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 3809 PetscFunctionReturn(0); 3810 } 3811 3812 /*@ 3813 DMPlexGetPointDepth - Get the depth of a given point 3814 3815 Not Collective 3816 3817 Input Parameter: 3818 + dm - The DMPlex object 3819 - point - The point 3820 3821 Output Parameter: 3822 . depth - The depth of the point 3823 3824 Level: intermediate 3825 3826 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth() 3827 @*/ 3828 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 3829 { 3830 PetscErrorCode ierr; 3831 3832 PetscFunctionBegin; 3833 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3834 PetscValidIntPointer(depth, 3); 3835 ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr); 3836 PetscFunctionReturn(0); 3837 } 3838 3839 /*@ 3840 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 3841 3842 Not Collective 3843 3844 Input Parameter: 3845 . dm - The DMPlex object 3846 3847 Output Parameter: 3848 . celltypeLabel - The DMLabel recording cell polytope type 3849 3850 Level: developer 3851 3852 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth() 3853 @*/ 3854 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 3855 { 3856 PetscErrorCode ierr; 3857 3858 PetscFunctionBegin; 3859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3860 PetscValidPointer(celltypeLabel, 2); 3861 if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);} 3862 *celltypeLabel = dm->celltypeLabel; 3863 PetscFunctionReturn(0); 3864 } 3865 3866 /*@ 3867 DMPlexGetCellType - Get the polytope type of a given cell 3868 3869 Not Collective 3870 3871 Input Parameter: 3872 + dm - The DMPlex object 3873 - cell - The cell 3874 3875 Output Parameter: 3876 . celltype - The polytope type of the cell 3877 3878 Level: intermediate 3879 3880 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth() 3881 @*/ 3882 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 3883 { 3884 DMLabel label; 3885 PetscInt ct; 3886 PetscErrorCode ierr; 3887 3888 PetscFunctionBegin; 3889 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3890 PetscValidPointer(celltype, 3); 3891 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 3892 ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr); 3893 *celltype = (DMPolytopeType) ct; 3894 PetscFunctionReturn(0); 3895 } 3896 3897 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 3898 { 3899 PetscSection section, s; 3900 Mat m; 3901 PetscInt maxHeight; 3902 PetscErrorCode ierr; 3903 3904 PetscFunctionBegin; 3905 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 3906 ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr); 3907 ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr); 3908 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 3909 ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr); 3910 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 3911 ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr); 3912 ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr); 3913 ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr); 3914 ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 3915 ierr = MatDestroy(&m);CHKERRQ(ierr); 3916 3917 ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr); 3918 ierr = DMCreateDS(*cdm);CHKERRQ(ierr); 3919 PetscFunctionReturn(0); 3920 } 3921 3922 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 3923 { 3924 Vec coordsLocal; 3925 DM coordsDM; 3926 PetscErrorCode ierr; 3927 3928 PetscFunctionBegin; 3929 *field = NULL; 3930 ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr); 3931 ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr); 3932 if (coordsLocal && coordsDM) { 3933 ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr); 3934 } 3935 PetscFunctionReturn(0); 3936 } 3937 3938 /*@C 3939 DMPlexGetConeSection - Return a section which describes the layout of cone data 3940 3941 Not Collective 3942 3943 Input Parameters: 3944 . dm - The DMPlex object 3945 3946 Output Parameter: 3947 . section - The PetscSection object 3948 3949 Level: developer 3950 3951 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations() 3952 @*/ 3953 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 3954 { 3955 DM_Plex *mesh = (DM_Plex*) dm->data; 3956 3957 PetscFunctionBegin; 3958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3959 if (section) *section = mesh->coneSection; 3960 PetscFunctionReturn(0); 3961 } 3962 3963 /*@C 3964 DMPlexGetSupportSection - Return a section which describes the layout of support data 3965 3966 Not Collective 3967 3968 Input Parameters: 3969 . dm - The DMPlex object 3970 3971 Output Parameter: 3972 . section - The PetscSection object 3973 3974 Level: developer 3975 3976 .seealso: DMPlexGetConeSection() 3977 @*/ 3978 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 3979 { 3980 DM_Plex *mesh = (DM_Plex*) dm->data; 3981 3982 PetscFunctionBegin; 3983 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3984 if (section) *section = mesh->supportSection; 3985 PetscFunctionReturn(0); 3986 } 3987 3988 /*@C 3989 DMPlexGetCones - Return cone data 3990 3991 Not Collective 3992 3993 Input Parameters: 3994 . dm - The DMPlex object 3995 3996 Output Parameter: 3997 . cones - The cone for each point 3998 3999 Level: developer 4000 4001 .seealso: DMPlexGetConeSection() 4002 @*/ 4003 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 4004 { 4005 DM_Plex *mesh = (DM_Plex*) dm->data; 4006 4007 PetscFunctionBegin; 4008 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4009 if (cones) *cones = mesh->cones; 4010 PetscFunctionReturn(0); 4011 } 4012 4013 /*@C 4014 DMPlexGetConeOrientations - Return cone orientation data 4015 4016 Not Collective 4017 4018 Input Parameters: 4019 . dm - The DMPlex object 4020 4021 Output Parameter: 4022 . coneOrientations - The cone orientation for each point 4023 4024 Level: developer 4025 4026 .seealso: DMPlexGetConeSection() 4027 @*/ 4028 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 4029 { 4030 DM_Plex *mesh = (DM_Plex*) dm->data; 4031 4032 PetscFunctionBegin; 4033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4034 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 4035 PetscFunctionReturn(0); 4036 } 4037 4038 /******************************** FEM Support **********************************/ 4039 4040 /* 4041 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 4042 representing a line in the section. 4043 */ 4044 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 4045 { 4046 PetscErrorCode ierr; 4047 4048 PetscFunctionBeginHot; 4049 ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr); 4050 if (line < 0) { 4051 *k = 0; 4052 *Nc = 0; 4053 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 4054 *k = 1; 4055 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 4056 /* An order k SEM disc has k-1 dofs on an edge */ 4057 ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr); 4058 *k = *k / *Nc + 1; 4059 } 4060 PetscFunctionReturn(0); 4061 } 4062 4063 /*@ 4064 4065 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 4066 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 4067 section provided (or the section of the DM). 4068 4069 Input Parameters: 4070 + dm - The DM 4071 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 4072 - section - The PetscSection to reorder, or NULL for the default section 4073 4074 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 4075 degree of the basis. 4076 4077 Example: 4078 A typical interpolated single-quad mesh might order points as 4079 .vb 4080 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 4081 4082 v4 -- e6 -- v3 4083 | | 4084 e7 c0 e8 4085 | | 4086 v1 -- e5 -- v2 4087 .ve 4088 4089 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 4090 dofs in the order of points, e.g., 4091 .vb 4092 c0 -> [0,1,2,3] 4093 v1 -> [4] 4094 ... 4095 e5 -> [8, 9] 4096 .ve 4097 4098 which corresponds to the dofs 4099 .vb 4100 6 10 11 7 4101 13 2 3 15 4102 12 0 1 14 4103 4 8 9 5 4104 .ve 4105 4106 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 4107 .vb 4108 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 4109 .ve 4110 4111 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 4112 .vb 4113 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 4114 .ve 4115 4116 Level: developer 4117 4118 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection() 4119 @*/ 4120 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 4121 { 4122 DMLabel label; 4123 PetscInt *perm; 4124 PetscInt dim, depth = -1, eStart = -1, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 4125 PetscBool vertexchart; 4126 PetscErrorCode ierr; 4127 4128 PetscFunctionBegin; 4129 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4130 if (dim < 1) PetscFunctionReturn(0); 4131 if (point < 0) { 4132 PetscInt sStart,sEnd; 4133 4134 ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr); 4135 point = sEnd-sStart ? sStart : point; 4136 } 4137 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4138 if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); } 4139 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 4140 if (depth == 1) {eStart = point;} 4141 else if (depth == dim) { 4142 const PetscInt *cone; 4143 4144 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4145 if (dim == 2) eStart = cone[0]; 4146 else if (dim == 3) { 4147 const PetscInt *cone2; 4148 ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr); 4149 eStart = cone2[0]; 4150 } else SETERRQ3(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); 4151 } else if (depth >= 0) SETERRQ3(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); 4152 { /* Determine whether the chart covers all points or just vertices. */ 4153 PetscInt pStart,pEnd,cStart,cEnd; 4154 ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr); 4155 ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr); 4156 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */ 4157 else vertexchart = PETSC_FALSE; /* Assume all interpolated points are in chart */ 4158 } 4159 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 4160 for (f = 0; f < Nf; ++f) { 4161 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4162 size += PetscPowInt(k+1, dim)*Nc; 4163 } 4164 ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr); 4165 for (f = 0; f < Nf; ++f) { 4166 switch (dim) { 4167 case 1: 4168 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4169 /* 4170 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 4171 We want [ vtx0; edge of length k-1; vtx1 ] 4172 */ 4173 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 4174 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 4175 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 4176 foffset = offset; 4177 break; 4178 case 2: 4179 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 4180 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4181 /* The SEM order is 4182 4183 v_lb, {e_b}, v_rb, 4184 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 4185 v_lt, reverse {e_t}, v_rt 4186 */ 4187 { 4188 const PetscInt of = 0; 4189 const PetscInt oeb = of + PetscSqr(k-1); 4190 const PetscInt oer = oeb + (k-1); 4191 const PetscInt oet = oer + (k-1); 4192 const PetscInt oel = oet + (k-1); 4193 const PetscInt ovlb = oel + (k-1); 4194 const PetscInt ovrb = ovlb + 1; 4195 const PetscInt ovrt = ovrb + 1; 4196 const PetscInt ovlt = ovrt + 1; 4197 PetscInt o; 4198 4199 /* bottom */ 4200 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 4201 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4202 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 4203 /* middle */ 4204 for (i = 0; i < k-1; ++i) { 4205 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 4206 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; 4207 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 4208 } 4209 /* top */ 4210 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 4211 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4212 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 4213 foffset = offset; 4214 } 4215 break; 4216 case 3: 4217 /* The original hex closure is 4218 4219 {c, 4220 f_b, f_t, f_f, f_b, f_r, f_l, 4221 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 4222 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 4223 */ 4224 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4225 /* The SEM order is 4226 Bottom Slice 4227 v_blf, {e^{(k-1)-n}_bf}, v_brf, 4228 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 4229 v_blb, {e_bb}, v_brb, 4230 4231 Middle Slice (j) 4232 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 4233 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 4234 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 4235 4236 Top Slice 4237 v_tlf, {e_tf}, v_trf, 4238 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 4239 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 4240 */ 4241 { 4242 const PetscInt oc = 0; 4243 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 4244 const PetscInt oft = ofb + PetscSqr(k-1); 4245 const PetscInt off = oft + PetscSqr(k-1); 4246 const PetscInt ofk = off + PetscSqr(k-1); 4247 const PetscInt ofr = ofk + PetscSqr(k-1); 4248 const PetscInt ofl = ofr + PetscSqr(k-1); 4249 const PetscInt oebl = ofl + PetscSqr(k-1); 4250 const PetscInt oebb = oebl + (k-1); 4251 const PetscInt oebr = oebb + (k-1); 4252 const PetscInt oebf = oebr + (k-1); 4253 const PetscInt oetf = oebf + (k-1); 4254 const PetscInt oetr = oetf + (k-1); 4255 const PetscInt oetb = oetr + (k-1); 4256 const PetscInt oetl = oetb + (k-1); 4257 const PetscInt oerf = oetl + (k-1); 4258 const PetscInt oelf = oerf + (k-1); 4259 const PetscInt oelb = oelf + (k-1); 4260 const PetscInt oerb = oelb + (k-1); 4261 const PetscInt ovblf = oerb + (k-1); 4262 const PetscInt ovblb = ovblf + 1; 4263 const PetscInt ovbrb = ovblb + 1; 4264 const PetscInt ovbrf = ovbrb + 1; 4265 const PetscInt ovtlf = ovbrf + 1; 4266 const PetscInt ovtrf = ovtlf + 1; 4267 const PetscInt ovtrb = ovtrf + 1; 4268 const PetscInt ovtlb = ovtrb + 1; 4269 PetscInt o, n; 4270 4271 /* Bottom Slice */ 4272 /* bottom */ 4273 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 4274 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4275 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 4276 /* middle */ 4277 for (i = 0; i < k-1; ++i) { 4278 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 4279 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;} 4280 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 4281 } 4282 /* top */ 4283 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 4284 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4285 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 4286 4287 /* Middle Slice */ 4288 for (j = 0; j < k-1; ++j) { 4289 /* bottom */ 4290 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 4291 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; 4292 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 4293 /* middle */ 4294 for (i = 0; i < k-1; ++i) { 4295 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 4296 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; 4297 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 4298 } 4299 /* top */ 4300 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 4301 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; 4302 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 4303 } 4304 4305 /* Top Slice */ 4306 /* bottom */ 4307 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 4308 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4309 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 4310 /* middle */ 4311 for (i = 0; i < k-1; ++i) { 4312 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 4313 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 4314 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 4315 } 4316 /* top */ 4317 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 4318 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4319 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 4320 4321 foffset = offset; 4322 } 4323 break; 4324 default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim); 4325 } 4326 } 4327 if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size); 4328 /* Check permutation */ 4329 { 4330 PetscInt *check; 4331 4332 ierr = PetscMalloc1(size, &check);CHKERRQ(ierr); 4333 for (i = 0; i < size; ++i) {check[i] = -1; if (perm[i] < 0 || perm[i] >= size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);} 4334 for (i = 0; i < size; ++i) check[perm[i]] = i; 4335 for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);} 4336 ierr = PetscFree(check);CHKERRQ(ierr); 4337 } 4338 ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr); 4339 PetscFunctionReturn(0); 4340 } 4341 4342 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 4343 { 4344 PetscDS prob; 4345 PetscInt depth, Nf, h; 4346 DMLabel label; 4347 PetscErrorCode ierr; 4348 4349 PetscFunctionBeginHot; 4350 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 4351 Nf = prob->Nf; 4352 label = dm->depthLabel; 4353 *dspace = NULL; 4354 if (field < Nf) { 4355 PetscObject disc = prob->disc[field]; 4356 4357 if (disc->classid == PETSCFE_CLASSID) { 4358 PetscDualSpace dsp; 4359 4360 ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr); 4361 ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr); 4362 ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr); 4363 h = depth - 1 - h; 4364 if (h) { 4365 ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr); 4366 } else { 4367 *dspace = dsp; 4368 } 4369 } 4370 } 4371 PetscFunctionReturn(0); 4372 } 4373 4374 4375 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4376 { 4377 PetscScalar *array, *vArray; 4378 const PetscInt *cone, *coneO; 4379 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 4380 PetscErrorCode ierr; 4381 4382 PetscFunctionBeginHot; 4383 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4384 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4385 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4386 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4387 if (!values || !*values) { 4388 if ((point >= pStart) && (point < pEnd)) { 4389 PetscInt dof; 4390 4391 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4392 size += dof; 4393 } 4394 for (p = 0; p < numPoints; ++p) { 4395 const PetscInt cp = cone[p]; 4396 PetscInt dof; 4397 4398 if ((cp < pStart) || (cp >= pEnd)) continue; 4399 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4400 size += dof; 4401 } 4402 if (!values) { 4403 if (csize) *csize = size; 4404 PetscFunctionReturn(0); 4405 } 4406 ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr); 4407 } else { 4408 array = *values; 4409 } 4410 size = 0; 4411 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4412 if ((point >= pStart) && (point < pEnd)) { 4413 PetscInt dof, off, d; 4414 PetscScalar *varr; 4415 4416 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4417 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4418 varr = &vArray[off]; 4419 for (d = 0; d < dof; ++d, ++offset) { 4420 array[offset] = varr[d]; 4421 } 4422 size += dof; 4423 } 4424 for (p = 0; p < numPoints; ++p) { 4425 const PetscInt cp = cone[p]; 4426 PetscInt o = coneO[p]; 4427 PetscInt dof, off, d; 4428 PetscScalar *varr; 4429 4430 if ((cp < pStart) || (cp >= pEnd)) continue; 4431 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4432 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 4433 varr = &vArray[off]; 4434 if (o >= 0) { 4435 for (d = 0; d < dof; ++d, ++offset) { 4436 array[offset] = varr[d]; 4437 } 4438 } else { 4439 for (d = dof-1; d >= 0; --d, ++offset) { 4440 array[offset] = varr[d]; 4441 } 4442 } 4443 size += dof; 4444 } 4445 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4446 if (!*values) { 4447 if (csize) *csize = size; 4448 *values = array; 4449 } else { 4450 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 4451 *csize = size; 4452 } 4453 PetscFunctionReturn(0); 4454 } 4455 4456 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 4457 { 4458 const PetscInt *cla; 4459 PetscInt np, *pts = NULL; 4460 PetscErrorCode ierr; 4461 4462 PetscFunctionBeginHot; 4463 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr); 4464 if (!*clPoints) { 4465 PetscInt pStart, pEnd, p, q; 4466 4467 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4468 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr); 4469 /* Compress out points not in the section */ 4470 for (p = 0, q = 0; p < np; p++) { 4471 PetscInt r = pts[2*p]; 4472 if ((r >= pStart) && (r < pEnd)) { 4473 pts[q*2] = r; 4474 pts[q*2+1] = pts[2*p+1]; 4475 ++q; 4476 } 4477 } 4478 np = q; 4479 cla = NULL; 4480 } else { 4481 PetscInt dof, off; 4482 4483 ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr); 4484 ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr); 4485 ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr); 4486 np = dof/2; 4487 pts = (PetscInt *) &cla[off]; 4488 } 4489 *numPoints = np; 4490 *points = pts; 4491 *clp = cla; 4492 4493 PetscFunctionReturn(0); 4494 } 4495 4496 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 4497 { 4498 PetscErrorCode ierr; 4499 4500 PetscFunctionBeginHot; 4501 if (!*clPoints) { 4502 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr); 4503 } else { 4504 ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr); 4505 } 4506 *numPoints = 0; 4507 *points = NULL; 4508 *clSec = NULL; 4509 *clPoints = NULL; 4510 *clp = NULL; 4511 PetscFunctionReturn(0); 4512 } 4513 4514 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(DM dm, PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt clperm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 4515 { 4516 PetscInt offset = 0, p; 4517 const PetscInt **perms = NULL; 4518 const PetscScalar **flips = NULL; 4519 PetscErrorCode ierr; 4520 4521 PetscFunctionBeginHot; 4522 *size = 0; 4523 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4524 for (p = 0; p < numPoints; p++) { 4525 const PetscInt point = points[2*p]; 4526 const PetscInt *perm = perms ? perms[p] : NULL; 4527 const PetscScalar *flip = flips ? flips[p] : NULL; 4528 PetscInt dof, off, d; 4529 const PetscScalar *varr; 4530 4531 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4532 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4533 varr = &vArray[off]; 4534 if (clperm) { 4535 if (perm) { 4536 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 4537 } else { 4538 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 4539 } 4540 if (flip) { 4541 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 4542 } 4543 } else { 4544 if (perm) { 4545 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 4546 } else { 4547 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 4548 } 4549 if (flip) { 4550 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 4551 } 4552 } 4553 offset += dof; 4554 } 4555 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4556 *size = offset; 4557 PetscFunctionReturn(0); 4558 } 4559 4560 PETSC_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[]) 4561 { 4562 PetscInt offset = 0, f; 4563 PetscErrorCode ierr; 4564 4565 PetscFunctionBeginHot; 4566 *size = 0; 4567 for (f = 0; f < numFields; ++f) { 4568 PetscInt p; 4569 const PetscInt **perms = NULL; 4570 const PetscScalar **flips = NULL; 4571 4572 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4573 for (p = 0; p < numPoints; p++) { 4574 const PetscInt point = points[2*p]; 4575 PetscInt fdof, foff, b; 4576 const PetscScalar *varr; 4577 const PetscInt *perm = perms ? perms[p] : NULL; 4578 const PetscScalar *flip = flips ? flips[p] : NULL; 4579 4580 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4581 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4582 varr = &vArray[foff]; 4583 if (clperm) { 4584 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 4585 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 4586 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 4587 } else { 4588 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 4589 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 4590 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 4591 } 4592 offset += fdof; 4593 } 4594 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 4595 } 4596 *size = offset; 4597 PetscFunctionReturn(0); 4598 } 4599 4600 /*@C 4601 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 4602 4603 Not collective 4604 4605 Input Parameters: 4606 + dm - The DM 4607 . section - The section describing the layout in v, or NULL to use the default section 4608 . v - The local vector 4609 . point - The point in the DM 4610 . csize - The size of the input values array, or NULL 4611 - values - An array to use for the values, or NULL to have it allocated automatically 4612 4613 Output Parameters: 4614 + csize - The number of values in the closure 4615 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed 4616 4617 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 4618 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 4619 $ assembly function, and a user may already have allocated storage for this operation. 4620 $ 4621 $ A typical use could be 4622 $ 4623 $ values = NULL; 4624 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4625 $ for (cl = 0; cl < clSize; ++cl) { 4626 $ <Compute on closure> 4627 $ } 4628 $ ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4629 $ 4630 $ or 4631 $ 4632 $ PetscMalloc1(clMaxSize, &values); 4633 $ for (p = pStart; p < pEnd; ++p) { 4634 $ clSize = clMaxSize; 4635 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 4636 $ for (cl = 0; cl < clSize; ++cl) { 4637 $ <Compute on closure> 4638 $ } 4639 $ } 4640 $ PetscFree(values); 4641 4642 Fortran Notes: 4643 Since it returns an array, this routine is only available in Fortran 90, and you must 4644 include petsc.h90 in your code. 4645 4646 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4647 4648 Level: intermediate 4649 4650 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4651 @*/ 4652 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4653 { 4654 PetscSection clSection; 4655 IS clPoints; 4656 PetscScalar *array; 4657 const PetscScalar *vArray; 4658 PetscInt *points = NULL; 4659 const PetscInt *clp, *perm; 4660 PetscInt depth, numFields, numPoints, size; 4661 PetscErrorCode ierr; 4662 4663 PetscFunctionBeginHot; 4664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4665 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 4666 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4667 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4668 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4669 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4670 if (depth == 1 && numFields < 2) { 4671 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 4672 PetscFunctionReturn(0); 4673 } 4674 /* Get points */ 4675 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4676 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr); 4677 /* Get array */ 4678 if (!values || !*values) { 4679 PetscInt asize = 0, dof, p; 4680 4681 for (p = 0; p < numPoints*2; p += 2) { 4682 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4683 asize += dof; 4684 } 4685 if (!values) { 4686 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4687 if (csize) *csize = asize; 4688 PetscFunctionReturn(0); 4689 } 4690 ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr); 4691 } else { 4692 array = *values; 4693 } 4694 ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr); 4695 /* Get values */ 4696 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);} 4697 else {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);} 4698 /* Cleanup points */ 4699 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4700 /* Cleanup array */ 4701 ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr); 4702 if (!*values) { 4703 if (csize) *csize = size; 4704 *values = array; 4705 } else { 4706 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 4707 *csize = size; 4708 } 4709 PetscFunctionReturn(0); 4710 } 4711 4712 /*@C 4713 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 4714 4715 Not collective 4716 4717 Input Parameters: 4718 + dm - The DM 4719 . section - The section describing the layout in v, or NULL to use the default section 4720 . v - The local vector 4721 . point - The point in the DM 4722 . csize - The number of values in the closure, or NULL 4723 - values - The array of values, which is a borrowed array and should not be freed 4724 4725 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 4726 4727 Fortran Notes: 4728 Since it returns an array, this routine is only available in Fortran 90, and you must 4729 include petsc.h90 in your code. 4730 4731 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4732 4733 Level: intermediate 4734 4735 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4736 @*/ 4737 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4738 { 4739 PetscInt size = 0; 4740 PetscErrorCode ierr; 4741 4742 PetscFunctionBegin; 4743 /* Should work without recalculating size */ 4744 ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr); 4745 *values = NULL; 4746 PetscFunctionReturn(0); 4747 } 4748 4749 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 4750 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 4751 4752 PETSC_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[]) 4753 { 4754 PetscInt cdof; /* The number of constraints on this point */ 4755 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4756 PetscScalar *a; 4757 PetscInt off, cind = 0, k; 4758 PetscErrorCode ierr; 4759 4760 PetscFunctionBegin; 4761 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4762 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4763 a = &array[off]; 4764 if (!cdof || setBC) { 4765 if (clperm) { 4766 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 4767 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 4768 } else { 4769 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 4770 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 4771 } 4772 } else { 4773 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4774 if (clperm) { 4775 if (perm) {for (k = 0; k < dof; ++k) { 4776 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4777 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 4778 } 4779 } else { 4780 for (k = 0; k < dof; ++k) { 4781 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4782 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 4783 } 4784 } 4785 } else { 4786 if (perm) { 4787 for (k = 0; k < dof; ++k) { 4788 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4789 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 4790 } 4791 } else { 4792 for (k = 0; k < dof; ++k) { 4793 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4794 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 4795 } 4796 } 4797 } 4798 } 4799 PetscFunctionReturn(0); 4800 } 4801 4802 PETSC_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[]) 4803 { 4804 PetscInt cdof; /* The number of constraints on this point */ 4805 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4806 PetscScalar *a; 4807 PetscInt off, cind = 0, k; 4808 PetscErrorCode ierr; 4809 4810 PetscFunctionBegin; 4811 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4812 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4813 a = &array[off]; 4814 if (cdof) { 4815 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4816 if (clperm) { 4817 if (perm) { 4818 for (k = 0; k < dof; ++k) { 4819 if ((cind < cdof) && (k == cdofs[cind])) { 4820 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 4821 cind++; 4822 } 4823 } 4824 } else { 4825 for (k = 0; k < dof; ++k) { 4826 if ((cind < cdof) && (k == cdofs[cind])) { 4827 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 4828 cind++; 4829 } 4830 } 4831 } 4832 } else { 4833 if (perm) { 4834 for (k = 0; k < dof; ++k) { 4835 if ((cind < cdof) && (k == cdofs[cind])) { 4836 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 4837 cind++; 4838 } 4839 } 4840 } else { 4841 for (k = 0; k < dof; ++k) { 4842 if ((cind < cdof) && (k == cdofs[cind])) { 4843 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 4844 cind++; 4845 } 4846 } 4847 } 4848 } 4849 } 4850 PetscFunctionReturn(0); 4851 } 4852 4853 PETSC_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[]) 4854 { 4855 PetscScalar *a; 4856 PetscInt fdof, foff, fcdof, foffset = *offset; 4857 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4858 PetscInt cind = 0, b; 4859 PetscErrorCode ierr; 4860 4861 PetscFunctionBegin; 4862 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4863 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4864 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4865 a = &array[foff]; 4866 if (!fcdof || setBC) { 4867 if (clperm) { 4868 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 4869 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 4870 } else { 4871 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 4872 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 4873 } 4874 } else { 4875 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4876 if (clperm) { 4877 if (perm) { 4878 for (b = 0; b < fdof; b++) { 4879 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4880 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 4881 } 4882 } else { 4883 for (b = 0; b < fdof; b++) { 4884 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4885 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 4886 } 4887 } 4888 } else { 4889 if (perm) { 4890 for (b = 0; b < fdof; b++) { 4891 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4892 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 4893 } 4894 } else { 4895 for (b = 0; b < fdof; b++) { 4896 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 4897 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 4898 } 4899 } 4900 } 4901 } 4902 *offset += fdof; 4903 PetscFunctionReturn(0); 4904 } 4905 4906 PETSC_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[]) 4907 { 4908 PetscScalar *a; 4909 PetscInt fdof, foff, fcdof, foffset = *offset; 4910 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4911 PetscInt cind = 0, ncind = 0, b; 4912 PetscBool ncSet, fcSet; 4913 PetscErrorCode ierr; 4914 4915 PetscFunctionBegin; 4916 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4917 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4918 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4919 a = &array[foff]; 4920 if (fcdof) { 4921 /* We just override fcdof and fcdofs with Ncc and comps */ 4922 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4923 if (clperm) { 4924 if (perm) { 4925 if (comps) { 4926 for (b = 0; b < fdof; b++) { 4927 ncSet = fcSet = PETSC_FALSE; 4928 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4929 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4930 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 4931 } 4932 } else { 4933 for (b = 0; b < fdof; b++) { 4934 if ((cind < fcdof) && (b == fcdofs[cind])) { 4935 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 4936 ++cind; 4937 } 4938 } 4939 } 4940 } else { 4941 if (comps) { 4942 for (b = 0; b < fdof; b++) { 4943 ncSet = fcSet = PETSC_FALSE; 4944 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4945 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4946 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 4947 } 4948 } else { 4949 for (b = 0; b < fdof; b++) { 4950 if ((cind < fcdof) && (b == fcdofs[cind])) { 4951 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 4952 ++cind; 4953 } 4954 } 4955 } 4956 } 4957 } else { 4958 if (perm) { 4959 if (comps) { 4960 for (b = 0; b < fdof; b++) { 4961 ncSet = fcSet = PETSC_FALSE; 4962 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4963 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4964 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 4965 } 4966 } else { 4967 for (b = 0; b < fdof; b++) { 4968 if ((cind < fcdof) && (b == fcdofs[cind])) { 4969 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 4970 ++cind; 4971 } 4972 } 4973 } 4974 } else { 4975 if (comps) { 4976 for (b = 0; b < fdof; b++) { 4977 ncSet = fcSet = PETSC_FALSE; 4978 if ((ncind < Ncc) && (b == comps[ncind])) {++ncind; ncSet = PETSC_TRUE;} 4979 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 4980 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 4981 } 4982 } else { 4983 for (b = 0; b < fdof; b++) { 4984 if ((cind < fcdof) && (b == fcdofs[cind])) { 4985 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 4986 ++cind; 4987 } 4988 } 4989 } 4990 } 4991 } 4992 } 4993 *offset += fdof; 4994 PetscFunctionReturn(0); 4995 } 4996 4997 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 4998 { 4999 PetscScalar *array; 5000 const PetscInt *cone, *coneO; 5001 PetscInt pStart, pEnd, p, numPoints, off, dof; 5002 PetscErrorCode ierr; 5003 5004 PetscFunctionBeginHot; 5005 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5006 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 5007 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5008 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 5009 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5010 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 5011 const PetscInt cp = !p ? point : cone[p-1]; 5012 const PetscInt o = !p ? 0 : coneO[p-1]; 5013 5014 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 5015 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5016 /* ADD_VALUES */ 5017 { 5018 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5019 PetscScalar *a; 5020 PetscInt cdof, coff, cind = 0, k; 5021 5022 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 5023 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 5024 a = &array[coff]; 5025 if (!cdof) { 5026 if (o >= 0) { 5027 for (k = 0; k < dof; ++k) { 5028 a[k] += values[off+k]; 5029 } 5030 } else { 5031 for (k = 0; k < dof; ++k) { 5032 a[k] += values[off+dof-k-1]; 5033 } 5034 } 5035 } else { 5036 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 5037 if (o >= 0) { 5038 for (k = 0; k < dof; ++k) { 5039 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5040 a[k] += values[off+k]; 5041 } 5042 } else { 5043 for (k = 0; k < dof; ++k) { 5044 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5045 a[k] += values[off+dof-k-1]; 5046 } 5047 } 5048 } 5049 } 5050 } 5051 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5052 PetscFunctionReturn(0); 5053 } 5054 5055 /*@C 5056 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 5057 5058 Not collective 5059 5060 Input Parameters: 5061 + dm - The DM 5062 . section - The section describing the layout in v, or NULL to use the default section 5063 . v - The local vector 5064 . point - The point in the DM 5065 . values - The array of values 5066 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 5067 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 5068 5069 Fortran Notes: 5070 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5071 5072 Level: intermediate 5073 5074 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 5075 @*/ 5076 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5077 { 5078 PetscSection clSection; 5079 IS clPoints; 5080 PetscScalar *array; 5081 PetscInt *points = NULL; 5082 const PetscInt *clp, *clperm; 5083 PetscInt depth, numFields, numPoints, p; 5084 PetscErrorCode ierr; 5085 5086 PetscFunctionBeginHot; 5087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5088 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5089 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5090 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5091 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5092 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5093 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 5094 ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr); 5095 PetscFunctionReturn(0); 5096 } 5097 /* Get points */ 5098 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 5099 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5100 /* Get array */ 5101 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5102 /* Get values */ 5103 if (numFields > 0) { 5104 PetscInt offset = 0, f; 5105 for (f = 0; f < numFields; ++f) { 5106 const PetscInt **perms = NULL; 5107 const PetscScalar **flips = NULL; 5108 5109 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5110 switch (mode) { 5111 case INSERT_VALUES: 5112 for (p = 0; p < numPoints; p++) { 5113 const PetscInt point = points[2*p]; 5114 const PetscInt *perm = perms ? perms[p] : NULL; 5115 const PetscScalar *flip = flips ? flips[p] : NULL; 5116 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 5117 } break; 5118 case INSERT_ALL_VALUES: 5119 for (p = 0; p < numPoints; p++) { 5120 const PetscInt point = points[2*p]; 5121 const PetscInt *perm = perms ? perms[p] : NULL; 5122 const PetscScalar *flip = flips ? flips[p] : NULL; 5123 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 5124 } break; 5125 case INSERT_BC_VALUES: 5126 for (p = 0; p < numPoints; p++) { 5127 const PetscInt point = points[2*p]; 5128 const PetscInt *perm = perms ? perms[p] : NULL; 5129 const PetscScalar *flip = flips ? flips[p] : NULL; 5130 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 5131 } break; 5132 case ADD_VALUES: 5133 for (p = 0; p < numPoints; p++) { 5134 const PetscInt point = points[2*p]; 5135 const PetscInt *perm = perms ? perms[p] : NULL; 5136 const PetscScalar *flip = flips ? flips[p] : NULL; 5137 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 5138 } break; 5139 case ADD_ALL_VALUES: 5140 for (p = 0; p < numPoints; p++) { 5141 const PetscInt point = points[2*p]; 5142 const PetscInt *perm = perms ? perms[p] : NULL; 5143 const PetscScalar *flip = flips ? flips[p] : NULL; 5144 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 5145 } break; 5146 case ADD_BC_VALUES: 5147 for (p = 0; p < numPoints; p++) { 5148 const PetscInt point = points[2*p]; 5149 const PetscInt *perm = perms ? perms[p] : NULL; 5150 const PetscScalar *flip = flips ? flips[p] : NULL; 5151 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 5152 } break; 5153 default: 5154 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5155 } 5156 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5157 } 5158 } else { 5159 PetscInt dof, off; 5160 const PetscInt **perms = NULL; 5161 const PetscScalar **flips = NULL; 5162 5163 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5164 switch (mode) { 5165 case INSERT_VALUES: 5166 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5167 const PetscInt point = points[2*p]; 5168 const PetscInt *perm = perms ? perms[p] : NULL; 5169 const PetscScalar *flip = flips ? flips[p] : NULL; 5170 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5171 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 5172 } break; 5173 case INSERT_ALL_VALUES: 5174 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5175 const PetscInt point = points[2*p]; 5176 const PetscInt *perm = perms ? perms[p] : NULL; 5177 const PetscScalar *flip = flips ? flips[p] : NULL; 5178 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5179 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 5180 } break; 5181 case INSERT_BC_VALUES: 5182 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5183 const PetscInt point = points[2*p]; 5184 const PetscInt *perm = perms ? perms[p] : NULL; 5185 const PetscScalar *flip = flips ? flips[p] : NULL; 5186 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5187 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 5188 } break; 5189 case ADD_VALUES: 5190 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5191 const PetscInt point = points[2*p]; 5192 const PetscInt *perm = perms ? perms[p] : NULL; 5193 const PetscScalar *flip = flips ? flips[p] : NULL; 5194 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5195 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 5196 } break; 5197 case ADD_ALL_VALUES: 5198 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5199 const PetscInt point = points[2*p]; 5200 const PetscInt *perm = perms ? perms[p] : NULL; 5201 const PetscScalar *flip = flips ? flips[p] : NULL; 5202 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5203 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 5204 } break; 5205 case ADD_BC_VALUES: 5206 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5207 const PetscInt point = points[2*p]; 5208 const PetscInt *perm = perms ? perms[p] : NULL; 5209 const PetscScalar *flip = flips ? flips[p] : NULL; 5210 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5211 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 5212 } break; 5213 default: 5214 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5215 } 5216 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5217 } 5218 /* Cleanup points */ 5219 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5220 /* Cleanup array */ 5221 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5222 PetscFunctionReturn(0); 5223 } 5224 5225 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, PetscInt Ncc, const PetscInt comps[], const PetscScalar values[], InsertMode mode) 5226 { 5227 PetscSection clSection; 5228 IS clPoints; 5229 PetscScalar *array; 5230 PetscInt *points = NULL; 5231 const PetscInt *clp, *clperm; 5232 PetscInt numFields, numPoints, p; 5233 PetscInt offset = 0, f; 5234 PetscErrorCode ierr; 5235 5236 PetscFunctionBeginHot; 5237 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5238 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5239 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5240 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5241 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5242 /* Get points */ 5243 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 5244 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5245 /* Get array */ 5246 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5247 /* Get values */ 5248 for (f = 0; f < numFields; ++f) { 5249 const PetscInt **perms = NULL; 5250 const PetscScalar **flips = NULL; 5251 5252 if (!fieldActive[f]) { 5253 for (p = 0; p < numPoints*2; p += 2) { 5254 PetscInt fdof; 5255 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5256 offset += fdof; 5257 } 5258 continue; 5259 } 5260 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5261 switch (mode) { 5262 case INSERT_VALUES: 5263 for (p = 0; p < numPoints; p++) { 5264 const PetscInt point = points[2*p]; 5265 const PetscInt *perm = perms ? perms[p] : NULL; 5266 const PetscScalar *flip = flips ? flips[p] : NULL; 5267 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 5268 } break; 5269 case INSERT_ALL_VALUES: 5270 for (p = 0; p < numPoints; p++) { 5271 const PetscInt point = points[2*p]; 5272 const PetscInt *perm = perms ? perms[p] : NULL; 5273 const PetscScalar *flip = flips ? flips[p] : NULL; 5274 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 5275 } break; 5276 case INSERT_BC_VALUES: 5277 for (p = 0; p < numPoints; p++) { 5278 const PetscInt point = points[2*p]; 5279 const PetscInt *perm = perms ? perms[p] : NULL; 5280 const PetscScalar *flip = flips ? flips[p] : NULL; 5281 updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, clperm, values, &offset, array); 5282 } break; 5283 case ADD_VALUES: 5284 for (p = 0; p < numPoints; p++) { 5285 const PetscInt point = points[2*p]; 5286 const PetscInt *perm = perms ? perms[p] : NULL; 5287 const PetscScalar *flip = flips ? flips[p] : NULL; 5288 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 5289 } break; 5290 case ADD_ALL_VALUES: 5291 for (p = 0; p < numPoints; p++) { 5292 const PetscInt point = points[2*p]; 5293 const PetscInt *perm = perms ? perms[p] : NULL; 5294 const PetscScalar *flip = flips ? flips[p] : NULL; 5295 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 5296 } break; 5297 default: 5298 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5299 } 5300 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5301 } 5302 /* Cleanup points */ 5303 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5304 /* Cleanup array */ 5305 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5306 PetscFunctionReturn(0); 5307 } 5308 5309 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 5310 { 5311 PetscMPIInt rank; 5312 PetscInt i, j; 5313 PetscErrorCode ierr; 5314 5315 PetscFunctionBegin; 5316 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr); 5317 ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr); 5318 for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);} 5319 for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);} 5320 numCIndices = numCIndices ? numCIndices : numRIndices; 5321 for (i = 0; i < numRIndices; i++) { 5322 ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr); 5323 for (j = 0; j < numCIndices; j++) { 5324 #if defined(PETSC_USE_COMPLEX) 5325 ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr); 5326 #else 5327 ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr); 5328 #endif 5329 } 5330 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 5331 } 5332 PetscFunctionReturn(0); 5333 } 5334 5335 /* 5336 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 5337 5338 Input Parameters: 5339 + section - The section for this data layout 5340 . point - The point contributing dofs with these indices 5341 . off - The global offset of this point 5342 . loff - The local offset of each field 5343 . setBC - The flag determining whether to include indices of bounsary values 5344 . perm - A permutation of the dofs on this point, or NULL 5345 - indperm - A permutation of the entire indices array, or NULL 5346 5347 Output Parameter: 5348 . indices - Indices for dofs on this point 5349 5350 Level: developer 5351 5352 Note: The indices could be local or global, depending on the value of 'off'. 5353 */ 5354 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 5355 { 5356 PetscInt dof; /* The number of unknowns on this point */ 5357 PetscInt cdof; /* The number of constraints on this point */ 5358 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5359 PetscInt cind = 0, k; 5360 PetscErrorCode ierr; 5361 5362 PetscFunctionBegin; 5363 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5364 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5365 if (!cdof || setBC) { 5366 for (k = 0; k < dof; ++k) { 5367 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 5368 const PetscInt ind = indperm ? indperm[preind] : preind; 5369 5370 indices[ind] = off + k; 5371 } 5372 } else { 5373 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5374 for (k = 0; k < dof; ++k) { 5375 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 5376 const PetscInt ind = indperm ? indperm[preind] : preind; 5377 5378 if ((cind < cdof) && (k == cdofs[cind])) { 5379 /* Insert check for returning constrained indices */ 5380 indices[ind] = -(off+k+1); 5381 ++cind; 5382 } else { 5383 indices[ind] = off+k-cind; 5384 } 5385 } 5386 } 5387 *loff += dof; 5388 PetscFunctionReturn(0); 5389 } 5390 5391 /* 5392 This version only believes the point offset from the globalSection 5393 5394 . off - The global offset of this point 5395 */ 5396 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 5397 { 5398 PetscInt numFields, foff, f; 5399 PetscErrorCode ierr; 5400 5401 PetscFunctionBegin; 5402 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5403 for (f = 0, foff = 0; f < numFields; ++f) { 5404 PetscInt fdof, cfdof; 5405 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5406 PetscInt cind = 0, b; 5407 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 5408 5409 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5410 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5411 if (!cfdof || setBC) { 5412 for (b = 0; b < fdof; ++b) { 5413 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5414 const PetscInt ind = indperm ? indperm[preind] : preind; 5415 5416 indices[ind] = off+foff+b; 5417 } 5418 } else { 5419 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5420 for (b = 0; b < fdof; ++b) { 5421 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5422 const PetscInt ind = indperm ? indperm[preind] : preind; 5423 5424 if ((cind < cfdof) && (b == fcdofs[cind])) { 5425 indices[ind] = -(off+foff+b+1); 5426 ++cind; 5427 } else { 5428 indices[ind] = off+foff+b-cind; 5429 } 5430 } 5431 } 5432 foff += (setBC ? fdof : (fdof - cfdof)); 5433 foffs[f] += fdof; 5434 } 5435 PetscFunctionReturn(0); 5436 } 5437 5438 /* 5439 This version believes the globalSection offsets for each field, rather than just the point offset 5440 5441 . foffs - The offset into 'indices' for each field, since it is segregated by field 5442 */ 5443 PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], PetscBool setBC, const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 5444 { 5445 PetscInt numFields, foff, f; 5446 PetscErrorCode ierr; 5447 5448 PetscFunctionBegin; 5449 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5450 for (f = 0; f < numFields; ++f) { 5451 PetscInt fdof, cfdof; 5452 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5453 PetscInt cind = 0, b; 5454 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 5455 5456 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5457 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5458 ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr); 5459 if (!cfdof || setBC) { 5460 for (b = 0; b < fdof; ++b) { 5461 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5462 const PetscInt ind = indperm ? indperm[preind] : preind; 5463 5464 indices[ind] = foff+b; 5465 } 5466 } else { 5467 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5468 for (b = 0; b < fdof; ++b) { 5469 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 5470 const PetscInt ind = indperm ? indperm[preind] : preind; 5471 5472 if ((cind < cfdof) && (b == fcdofs[cind])) { 5473 indices[ind] = -(foff+b+1); 5474 ++cind; 5475 } else { 5476 indices[ind] = foff+b-cind; 5477 } 5478 } 5479 } 5480 foffs[f] += fdof; 5481 } 5482 PetscFunctionReturn(0); 5483 } 5484 5485 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) 5486 { 5487 Mat cMat; 5488 PetscSection aSec, cSec; 5489 IS aIS; 5490 PetscInt aStart = -1, aEnd = -1; 5491 const PetscInt *anchors; 5492 PetscInt numFields, f, p, q, newP = 0; 5493 PetscInt newNumPoints = 0, newNumIndices = 0; 5494 PetscInt *newPoints, *indices, *newIndices; 5495 PetscInt maxAnchor, maxDof; 5496 PetscInt newOffsets[32]; 5497 PetscInt *pointMatOffsets[32]; 5498 PetscInt *newPointOffsets[32]; 5499 PetscScalar *pointMat[32]; 5500 PetscScalar *newValues=NULL,*tmpValues; 5501 PetscBool anyConstrained = PETSC_FALSE; 5502 PetscErrorCode ierr; 5503 5504 PetscFunctionBegin; 5505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5506 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5507 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5508 5509 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 5510 /* if there are point-to-point constraints */ 5511 if (aSec) { 5512 ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr); 5513 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 5514 ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); 5515 /* figure out how many points are going to be in the new element matrix 5516 * (we allow double counting, because it's all just going to be summed 5517 * into the global matrix anyway) */ 5518 for (p = 0; p < 2*numPoints; p+=2) { 5519 PetscInt b = points[p]; 5520 PetscInt bDof = 0, bSecDof; 5521 5522 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5523 if (!bSecDof) { 5524 continue; 5525 } 5526 if (b >= aStart && b < aEnd) { 5527 ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr); 5528 } 5529 if (bDof) { 5530 /* this point is constrained */ 5531 /* it is going to be replaced by its anchors */ 5532 PetscInt bOff, q; 5533 5534 anyConstrained = PETSC_TRUE; 5535 newNumPoints += bDof; 5536 ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr); 5537 for (q = 0; q < bDof; q++) { 5538 PetscInt a = anchors[bOff + q]; 5539 PetscInt aDof; 5540 5541 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 5542 newNumIndices += aDof; 5543 for (f = 0; f < numFields; ++f) { 5544 PetscInt fDof; 5545 5546 ierr = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr); 5547 newOffsets[f+1] += fDof; 5548 } 5549 } 5550 } 5551 else { 5552 /* this point is not constrained */ 5553 newNumPoints++; 5554 newNumIndices += bSecDof; 5555 for (f = 0; f < numFields; ++f) { 5556 PetscInt fDof; 5557 5558 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5559 newOffsets[f+1] += fDof; 5560 } 5561 } 5562 } 5563 } 5564 if (!anyConstrained) { 5565 if (outNumPoints) *outNumPoints = 0; 5566 if (outNumIndices) *outNumIndices = 0; 5567 if (outPoints) *outPoints = NULL; 5568 if (outValues) *outValues = NULL; 5569 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 5570 PetscFunctionReturn(0); 5571 } 5572 5573 if (outNumPoints) *outNumPoints = newNumPoints; 5574 if (outNumIndices) *outNumIndices = newNumIndices; 5575 5576 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 5577 5578 if (!outPoints && !outValues) { 5579 if (offsets) { 5580 for (f = 0; f <= numFields; f++) { 5581 offsets[f] = newOffsets[f]; 5582 } 5583 } 5584 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 5585 PetscFunctionReturn(0); 5586 } 5587 5588 if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices); 5589 5590 ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr); 5591 5592 /* workspaces */ 5593 if (numFields) { 5594 for (f = 0; f < numFields; f++) { 5595 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 5596 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 5597 } 5598 } 5599 else { 5600 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 5601 ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 5602 } 5603 5604 /* get workspaces for the point-to-point matrices */ 5605 if (numFields) { 5606 PetscInt totalOffset, totalMatOffset; 5607 5608 for (p = 0; p < numPoints; p++) { 5609 PetscInt b = points[2*p]; 5610 PetscInt bDof = 0, bSecDof; 5611 5612 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5613 if (!bSecDof) { 5614 for (f = 0; f < numFields; f++) { 5615 newPointOffsets[f][p + 1] = 0; 5616 pointMatOffsets[f][p + 1] = 0; 5617 } 5618 continue; 5619 } 5620 if (b >= aStart && b < aEnd) { 5621 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5622 } 5623 if (bDof) { 5624 for (f = 0; f < numFields; f++) { 5625 PetscInt fDof, q, bOff, allFDof = 0; 5626 5627 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5628 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5629 for (q = 0; q < bDof; q++) { 5630 PetscInt a = anchors[bOff + q]; 5631 PetscInt aFDof; 5632 5633 ierr = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr); 5634 allFDof += aFDof; 5635 } 5636 newPointOffsets[f][p+1] = allFDof; 5637 pointMatOffsets[f][p+1] = fDof * allFDof; 5638 } 5639 } 5640 else { 5641 for (f = 0; f < numFields; f++) { 5642 PetscInt fDof; 5643 5644 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 5645 newPointOffsets[f][p+1] = fDof; 5646 pointMatOffsets[f][p+1] = 0; 5647 } 5648 } 5649 } 5650 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 5651 newPointOffsets[f][0] = totalOffset; 5652 pointMatOffsets[f][0] = totalMatOffset; 5653 for (p = 0; p < numPoints; p++) { 5654 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 5655 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 5656 } 5657 totalOffset = newPointOffsets[f][numPoints]; 5658 totalMatOffset = pointMatOffsets[f][numPoints]; 5659 ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 5660 } 5661 } 5662 else { 5663 for (p = 0; p < numPoints; p++) { 5664 PetscInt b = points[2*p]; 5665 PetscInt bDof = 0, bSecDof; 5666 5667 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 5668 if (!bSecDof) { 5669 newPointOffsets[0][p + 1] = 0; 5670 pointMatOffsets[0][p + 1] = 0; 5671 continue; 5672 } 5673 if (b >= aStart && b < aEnd) { 5674 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5675 } 5676 if (bDof) { 5677 PetscInt bOff, q, allDof = 0; 5678 5679 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5680 for (q = 0; q < bDof; q++) { 5681 PetscInt a = anchors[bOff + q], aDof; 5682 5683 ierr = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr); 5684 allDof += aDof; 5685 } 5686 newPointOffsets[0][p+1] = allDof; 5687 pointMatOffsets[0][p+1] = bSecDof * allDof; 5688 } 5689 else { 5690 newPointOffsets[0][p+1] = bSecDof; 5691 pointMatOffsets[0][p+1] = 0; 5692 } 5693 } 5694 newPointOffsets[0][0] = 0; 5695 pointMatOffsets[0][0] = 0; 5696 for (p = 0; p < numPoints; p++) { 5697 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 5698 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 5699 } 5700 ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 5701 } 5702 5703 /* output arrays */ 5704 ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 5705 5706 /* get the point-to-point matrices; construct newPoints */ 5707 ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr); 5708 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 5709 ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 5710 ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 5711 if (numFields) { 5712 for (p = 0, newP = 0; p < numPoints; p++) { 5713 PetscInt b = points[2*p]; 5714 PetscInt o = points[2*p+1]; 5715 PetscInt bDof = 0, bSecDof; 5716 5717 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 5718 if (!bSecDof) { 5719 continue; 5720 } 5721 if (b >= aStart && b < aEnd) { 5722 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5723 } 5724 if (bDof) { 5725 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 5726 5727 fStart[0] = 0; 5728 fEnd[0] = 0; 5729 for (f = 0; f < numFields; f++) { 5730 PetscInt fDof; 5731 5732 ierr = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr); 5733 fStart[f+1] = fStart[f] + fDof; 5734 fEnd[f+1] = fStart[f+1]; 5735 } 5736 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 5737 ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr); 5738 5739 fAnchorStart[0] = 0; 5740 fAnchorEnd[0] = 0; 5741 for (f = 0; f < numFields; f++) { 5742 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 5743 5744 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 5745 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 5746 } 5747 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 5748 for (q = 0; q < bDof; q++) { 5749 PetscInt a = anchors[bOff + q], aOff; 5750 5751 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 5752 newPoints[2*(newP + q)] = a; 5753 newPoints[2*(newP + q) + 1] = 0; 5754 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 5755 ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr); 5756 } 5757 newP += bDof; 5758 5759 if (outValues) { 5760 /* get the point-to-point submatrix */ 5761 for (f = 0; f < numFields; f++) { 5762 ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr); 5763 } 5764 } 5765 } 5766 else { 5767 newPoints[2 * newP] = b; 5768 newPoints[2 * newP + 1] = o; 5769 newP++; 5770 } 5771 } 5772 } else { 5773 for (p = 0; p < numPoints; p++) { 5774 PetscInt b = points[2*p]; 5775 PetscInt o = points[2*p+1]; 5776 PetscInt bDof = 0, bSecDof; 5777 5778 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 5779 if (!bSecDof) { 5780 continue; 5781 } 5782 if (b >= aStart && b < aEnd) { 5783 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 5784 } 5785 if (bDof) { 5786 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 5787 5788 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 5789 ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr); 5790 5791 ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr); 5792 for (q = 0; q < bDof; q++) { 5793 PetscInt a = anchors[bOff + q], aOff; 5794 5795 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 5796 5797 newPoints[2*(newP + q)] = a; 5798 newPoints[2*(newP + q) + 1] = 0; 5799 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 5800 ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr); 5801 } 5802 newP += bDof; 5803 5804 /* get the point-to-point submatrix */ 5805 if (outValues) { 5806 ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr); 5807 } 5808 } 5809 else { 5810 newPoints[2 * newP] = b; 5811 newPoints[2 * newP + 1] = o; 5812 newP++; 5813 } 5814 } 5815 } 5816 5817 if (outValues) { 5818 ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 5819 ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr); 5820 /* multiply constraints on the right */ 5821 if (numFields) { 5822 for (f = 0; f < numFields; f++) { 5823 PetscInt oldOff = offsets[f]; 5824 5825 for (p = 0; p < numPoints; p++) { 5826 PetscInt cStart = newPointOffsets[f][p]; 5827 PetscInt b = points[2 * p]; 5828 PetscInt c, r, k; 5829 PetscInt dof; 5830 5831 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 5832 if (!dof) { 5833 continue; 5834 } 5835 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 5836 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 5837 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 5838 5839 for (r = 0; r < numIndices; r++) { 5840 for (c = 0; c < nCols; c++) { 5841 for (k = 0; k < dof; k++) { 5842 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 5843 } 5844 } 5845 } 5846 } 5847 else { 5848 /* copy this column as is */ 5849 for (r = 0; r < numIndices; r++) { 5850 for (c = 0; c < dof; c++) { 5851 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 5852 } 5853 } 5854 } 5855 oldOff += dof; 5856 } 5857 } 5858 } 5859 else { 5860 PetscInt oldOff = 0; 5861 for (p = 0; p < numPoints; p++) { 5862 PetscInt cStart = newPointOffsets[0][p]; 5863 PetscInt b = points[2 * p]; 5864 PetscInt c, r, k; 5865 PetscInt dof; 5866 5867 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 5868 if (!dof) { 5869 continue; 5870 } 5871 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 5872 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 5873 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 5874 5875 for (r = 0; r < numIndices; r++) { 5876 for (c = 0; c < nCols; c++) { 5877 for (k = 0; k < dof; k++) { 5878 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 5879 } 5880 } 5881 } 5882 } 5883 else { 5884 /* copy this column as is */ 5885 for (r = 0; r < numIndices; r++) { 5886 for (c = 0; c < dof; c++) { 5887 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 5888 } 5889 } 5890 } 5891 oldOff += dof; 5892 } 5893 } 5894 5895 if (multiplyLeft) { 5896 ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr); 5897 ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr); 5898 /* multiply constraints transpose on the left */ 5899 if (numFields) { 5900 for (f = 0; f < numFields; f++) { 5901 PetscInt oldOff = offsets[f]; 5902 5903 for (p = 0; p < numPoints; p++) { 5904 PetscInt rStart = newPointOffsets[f][p]; 5905 PetscInt b = points[2 * p]; 5906 PetscInt c, r, k; 5907 PetscInt dof; 5908 5909 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 5910 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 5911 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 5912 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 5913 5914 for (r = 0; r < nRows; r++) { 5915 for (c = 0; c < newNumIndices; c++) { 5916 for (k = 0; k < dof; k++) { 5917 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 5918 } 5919 } 5920 } 5921 } 5922 else { 5923 /* copy this row as is */ 5924 for (r = 0; r < dof; r++) { 5925 for (c = 0; c < newNumIndices; c++) { 5926 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 5927 } 5928 } 5929 } 5930 oldOff += dof; 5931 } 5932 } 5933 } 5934 else { 5935 PetscInt oldOff = 0; 5936 5937 for (p = 0; p < numPoints; p++) { 5938 PetscInt rStart = newPointOffsets[0][p]; 5939 PetscInt b = points[2 * p]; 5940 PetscInt c, r, k; 5941 PetscInt dof; 5942 5943 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 5944 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 5945 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 5946 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 5947 5948 for (r = 0; r < nRows; r++) { 5949 for (c = 0; c < newNumIndices; c++) { 5950 for (k = 0; k < dof; k++) { 5951 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 5952 } 5953 } 5954 } 5955 } 5956 else { 5957 /* copy this row as is */ 5958 for (r = 0; r < dof; r++) { 5959 for (c = 0; c < newNumIndices; c++) { 5960 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 5961 } 5962 } 5963 } 5964 oldOff += dof; 5965 } 5966 } 5967 5968 ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 5969 } 5970 else { 5971 newValues = tmpValues; 5972 } 5973 } 5974 5975 /* clean up */ 5976 ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 5977 ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 5978 5979 if (numFields) { 5980 for (f = 0; f < numFields; f++) { 5981 ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 5982 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 5983 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 5984 } 5985 } 5986 else { 5987 ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 5988 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 5989 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 5990 } 5991 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 5992 5993 /* output */ 5994 if (outPoints) { 5995 *outPoints = newPoints; 5996 } 5997 else { 5998 ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 5999 } 6000 if (outValues) { 6001 *outValues = newValues; 6002 } 6003 for (f = 0; f <= numFields; f++) { 6004 offsets[f] = newOffsets[f]; 6005 } 6006 PetscFunctionReturn(0); 6007 } 6008 6009 /*@C 6010 DMPlexGetClosureIndices - Get the global indices for all local points in the closure of the given point 6011 6012 Not collective 6013 6014 Input Parameters: 6015 + dm - The DM 6016 . section - The section describing the local layout 6017 . globalSection - The section describing the parallel layout 6018 - point - The mesh point 6019 6020 Output parameters: 6021 + numIndices - The number of indices 6022 . indices - The indices 6023 - outOffsets - Field offset if not NULL 6024 6025 Note: Must call DMPlexRestoreClosureIndices() to free allocated memory 6026 6027 Level: advanced 6028 6029 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure() 6030 @*/ 6031 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets) 6032 { 6033 PetscSection clSection; 6034 IS clPoints; 6035 const PetscInt *clp, *clperm; 6036 const PetscInt **perms[32] = {NULL}; 6037 PetscInt *points = NULL, *pointsNew; 6038 PetscInt numPoints, numPointsNew; 6039 PetscInt offsets[32]; 6040 PetscInt Nf, Nind, NindNew, off, globalOff, f, p; 6041 PetscErrorCode ierr; 6042 6043 PetscFunctionBegin; 6044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6045 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6046 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 6047 if (numIndices) PetscValidPointer(numIndices, 4); 6048 PetscValidPointer(indices, 5); 6049 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 6050 if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf); 6051 ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr); 6052 /* Get points in closure */ 6053 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6054 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 6055 /* Get number of indices and indices per field */ 6056 for (p = 0, Nind = 0; p < numPoints*2; p += 2) { 6057 PetscInt dof, fdof; 6058 6059 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 6060 for (f = 0; f < Nf; ++f) { 6061 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6062 offsets[f+1] += fdof; 6063 } 6064 Nind += dof; 6065 } 6066 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 6067 if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Nind); 6068 if (!Nf) offsets[1] = Nind; 6069 /* Get dual space symmetries */ 6070 for (f = 0; f < PetscMax(1,Nf); f++) { 6071 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6072 else {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6073 } 6074 /* Correct for hanging node constraints */ 6075 { 6076 ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, perms, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr); 6077 if (numPointsNew) { 6078 for (f = 0; f < PetscMax(1,Nf); f++) { 6079 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6080 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6081 } 6082 for (f = 0; f < PetscMax(1,Nf); f++) { 6083 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section,f,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);} 6084 else {ierr = PetscSectionGetPointSyms(section,numPointsNew,pointsNew,&perms[f],NULL);CHKERRQ(ierr);} 6085 } 6086 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6087 numPoints = numPointsNew; 6088 Nind = NindNew; 6089 points = pointsNew; 6090 } 6091 } 6092 /* Calculate indices */ 6093 ierr = DMGetWorkArray(dm, Nind, MPIU_INT, indices);CHKERRQ(ierr); 6094 if (Nf) { 6095 if (outOffsets) { 6096 PetscInt f; 6097 6098 for (f = 0; f <= Nf; f++) { 6099 outOffsets[f] = offsets[f]; 6100 } 6101 } 6102 for (p = 0; p < numPoints; p++) { 6103 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6104 ierr = DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, *indices);CHKERRQ(ierr); 6105 } 6106 } else { 6107 for (p = 0, off = 0; p < numPoints; p++) { 6108 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 6109 6110 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6111 ierr = DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, *indices);CHKERRQ(ierr); 6112 } 6113 } 6114 /* Cleanup points */ 6115 for (f = 0; f < PetscMax(1,Nf); f++) { 6116 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6117 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],NULL);CHKERRQ(ierr);} 6118 } 6119 if (numPointsNew) { 6120 ierr = DMRestoreWorkArray(dm, 2*numPointsNew, MPIU_INT, &pointsNew);CHKERRQ(ierr); 6121 } else { 6122 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6123 } 6124 if (numIndices) *numIndices = Nind; 6125 PetscFunctionReturn(0); 6126 } 6127 6128 /*@C 6129 DMPlexRestoreClosureIndices - Restore the indices in a vector v for all points in the closure of the given point 6130 6131 Not collective 6132 6133 Input Parameters: 6134 + dm - The DM 6135 . section - The section describing the layout in v, or NULL to use the default section 6136 . globalSection - The section describing the parallel layout in v, or NULL to use the default section 6137 . point - The mesh point 6138 . numIndices - The number of indices 6139 . indices - The indices 6140 - outOffsets - Field offset if not NULL 6141 6142 Level: advanced 6143 6144 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure() 6145 @*/ 6146 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets) 6147 { 6148 PetscErrorCode ierr; 6149 6150 PetscFunctionBegin; 6151 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6152 PetscValidPointer(indices, 5); 6153 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr); 6154 PetscFunctionReturn(0); 6155 } 6156 6157 /*@C 6158 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 6159 6160 Not collective 6161 6162 Input Parameters: 6163 + dm - The DM 6164 . section - The section describing the layout in v, or NULL to use the default section 6165 . globalSection - The section describing the layout in v, or NULL to use the default global section 6166 . A - The matrix 6167 . point - The point in the DM 6168 . values - The array of values 6169 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 6170 6171 Fortran Notes: 6172 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 6173 6174 Level: intermediate 6175 6176 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure() 6177 @*/ 6178 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 6179 { 6180 DM_Plex *mesh = (DM_Plex*) dm->data; 6181 PetscSection clSection; 6182 IS clPoints; 6183 PetscInt *points = NULL, *newPoints; 6184 const PetscInt *clp, *clperm; 6185 PetscInt *indices; 6186 PetscInt offsets[32]; 6187 const PetscInt **perms[32] = {NULL}; 6188 const PetscScalar **flips[32] = {NULL}; 6189 PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f; 6190 PetscScalar *valCopy = NULL; 6191 PetscScalar *newValues; 6192 PetscErrorCode ierr; 6193 6194 PetscFunctionBegin; 6195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6196 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 6197 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6198 if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 6199 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 6200 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 6201 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6202 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6203 ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr); 6204 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &clperm);CHKERRQ(ierr); 6205 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6206 for (p = 0, numIndices = 0; p < numPoints*2; p += 2) { 6207 PetscInt fdof; 6208 6209 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 6210 for (f = 0; f < numFields; ++f) { 6211 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6212 offsets[f+1] += fdof; 6213 } 6214 numIndices += dof; 6215 } 6216 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 6217 6218 if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[numFields], numIndices); 6219 /* Get symmetries */ 6220 for (f = 0; f < PetscMax(1,numFields); f++) { 6221 if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6222 else {ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6223 if (values && flips[f]) { /* may need to apply sign changes to the element matrix */ 6224 PetscInt foffset = offsets[f]; 6225 6226 for (p = 0; p < numPoints; p++) { 6227 PetscInt point = points[2*p], fdof; 6228 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 6229 6230 if (!numFields) { 6231 ierr = PetscSectionGetDof(section,point,&fdof);CHKERRQ(ierr); 6232 } else { 6233 ierr = PetscSectionGetFieldDof(section,point,f,&fdof);CHKERRQ(ierr); 6234 } 6235 if (flip) { 6236 PetscInt i, j, k; 6237 6238 if (!valCopy) { 6239 ierr = DMGetWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6240 for (j = 0; j < numIndices * numIndices; j++) valCopy[j] = values[j]; 6241 values = valCopy; 6242 } 6243 for (i = 0; i < fdof; i++) { 6244 PetscScalar fval = flip[i]; 6245 6246 for (k = 0; k < numIndices; k++) { 6247 valCopy[numIndices * (foffset + i) + k] *= fval; 6248 valCopy[numIndices * k + (foffset + i)] *= fval; 6249 } 6250 } 6251 } 6252 foffset += fdof; 6253 } 6254 } 6255 } 6256 ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,perms,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr); 6257 if (newNumPoints) { 6258 if (valCopy) { 6259 ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6260 } 6261 for (f = 0; f < PetscMax(1,numFields); f++) { 6262 if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6263 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6264 } 6265 for (f = 0; f < PetscMax(1,numFields); f++) { 6266 if (numFields) {ierr = PetscSectionGetFieldPointSyms(section,f,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);} 6267 else {ierr = PetscSectionGetPointSyms(section,newNumPoints,newPoints,&perms[f],&flips[f]);CHKERRQ(ierr);} 6268 } 6269 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6270 numPoints = newNumPoints; 6271 numIndices = newNumIndices; 6272 points = newPoints; 6273 values = newValues; 6274 } 6275 ierr = DMGetWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr); 6276 if (numFields) { 6277 PetscBool useFieldOffsets; 6278 6279 ierr = PetscSectionGetUseFieldOffsets(globalSection, &useFieldOffsets);CHKERRQ(ierr); 6280 if (useFieldOffsets) { 6281 for (p = 0; p < numPoints; p++) { 6282 DMPlexGetIndicesPointFieldsSplit_Internal(section, globalSection, points[2*p], offsets, PETSC_FALSE, perms, p, clperm, indices); 6283 } 6284 } else { 6285 for (p = 0; p < numPoints; p++) { 6286 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6287 DMPlexGetIndicesPointFields_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, perms, p, clperm, indices); 6288 } 6289 } 6290 } else { 6291 for (p = 0, off = 0; p < numPoints; p++) { 6292 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 6293 ierr = PetscSectionGetOffset(globalSection, points[2*p], &globalOff);CHKERRQ(ierr); 6294 DMPlexGetIndicesPoint_Internal(section, points[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, clperm, indices); 6295 } 6296 } 6297 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);} 6298 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 6299 if (mesh->printFEM > 1) { 6300 PetscInt i; 6301 ierr = PetscPrintf(PETSC_COMM_SELF, " Indices:");CHKERRQ(ierr); 6302 for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);} 6303 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 6304 } 6305 if (ierr) { 6306 PetscMPIInt rank; 6307 PetscErrorCode ierr2; 6308 6309 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 6310 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 6311 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2); 6312 ierr2 = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr2); 6313 CHKERRQ(ierr); 6314 } 6315 for (f = 0; f < PetscMax(1,numFields); f++) { 6316 if (numFields) {ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6317 else {ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms[f],&flips[f]);CHKERRQ(ierr);} 6318 } 6319 if (newNumPoints) { 6320 ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr); 6321 ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 6322 } 6323 else { 6324 if (valCopy) { 6325 ierr = DMRestoreWorkArray(dm,numIndices*numIndices,MPIU_SCALAR,&valCopy);CHKERRQ(ierr); 6326 } 6327 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6328 } 6329 ierr = DMRestoreWorkArray(dm, numIndices, MPIU_INT, &indices);CHKERRQ(ierr); 6330 PetscFunctionReturn(0); 6331 } 6332 6333 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 6334 { 6335 DM_Plex *mesh = (DM_Plex*) dmf->data; 6336 PetscInt *fpoints = NULL, *ftotpoints = NULL; 6337 PetscInt *cpoints = NULL; 6338 PetscInt *findices, *cindices; 6339 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 6340 PetscInt foffsets[32], coffsets[32]; 6341 CellRefiner cellRefiner; 6342 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 6343 PetscErrorCode ierr; 6344 6345 PetscFunctionBegin; 6346 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 6347 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 6348 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 6349 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 6350 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 6351 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 6352 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 6353 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 6354 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 6355 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 6356 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 6357 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 6358 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6359 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 6360 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 6361 /* Column indices */ 6362 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6363 maxFPoints = numCPoints; 6364 /* Compress out points not in the section */ 6365 /* TODO: Squeeze out points with 0 dof as well */ 6366 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 6367 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 6368 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 6369 cpoints[q*2] = cpoints[p]; 6370 cpoints[q*2+1] = cpoints[p+1]; 6371 ++q; 6372 } 6373 } 6374 numCPoints = q; 6375 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 6376 PetscInt fdof; 6377 6378 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 6379 if (!dof) continue; 6380 for (f = 0; f < numFields; ++f) { 6381 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 6382 coffsets[f+1] += fdof; 6383 } 6384 numCIndices += dof; 6385 } 6386 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 6387 /* Row indices */ 6388 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 6389 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 6390 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6391 for (r = 0, q = 0; r < numSubcells; ++r) { 6392 /* TODO Map from coarse to fine cells */ 6393 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6394 /* Compress out points not in the section */ 6395 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 6396 for (p = 0; p < numFPoints*2; p += 2) { 6397 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 6398 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 6399 if (!dof) continue; 6400 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 6401 if (s < q) continue; 6402 ftotpoints[q*2] = fpoints[p]; 6403 ftotpoints[q*2+1] = fpoints[p+1]; 6404 ++q; 6405 } 6406 } 6407 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6408 } 6409 numFPoints = q; 6410 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 6411 PetscInt fdof; 6412 6413 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 6414 if (!dof) continue; 6415 for (f = 0; f < numFields; ++f) { 6416 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 6417 foffsets[f+1] += fdof; 6418 } 6419 numFIndices += dof; 6420 } 6421 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 6422 6423 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 6424 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 6425 ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 6426 ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 6427 if (numFields) { 6428 const PetscInt **permsF[32] = {NULL}; 6429 const PetscInt **permsC[32] = {NULL}; 6430 6431 for (f = 0; f < numFields; f++) { 6432 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6433 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6434 } 6435 for (p = 0; p < numFPoints; p++) { 6436 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6437 ierr = DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr); 6438 } 6439 for (p = 0; p < numCPoints; p++) { 6440 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6441 ierr = DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr); 6442 } 6443 for (f = 0; f < numFields; f++) { 6444 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6445 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6446 } 6447 } else { 6448 const PetscInt **permsF = NULL; 6449 const PetscInt **permsC = NULL; 6450 6451 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6452 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6453 for (p = 0, off = 0; p < numFPoints; p++) { 6454 const PetscInt *perm = permsF ? permsF[p] : NULL; 6455 6456 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6457 ierr = DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr); 6458 } 6459 for (p = 0, off = 0; p < numCPoints; p++) { 6460 const PetscInt *perm = permsC ? permsC[p] : NULL; 6461 6462 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6463 ierr = DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr); 6464 } 6465 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6466 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6467 } 6468 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);} 6469 /* TODO: flips */ 6470 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 6471 if (ierr) { 6472 PetscMPIInt rank; 6473 PetscErrorCode ierr2; 6474 6475 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 6476 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 6477 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2); 6478 ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2); 6479 ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2); 6480 CHKERRQ(ierr); 6481 } 6482 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6483 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6484 ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 6485 ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 6486 PetscFunctionReturn(0); 6487 } 6488 6489 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 6490 { 6491 PetscInt *fpoints = NULL, *ftotpoints = NULL; 6492 PetscInt *cpoints = NULL; 6493 PetscInt foffsets[32], coffsets[32]; 6494 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 6495 CellRefiner cellRefiner; 6496 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 6497 PetscErrorCode ierr; 6498 6499 PetscFunctionBegin; 6500 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 6501 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 6502 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 6503 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 6504 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 6505 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 6506 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 6507 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 6508 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 6509 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 6510 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 6511 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 6512 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 6513 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 6514 /* Column indices */ 6515 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6516 maxFPoints = numCPoints; 6517 /* Compress out points not in the section */ 6518 /* TODO: Squeeze out points with 0 dof as well */ 6519 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 6520 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 6521 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 6522 cpoints[q*2] = cpoints[p]; 6523 cpoints[q*2+1] = cpoints[p+1]; 6524 ++q; 6525 } 6526 } 6527 numCPoints = q; 6528 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 6529 PetscInt fdof; 6530 6531 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 6532 if (!dof) continue; 6533 for (f = 0; f < numFields; ++f) { 6534 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 6535 coffsets[f+1] += fdof; 6536 } 6537 numCIndices += dof; 6538 } 6539 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 6540 /* Row indices */ 6541 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 6542 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 6543 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6544 for (r = 0, q = 0; r < numSubcells; ++r) { 6545 /* TODO Map from coarse to fine cells */ 6546 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6547 /* Compress out points not in the section */ 6548 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 6549 for (p = 0; p < numFPoints*2; p += 2) { 6550 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 6551 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 6552 if (!dof) continue; 6553 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 6554 if (s < q) continue; 6555 ftotpoints[q*2] = fpoints[p]; 6556 ftotpoints[q*2+1] = fpoints[p+1]; 6557 ++q; 6558 } 6559 } 6560 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 6561 } 6562 numFPoints = q; 6563 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 6564 PetscInt fdof; 6565 6566 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 6567 if (!dof) continue; 6568 for (f = 0; f < numFields; ++f) { 6569 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 6570 foffsets[f+1] += fdof; 6571 } 6572 numFIndices += dof; 6573 } 6574 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 6575 6576 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 6577 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 6578 if (numFields) { 6579 const PetscInt **permsF[32] = {NULL}; 6580 const PetscInt **permsC[32] = {NULL}; 6581 6582 for (f = 0; f < numFields; f++) { 6583 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6584 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6585 } 6586 for (p = 0; p < numFPoints; p++) { 6587 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6588 DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices); 6589 } 6590 for (p = 0; p < numCPoints; p++) { 6591 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6592 DMPlexGetIndicesPointFields_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices); 6593 } 6594 for (f = 0; f < numFields; f++) { 6595 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 6596 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 6597 } 6598 } else { 6599 const PetscInt **permsF = NULL; 6600 const PetscInt **permsC = NULL; 6601 6602 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6603 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6604 for (p = 0, off = 0; p < numFPoints; p++) { 6605 const PetscInt *perm = permsF ? permsF[p] : NULL; 6606 6607 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 6608 DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices); 6609 } 6610 for (p = 0, off = 0; p < numCPoints; p++) { 6611 const PetscInt *perm = permsC ? permsC[p] : NULL; 6612 6613 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 6614 DMPlexGetIndicesPoint_Internal(csection, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices); 6615 } 6616 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 6617 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 6618 } 6619 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 6620 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 6621 PetscFunctionReturn(0); 6622 } 6623 6624 /*@ 6625 DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid 6626 6627 Input Parameter: 6628 . dm - The DMPlex object 6629 6630 Output Parameters: 6631 + cMax - The first hybrid cell 6632 . fMax - The first hybrid face 6633 . eMax - The first hybrid edge 6634 - vMax - The first hybrid vertex 6635 6636 Level: developer 6637 6638 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds() 6639 @*/ 6640 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax) 6641 { 6642 DM_Plex *mesh = (DM_Plex*) dm->data; 6643 PetscInt dim; 6644 PetscErrorCode ierr; 6645 6646 PetscFunctionBegin; 6647 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6648 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6649 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6650 if (cMax) *cMax = mesh->hybridPointMax[dim]; 6651 if (fMax) *fMax = mesh->hybridPointMax[PetscMax(dim-1,0)]; 6652 if (eMax) *eMax = mesh->hybridPointMax[1]; 6653 if (vMax) *vMax = mesh->hybridPointMax[0]; 6654 PetscFunctionReturn(0); 6655 } 6656 6657 static PetscErrorCode DMPlexCreateDimStratum(DM dm, DMLabel depthLabel, DMLabel dimLabel, PetscInt d, PetscInt dMax) 6658 { 6659 IS is, his; 6660 PetscInt first = 0, stride; 6661 PetscBool isStride; 6662 PetscErrorCode ierr; 6663 6664 PetscFunctionBegin; 6665 ierr = DMLabelGetStratumIS(depthLabel, d, &is);CHKERRQ(ierr); 6666 ierr = PetscObjectTypeCompare((PetscObject) is, ISSTRIDE, &isStride);CHKERRQ(ierr); 6667 if (isStride) {ierr = ISStrideGetInfo(is, &first, &stride);CHKERRQ(ierr);} 6668 if (is && (!isStride || stride != 1)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM is not stratified: depth %D IS is not contiguous", d); 6669 ierr = ISCreateStride(PETSC_COMM_SELF, (dMax - first), first, 1, &his);CHKERRQ(ierr); 6670 ierr = DMLabelSetStratumIS(dimLabel, d, his);CHKERRQ(ierr); 6671 ierr = ISDestroy(&his);CHKERRQ(ierr); 6672 ierr = ISDestroy(&is);CHKERRQ(ierr); 6673 PetscFunctionReturn(0); 6674 } 6675 6676 /*@ 6677 DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid 6678 6679 Input Parameters: 6680 + dm - The DMPlex object 6681 . cMax - The first hybrid cell 6682 . fMax - The first hybrid face 6683 . eMax - The first hybrid edge 6684 - vMax - The first hybrid vertex 6685 6686 Level: developer 6687 6688 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds() 6689 @*/ 6690 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax) 6691 { 6692 DM_Plex *mesh = (DM_Plex*) dm->data; 6693 PetscInt dim; 6694 PetscErrorCode ierr; 6695 6696 PetscFunctionBegin; 6697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6698 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6699 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6700 if (cMax >= 0) mesh->hybridPointMax[dim] = cMax; 6701 if (fMax >= 0) mesh->hybridPointMax[PetscMax(dim-1,0)] = fMax; 6702 if (eMax >= 0) mesh->hybridPointMax[1] = eMax; 6703 if (vMax >= 0) mesh->hybridPointMax[0] = vMax; 6704 PetscFunctionReturn(0); 6705 } 6706 6707 /*@C 6708 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 6709 6710 Input Parameter: 6711 . dm - The DMPlex object 6712 6713 Output Parameter: 6714 . cellHeight - The height of a cell 6715 6716 Level: developer 6717 6718 .seealso DMPlexSetVTKCellHeight() 6719 @*/ 6720 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 6721 { 6722 DM_Plex *mesh = (DM_Plex*) dm->data; 6723 6724 PetscFunctionBegin; 6725 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6726 PetscValidPointer(cellHeight, 2); 6727 *cellHeight = mesh->vtkCellHeight; 6728 PetscFunctionReturn(0); 6729 } 6730 6731 /*@C 6732 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 6733 6734 Input Parameters: 6735 + dm - The DMPlex object 6736 - cellHeight - The height of a cell 6737 6738 Level: developer 6739 6740 .seealso DMPlexGetVTKCellHeight() 6741 @*/ 6742 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 6743 { 6744 DM_Plex *mesh = (DM_Plex*) dm->data; 6745 6746 PetscFunctionBegin; 6747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6748 mesh->vtkCellHeight = cellHeight; 6749 PetscFunctionReturn(0); 6750 } 6751 6752 /*@ 6753 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 6754 6755 Input Parameter: 6756 . dm - The DMPlex object 6757 6758 Output Parameters: 6759 + gcStart - The first ghost cell, or NULL 6760 - gcEnd - The upper bound on ghost cells, or NULL 6761 6762 Level: advanced 6763 6764 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds() 6765 @*/ 6766 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 6767 { 6768 DM_Plex *mesh = (DM_Plex*) dm->data; 6769 PetscInt dim; 6770 PetscErrorCode ierr; 6771 6772 PetscFunctionBegin; 6773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6774 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6775 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6776 if (gcStart) {PetscValidIntPointer(gcStart, 2); *gcStart = mesh->ghostCellStart;} 6777 if (gcEnd) { 6778 PetscValidIntPointer(gcEnd, 3); 6779 if (mesh->ghostCellStart >= 0) {ierr = DMPlexGetHeightStratum(dm, 0, NULL, gcEnd);CHKERRQ(ierr);} 6780 else {*gcEnd = -1;} 6781 } 6782 PetscFunctionReturn(0); 6783 } 6784 6785 /*@ 6786 DMPlexSetGhostCellStratum - Set the range of cells which are used to enforce FV boundary conditions 6787 6788 Input Parameters: 6789 + dm - The DMPlex object 6790 . gcStart - The first ghost cell, or PETSC_DETERMINE 6791 - gcEnd - The upper bound on ghost cells, or PETSC_DETERMINE 6792 6793 Level: advanced 6794 6795 Note: This is not usually called directly by a user. 6796 6797 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum(), DMPlexSetHybridBounds() 6798 @*/ 6799 PetscErrorCode DMPlexSetGhostCellStratum(DM dm, PetscInt gcStart, PetscInt gcEnd) 6800 { 6801 DM_Plex *mesh = (DM_Plex*) dm->data; 6802 PetscInt dim; 6803 PetscErrorCode ierr; 6804 6805 PetscFunctionBegin; 6806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6807 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 6808 if (dim < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM dimension not yet set"); 6809 mesh->ghostCellStart = gcStart; 6810 if (gcEnd >= 0) { 6811 PetscInt cEnd; 6812 ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr); 6813 if (gcEnd != cEnd) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Ghost cells must appear at the end of the cell range, but gcEnd %D is not equal to cEnd %D", gcEnd, cEnd); 6814 } 6815 PetscFunctionReturn(0); 6816 } 6817 6818 /*@ 6819 DMPlexGetInteriorCellStratum - Get the range of cells which are neither hybrid nor ghost FV cells 6820 6821 Input Parameter: 6822 . dm - The DMPlex object 6823 6824 Output Parameters: 6825 + cStartInterior - The first ghost cell 6826 - cEndInterior - The upper bound on ghost cells 6827 6828 Level: developer 6829 6830 .seealso DMPlexConstructGhostCells(), DMPlexSetGhostCellStratum(), DMPlexGetHybridBounds() 6831 @*/ 6832 PetscErrorCode DMPlexGetInteriorCellStratum(DM dm, PetscInt *cStartInterior, PetscInt *cEndInterior) 6833 { 6834 PetscInt gcEnd, cMax; 6835 PetscErrorCode ierr; 6836 6837 PetscFunctionBegin; 6838 ierr = DMPlexGetHeightStratum(dm, 0, cStartInterior, cEndInterior);CHKERRQ(ierr); 6839 ierr = DMPlexGetGhostCellStratum(dm, &gcEnd, NULL);CHKERRQ(ierr); 6840 *cEndInterior = gcEnd < 0 ? *cEndInterior : gcEnd; 6841 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 6842 *cEndInterior = cMax < 0 ? *cEndInterior : cMax; 6843 PetscFunctionReturn(0); 6844 } 6845 6846 /* We can easily have a form that takes an IS instead */ 6847 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 6848 { 6849 PetscSection section, globalSection; 6850 PetscInt *numbers, p; 6851 PetscErrorCode ierr; 6852 6853 PetscFunctionBegin; 6854 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 6855 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 6856 for (p = pStart; p < pEnd; ++p) { 6857 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 6858 } 6859 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 6860 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 6861 ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr); 6862 for (p = pStart; p < pEnd; ++p) { 6863 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 6864 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 6865 else numbers[p-pStart] += shift; 6866 } 6867 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 6868 if (globalSize) { 6869 PetscLayout layout; 6870 ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr); 6871 ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr); 6872 ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr); 6873 } 6874 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 6875 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 6876 PetscFunctionReturn(0); 6877 } 6878 6879 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 6880 { 6881 PetscInt cellHeight, cStart, cEnd, cMax; 6882 PetscErrorCode ierr; 6883 6884 PetscFunctionBegin; 6885 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 6886 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 6887 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 6888 if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax); 6889 ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr); 6890 PetscFunctionReturn(0); 6891 } 6892 6893 /*@ 6894 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 6895 6896 Input Parameter: 6897 . dm - The DMPlex object 6898 6899 Output Parameter: 6900 . globalCellNumbers - Global cell numbers for all cells on this process 6901 6902 Level: developer 6903 6904 .seealso DMPlexGetVertexNumbering() 6905 @*/ 6906 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 6907 { 6908 DM_Plex *mesh = (DM_Plex*) dm->data; 6909 PetscErrorCode ierr; 6910 6911 PetscFunctionBegin; 6912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6913 if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);} 6914 *globalCellNumbers = mesh->globalCellNumbers; 6915 PetscFunctionReturn(0); 6916 } 6917 6918 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 6919 { 6920 PetscInt vStart, vEnd, vMax; 6921 PetscErrorCode ierr; 6922 6923 PetscFunctionBegin; 6924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6925 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 6926 ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); 6927 if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax); 6928 ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr); 6929 PetscFunctionReturn(0); 6930 } 6931 6932 /*@ 6933 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 6934 6935 Input Parameter: 6936 . dm - The DMPlex object 6937 6938 Output Parameter: 6939 . globalVertexNumbers - Global vertex numbers for all vertices on this process 6940 6941 Level: developer 6942 6943 .seealso DMPlexGetCellNumbering() 6944 @*/ 6945 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 6946 { 6947 DM_Plex *mesh = (DM_Plex*) dm->data; 6948 PetscErrorCode ierr; 6949 6950 PetscFunctionBegin; 6951 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6952 if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);} 6953 *globalVertexNumbers = mesh->globalVertexNumbers; 6954 PetscFunctionReturn(0); 6955 } 6956 6957 /*@ 6958 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 6959 6960 Input Parameter: 6961 . dm - The DMPlex object 6962 6963 Output Parameter: 6964 . globalPointNumbers - Global numbers for all points on this process 6965 6966 Level: developer 6967 6968 .seealso DMPlexGetCellNumbering() 6969 @*/ 6970 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 6971 { 6972 IS nums[4]; 6973 PetscInt depths[4], gdepths[4], starts[4]; 6974 PetscInt depth, d, shift = 0; 6975 PetscErrorCode ierr; 6976 6977 PetscFunctionBegin; 6978 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6979 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 6980 /* For unstratified meshes use dim instead of depth */ 6981 if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);} 6982 for (d = 0; d <= depth; ++d) { 6983 PetscInt end; 6984 6985 depths[d] = depth-d; 6986 ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr); 6987 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 6988 } 6989 ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr); 6990 ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr); 6991 for (d = 0; d <= depth; ++d) { 6992 if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]); 6993 } 6994 for (d = 0; d <= depth; ++d) { 6995 PetscInt pStart, pEnd, gsize; 6996 6997 ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr); 6998 ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr); 6999 shift += gsize; 7000 } 7001 ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr); 7002 for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);} 7003 PetscFunctionReturn(0); 7004 } 7005 7006 7007 /*@ 7008 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 7009 7010 Input Parameter: 7011 . dm - The DMPlex object 7012 7013 Output Parameter: 7014 . ranks - The rank field 7015 7016 Options Database Keys: 7017 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 7018 7019 Level: intermediate 7020 7021 .seealso: DMView() 7022 @*/ 7023 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 7024 { 7025 DM rdm; 7026 PetscFE fe; 7027 PetscScalar *r; 7028 PetscMPIInt rank; 7029 PetscInt dim, cStart, cEnd, c; 7030 PetscErrorCode ierr; 7031 7032 PetscFunctionBeginUser; 7033 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7034 PetscValidPointer(ranks, 2); 7035 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 7036 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7037 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7038 ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___rank_", -1, &fe);CHKERRQ(ierr); 7039 ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr); 7040 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7041 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7042 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7043 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7044 ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr); 7045 ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr); 7046 ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr); 7047 for (c = cStart; c < cEnd; ++c) { 7048 PetscScalar *lr; 7049 7050 ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr); 7051 *lr = rank; 7052 } 7053 ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr); 7054 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7055 PetscFunctionReturn(0); 7056 } 7057 7058 /*@ 7059 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 7060 7061 Input Parameters: 7062 + dm - The DMPlex 7063 - label - The DMLabel 7064 7065 Output Parameter: 7066 . val - The label value field 7067 7068 Options Database Keys: 7069 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 7070 7071 Level: intermediate 7072 7073 .seealso: DMView() 7074 @*/ 7075 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 7076 { 7077 DM rdm; 7078 PetscFE fe; 7079 PetscScalar *v; 7080 PetscInt dim, cStart, cEnd, c; 7081 PetscErrorCode ierr; 7082 7083 PetscFunctionBeginUser; 7084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7085 PetscValidPointer(label, 2); 7086 PetscValidPointer(val, 3); 7087 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7088 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7089 ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr); 7090 ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr); 7091 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7092 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7093 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7094 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7095 ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr); 7096 ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr); 7097 ierr = VecGetArray(*val, &v);CHKERRQ(ierr); 7098 for (c = cStart; c < cEnd; ++c) { 7099 PetscScalar *lv; 7100 PetscInt cval; 7101 7102 ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr); 7103 ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr); 7104 *lv = cval; 7105 } 7106 ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr); 7107 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7108 PetscFunctionReturn(0); 7109 } 7110 7111 /*@ 7112 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 7113 7114 Input Parameter: 7115 . dm - The DMPlex object 7116 7117 Notes: 7118 This is a useful diagnostic when creating meshes programmatically. 7119 7120 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7121 7122 Level: developer 7123 7124 .seealso: DMCreate(), DMSetFromOptions() 7125 @*/ 7126 PetscErrorCode DMPlexCheckSymmetry(DM dm) 7127 { 7128 PetscSection coneSection, supportSection; 7129 const PetscInt *cone, *support; 7130 PetscInt coneSize, c, supportSize, s; 7131 PetscInt pStart, pEnd, p, pp, csize, ssize; 7132 PetscBool storagecheck = PETSC_TRUE; 7133 PetscErrorCode ierr; 7134 7135 PetscFunctionBegin; 7136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7137 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 7138 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 7139 /* Check that point p is found in the support of its cone points, and vice versa */ 7140 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 7141 for (p = pStart; p < pEnd; ++p) { 7142 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 7143 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 7144 for (c = 0; c < coneSize; ++c) { 7145 PetscBool dup = PETSC_FALSE; 7146 PetscInt d; 7147 for (d = c-1; d >= 0; --d) { 7148 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 7149 } 7150 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 7151 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 7152 for (s = 0; s < supportSize; ++s) { 7153 if (support[s] == p) break; 7154 } 7155 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 7156 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr); 7157 for (s = 0; s < coneSize; ++s) { 7158 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr); 7159 } 7160 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7161 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr); 7162 for (s = 0; s < supportSize; ++s) { 7163 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr); 7164 } 7165 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7166 if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]); 7167 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]); 7168 } 7169 } 7170 ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr); 7171 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 7172 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 7173 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 7174 for (s = 0; s < supportSize; ++s) { 7175 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 7176 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 7177 for (c = 0; c < coneSize; ++c) { 7178 ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr); 7179 if (cone[c] != pp) { c = 0; break; } 7180 if (cone[c] == p) break; 7181 } 7182 if (c >= coneSize) { 7183 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr); 7184 for (c = 0; c < supportSize; ++c) { 7185 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr); 7186 } 7187 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7188 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr); 7189 for (c = 0; c < coneSize; ++c) { 7190 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr); 7191 } 7192 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7193 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]); 7194 } 7195 } 7196 } 7197 if (storagecheck) { 7198 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 7199 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 7200 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize); 7201 } 7202 PetscFunctionReturn(0); 7203 } 7204 7205 /*@ 7206 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 7207 7208 Input Parameters: 7209 + dm - The DMPlex object 7210 - cellHeight - Normally 0 7211 7212 Notes: 7213 This is a useful diagnostic when creating meshes programmatically. 7214 Currently applicable only to homogeneous simplex or tensor meshes. 7215 7216 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7217 7218 Level: developer 7219 7220 .seealso: DMCreate(), DMSetFromOptions() 7221 @*/ 7222 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 7223 { 7224 PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c; 7225 PetscBool isSimplex = PETSC_FALSE; 7226 PetscErrorCode ierr; 7227 7228 PetscFunctionBegin; 7229 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7230 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7231 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 7232 if (cStart < cEnd) { 7233 ierr = DMPlexGetConeSize(dm, cStart, &c);CHKERRQ(ierr); 7234 isSimplex = c == dim+1 ? PETSC_TRUE : PETSC_FALSE; 7235 } 7236 switch (dim) { 7237 case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break; 7238 case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break; 7239 case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break; 7240 default: 7241 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %D", dim); 7242 } 7243 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7244 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 7245 cMax = cMax >= 0 ? cMax : cEnd; 7246 for (c = cStart; c < cMax; ++c) { 7247 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 7248 7249 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7250 for (cl = 0; cl < closureSize*2; cl += 2) { 7251 const PetscInt p = closure[cl]; 7252 if ((p >= vStart) && (p < vEnd)) ++coneSize; 7253 } 7254 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7255 if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D vertices != %D", c, coneSize, numCorners); 7256 } 7257 for (c = cMax; c < cEnd; ++c) { 7258 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 7259 7260 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7261 for (cl = 0; cl < closureSize*2; cl += 2) { 7262 const PetscInt p = closure[cl]; 7263 if ((p >= vStart) && (p < vEnd)) ++coneSize; 7264 } 7265 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7266 if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %D has %D vertices > %D", c, coneSize, numHybridCorners); 7267 } 7268 PetscFunctionReturn(0); 7269 } 7270 7271 /*@ 7272 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 7273 7274 Not Collective 7275 7276 Input Parameters: 7277 + dm - The DMPlex object 7278 - cellHeight - Normally 0 7279 7280 Notes: 7281 This is a useful diagnostic when creating meshes programmatically. 7282 This routine is only relevant for meshes that are fully interpolated across all ranks. 7283 It will error out if a partially interpolated mesh is given on some rank. 7284 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 7285 7286 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7287 7288 Level: developer 7289 7290 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 7291 @*/ 7292 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 7293 { 7294 PetscInt pMax[4]; 7295 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 7296 PetscErrorCode ierr; 7297 DMPlexInterpolatedFlag interpEnum; 7298 7299 PetscFunctionBegin; 7300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7301 ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr); 7302 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 7303 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 7304 PetscMPIInt rank; 7305 MPI_Comm comm; 7306 7307 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 7308 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 7309 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 7310 } 7311 7312 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7313 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7314 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7315 ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr); 7316 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 7317 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 7318 for (c = cStart; c < cEnd; ++c) { 7319 const PetscInt *cone, *ornt, *faces; 7320 DMPolytopeType ct; 7321 PetscInt numFaces, faceSize, coneSize,f; 7322 PetscInt *closure = NULL, closureSize, cl, numCorners = 0; 7323 7324 if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue; 7325 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 7326 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 7327 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 7328 ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr); 7329 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7330 for (cl = 0; cl < closureSize*2; cl += 2) { 7331 const PetscInt p = closure[cl]; 7332 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 7333 } 7334 ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 7335 if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has %D faces but should have %D", c, coneSize, numFaces); 7336 for (f = 0; f < numFaces; ++f) { 7337 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 7338 7339 ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 7340 for (cl = 0; cl < fclosureSize*2; cl += 2) { 7341 const PetscInt p = fclosure[cl]; 7342 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 7343 } 7344 if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D (%D) of cell %D has %D vertices but should have %D", cone[f], f, c, fnumCorners, faceSize); 7345 for (v = 0; v < fnumCorners; ++v) { 7346 if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D (%d) of cell %D vertex %D, %D != %D", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]); 7347 } 7348 ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 7349 } 7350 ierr = DMPlexRestoreFaces_Internal(dm, ct, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 7351 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 7352 } 7353 } 7354 PetscFunctionReturn(0); 7355 } 7356 7357 /*@ 7358 DMPlexCheckGeometry - Check the geometry of mesh cells 7359 7360 Input Parameter: 7361 . dm - The DMPlex object 7362 7363 Notes: 7364 This is a useful diagnostic when creating meshes programmatically. 7365 7366 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7367 7368 Level: developer 7369 7370 .seealso: DMCreate(), DMSetFromOptions() 7371 @*/ 7372 PetscErrorCode DMPlexCheckGeometry(DM dm) 7373 { 7374 PetscReal detJ, J[9], refVol = 1.0; 7375 PetscReal vol; 7376 PetscInt dim, depth, d, cStart, cEnd, c, cMax; 7377 PetscErrorCode ierr; 7378 7379 PetscFunctionBegin; 7380 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 7381 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7382 for (d = 0; d < dim; ++d) refVol *= 2.0; 7383 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7384 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 7385 cMax = cMax < 0 ? cEnd : cMax; 7386 for (c = cStart; c < cMax; ++c) { 7387 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr); 7388 if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted, |J| = %g", c, (double) detJ); 7389 ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr); 7390 if (depth > 1) { 7391 ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr); 7392 if (vol <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %d is inverted, vol = %g", c, (double) vol); 7393 ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr); 7394 } 7395 } 7396 PetscFunctionReturn(0); 7397 } 7398 7399 /*@ 7400 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 7401 7402 Input Parameters: 7403 . dm - The DMPlex object 7404 7405 Notes: 7406 This is mainly intended for debugging/testing purposes. 7407 It currently checks only meshes with no partition overlapping. 7408 7409 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7410 7411 Level: developer 7412 7413 .seealso: DMGetPointSF(), DMSetFromOptions() 7414 @*/ 7415 PetscErrorCode DMPlexCheckPointSF(DM dm) 7416 { 7417 PetscSF pointSF; 7418 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 7419 const PetscInt *locals, *rootdegree; 7420 PetscBool distributed; 7421 PetscErrorCode ierr; 7422 7423 PetscFunctionBegin; 7424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7425 ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr); 7426 ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr); 7427 if (!distributed) PetscFunctionReturn(0); 7428 ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr); 7429 if (overlap) { 7430 ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping"); 7431 PetscFunctionReturn(0); 7432 } 7433 if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 7434 ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr); 7435 if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 7436 ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr); 7437 ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr); 7438 7439 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 7440 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 7441 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 7442 for (l = 0; l < nleaves; ++l) { 7443 const PetscInt point = locals[l]; 7444 7445 if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point); 7446 } 7447 7448 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 7449 for (l = 0; l < nleaves; ++l) { 7450 const PetscInt point = locals[l]; 7451 const PetscInt *cone; 7452 PetscInt coneSize, c, idx; 7453 7454 ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr); 7455 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 7456 for (c = 0; c < coneSize; ++c) { 7457 if (!rootdegree[cone[c]]) { 7458 ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr); 7459 if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]); 7460 } 7461 } 7462 } 7463 PetscFunctionReturn(0); 7464 } 7465 7466 typedef struct cell_stats 7467 { 7468 PetscReal min, max, sum, squaresum; 7469 PetscInt count; 7470 } cell_stats_t; 7471 7472 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 7473 { 7474 PetscInt i, N = *len; 7475 7476 for (i = 0; i < N; i++) { 7477 cell_stats_t *A = (cell_stats_t *) a; 7478 cell_stats_t *B = (cell_stats_t *) b; 7479 7480 B->min = PetscMin(A->min,B->min); 7481 B->max = PetscMax(A->max,B->max); 7482 B->sum += A->sum; 7483 B->squaresum += A->squaresum; 7484 B->count += A->count; 7485 } 7486 } 7487 7488 /*@ 7489 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 7490 7491 Collective on dm 7492 7493 Input Parameters: 7494 + dm - The DMPlex object 7495 . output - If true, statistics will be displayed on stdout 7496 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 7497 7498 Notes: 7499 This is mainly intended for debugging/testing purposes. 7500 7501 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7502 7503 Level: developer 7504 7505 .seealso: DMSetFromOptions() 7506 @*/ 7507 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 7508 { 7509 DM dmCoarse; 7510 cell_stats_t stats, globalStats; 7511 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 7512 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 7513 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 7514 PetscInt cdim, cStart, cEnd, cMax, c, eStart, eEnd, count = 0; 7515 PetscMPIInt rank,size; 7516 PetscErrorCode ierr; 7517 7518 PetscFunctionBegin; 7519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7520 stats.min = PETSC_MAX_REAL; 7521 stats.max = PETSC_MIN_REAL; 7522 stats.sum = stats.squaresum = 0.; 7523 stats.count = 0; 7524 7525 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 7526 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 7527 ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr); 7528 ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr); 7529 ierr = DMPlexGetHeightStratum(dm,0,&cStart,&cEnd);CHKERRQ(ierr); 7530 ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr); 7531 ierr = DMPlexGetHybridBounds(dm,&cMax,NULL,NULL,NULL);CHKERRQ(ierr); 7532 cMax = cMax < 0 ? cEnd : cMax; 7533 for (c = cStart; c < cMax; c++) { 7534 PetscInt i; 7535 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 7536 7537 ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr); 7538 if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c); 7539 for (i = 0; i < PetscSqr(cdim); ++i) { 7540 frobJ += J[i] * J[i]; 7541 frobInvJ += invJ[i] * invJ[i]; 7542 } 7543 cond2 = frobJ * frobInvJ; 7544 cond = PetscSqrtReal(cond2); 7545 7546 stats.min = PetscMin(stats.min,cond); 7547 stats.max = PetscMax(stats.max,cond); 7548 stats.sum += cond; 7549 stats.squaresum += cond2; 7550 stats.count++; 7551 if (output && cond > limit) { 7552 PetscSection coordSection; 7553 Vec coordsLocal; 7554 PetscScalar *coords = NULL; 7555 PetscInt Nv, d, clSize, cl, *closure = NULL; 7556 7557 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 7558 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 7559 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 7560 ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr); 7561 for (i = 0; i < Nv/cdim; ++i) { 7562 ierr = PetscSynchronizedPrintf(comm, " Vertex %D: (", i);CHKERRQ(ierr); 7563 for (d = 0; d < cdim; ++d) { 7564 if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);} 7565 ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr); 7566 } 7567 ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr); 7568 } 7569 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 7570 for (cl = 0; cl < clSize*2; cl += 2) { 7571 const PetscInt edge = closure[cl]; 7572 7573 if ((edge >= eStart) && (edge < eEnd)) { 7574 PetscReal len; 7575 7576 ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr); 7577 ierr = PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr); 7578 } 7579 } 7580 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 7581 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 7582 } 7583 } 7584 if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);} 7585 7586 if (size > 1) { 7587 PetscMPIInt blockLengths[2] = {4,1}; 7588 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 7589 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 7590 MPI_Op statReduce; 7591 7592 ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRQ(ierr); 7593 ierr = MPI_Type_commit(&statType);CHKERRQ(ierr); 7594 ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRQ(ierr); 7595 ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRQ(ierr); 7596 ierr = MPI_Op_free(&statReduce);CHKERRQ(ierr); 7597 ierr = MPI_Type_free(&statType);CHKERRQ(ierr); 7598 } else { 7599 ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr); 7600 } 7601 if (!rank) { 7602 count = globalStats.count; 7603 min = globalStats.min; 7604 max = globalStats.max; 7605 mean = globalStats.sum / globalStats.count; 7606 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 7607 } 7608 7609 if (output) { 7610 ierr = 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);CHKERRQ(ierr); 7611 } 7612 ierr = PetscFree2(J,invJ);CHKERRQ(ierr); 7613 7614 ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr); 7615 if (dmCoarse) { 7616 PetscBool isplex; 7617 7618 ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr); 7619 if (isplex) { 7620 ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr); 7621 } 7622 } 7623 PetscFunctionReturn(0); 7624 } 7625 7626 /* Pointwise interpolation 7627 Just code FEM for now 7628 u^f = I u^c 7629 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 7630 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 7631 I_{ij} = psi^f_i phi^c_j 7632 */ 7633 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 7634 { 7635 PetscSection gsc, gsf; 7636 PetscInt m, n; 7637 void *ctx; 7638 DM cdm; 7639 PetscBool regular, ismatis; 7640 PetscErrorCode ierr; 7641 7642 PetscFunctionBegin; 7643 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 7644 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 7645 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 7646 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 7647 7648 ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr); 7649 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr); 7650 ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 7651 ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr); 7652 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 7653 7654 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 7655 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 7656 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 7657 else {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 7658 ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr); 7659 if (scaling) { 7660 /* Use naive scaling */ 7661 ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr); 7662 } 7663 PetscFunctionReturn(0); 7664 } 7665 7666 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 7667 { 7668 PetscErrorCode ierr; 7669 VecScatter ctx; 7670 7671 PetscFunctionBegin; 7672 ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr); 7673 ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr); 7674 ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr); 7675 PetscFunctionReturn(0); 7676 } 7677 7678 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 7679 { 7680 PetscSection gsc, gsf; 7681 PetscInt m, n; 7682 void *ctx; 7683 DM cdm; 7684 PetscBool regular; 7685 PetscErrorCode ierr; 7686 7687 PetscFunctionBegin; 7688 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 7689 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 7690 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 7691 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 7692 7693 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr); 7694 ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 7695 ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr); 7696 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 7697 7698 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 7699 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 7700 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 7701 else {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 7702 ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr); 7703 PetscFunctionReturn(0); 7704 } 7705 7706 /*@ 7707 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 7708 7709 Input Parameter: 7710 . dm - The DMPlex object 7711 7712 Output Parameter: 7713 . regular - The flag 7714 7715 Level: intermediate 7716 7717 .seealso: DMPlexSetRegularRefinement() 7718 @*/ 7719 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 7720 { 7721 PetscFunctionBegin; 7722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7723 PetscValidPointer(regular, 2); 7724 *regular = ((DM_Plex *) dm->data)->regularRefinement; 7725 PetscFunctionReturn(0); 7726 } 7727 7728 /*@ 7729 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 7730 7731 Input Parameters: 7732 + dm - The DMPlex object 7733 - regular - The flag 7734 7735 Level: intermediate 7736 7737 .seealso: DMPlexGetRegularRefinement() 7738 @*/ 7739 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 7740 { 7741 PetscFunctionBegin; 7742 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7743 ((DM_Plex *) dm->data)->regularRefinement = regular; 7744 PetscFunctionReturn(0); 7745 } 7746 7747 /* anchors */ 7748 /*@ 7749 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 7750 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints(). 7751 7752 not collective 7753 7754 Input Parameters: 7755 . dm - The DMPlex object 7756 7757 Output Parameters: 7758 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 7759 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 7760 7761 7762 Level: intermediate 7763 7764 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints() 7765 @*/ 7766 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 7767 { 7768 DM_Plex *plex = (DM_Plex *)dm->data; 7769 PetscErrorCode ierr; 7770 7771 PetscFunctionBegin; 7772 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7773 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);} 7774 if (anchorSection) *anchorSection = plex->anchorSection; 7775 if (anchorIS) *anchorIS = plex->anchorIS; 7776 PetscFunctionReturn(0); 7777 } 7778 7779 /*@ 7780 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 7781 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 7782 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 7783 7784 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 7785 DMGetConstraints() and filling in the entries in the constraint matrix. 7786 7787 collective on dm 7788 7789 Input Parameters: 7790 + dm - The DMPlex object 7791 . 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). 7792 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 7793 7794 The reference counts of anchorSection and anchorIS are incremented. 7795 7796 Level: intermediate 7797 7798 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints() 7799 @*/ 7800 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 7801 { 7802 DM_Plex *plex = (DM_Plex *)dm->data; 7803 PetscMPIInt result; 7804 PetscErrorCode ierr; 7805 7806 PetscFunctionBegin; 7807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7808 if (anchorSection) { 7809 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 7810 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr); 7811 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 7812 } 7813 if (anchorIS) { 7814 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 7815 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr); 7816 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 7817 } 7818 7819 ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr); 7820 ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr); 7821 plex->anchorSection = anchorSection; 7822 7823 ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr); 7824 ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr); 7825 plex->anchorIS = anchorIS; 7826 7827 #if defined(PETSC_USE_DEBUG) 7828 if (anchorIS && anchorSection) { 7829 PetscInt size, a, pStart, pEnd; 7830 const PetscInt *anchors; 7831 7832 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 7833 ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr); 7834 ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr); 7835 for (a = 0; a < size; a++) { 7836 PetscInt p; 7837 7838 p = anchors[a]; 7839 if (p >= pStart && p < pEnd) { 7840 PetscInt dof; 7841 7842 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 7843 if (dof) { 7844 PetscErrorCode ierr2; 7845 7846 ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2); 7847 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p); 7848 } 7849 } 7850 } 7851 ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr); 7852 } 7853 #endif 7854 /* reset the generic constraints */ 7855 ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr); 7856 PetscFunctionReturn(0); 7857 } 7858 7859 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 7860 { 7861 PetscSection anchorSection; 7862 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 7863 PetscErrorCode ierr; 7864 7865 PetscFunctionBegin; 7866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7867 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 7868 ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr); 7869 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 7870 if (numFields) { 7871 PetscInt f; 7872 ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr); 7873 7874 for (f = 0; f < numFields; f++) { 7875 PetscInt numComp; 7876 7877 ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr); 7878 ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr); 7879 } 7880 } 7881 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 7882 ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr); 7883 pStart = PetscMax(pStart,sStart); 7884 pEnd = PetscMin(pEnd,sEnd); 7885 pEnd = PetscMax(pStart,pEnd); 7886 ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr); 7887 for (p = pStart; p < pEnd; p++) { 7888 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 7889 if (dof) { 7890 ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); 7891 ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr); 7892 for (f = 0; f < numFields; f++) { 7893 ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); 7894 ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr); 7895 } 7896 } 7897 } 7898 ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr); 7899 PetscFunctionReturn(0); 7900 } 7901 7902 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 7903 { 7904 PetscSection aSec; 7905 PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 7906 const PetscInt *anchors; 7907 PetscInt numFields, f; 7908 IS aIS; 7909 PetscErrorCode ierr; 7910 7911 PetscFunctionBegin; 7912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7913 ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr); 7914 ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr); 7915 ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr); 7916 ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr); 7917 ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr); 7918 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 7919 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 7920 /* cSec will be a subset of aSec and section */ 7921 ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr); 7922 ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr); 7923 i[0] = 0; 7924 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 7925 for (p = pStart; p < pEnd; p++) { 7926 PetscInt rDof, rOff, r; 7927 7928 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 7929 if (!rDof) continue; 7930 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 7931 if (numFields) { 7932 for (f = 0; f < numFields; f++) { 7933 annz = 0; 7934 for (r = 0; r < rDof; r++) { 7935 a = anchors[rOff + r]; 7936 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 7937 annz += aDof; 7938 } 7939 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 7940 ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr); 7941 for (q = 0; q < dof; q++) { 7942 i[off + q + 1] = i[off + q] + annz; 7943 } 7944 } 7945 } 7946 else { 7947 annz = 0; 7948 for (q = 0; q < dof; q++) { 7949 a = anchors[off + q]; 7950 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 7951 annz += aDof; 7952 } 7953 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 7954 ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr); 7955 for (q = 0; q < dof; q++) { 7956 i[off + q + 1] = i[off + q] + annz; 7957 } 7958 } 7959 } 7960 nnz = i[m]; 7961 ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr); 7962 offset = 0; 7963 for (p = pStart; p < pEnd; p++) { 7964 if (numFields) { 7965 for (f = 0; f < numFields; f++) { 7966 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 7967 for (q = 0; q < dof; q++) { 7968 PetscInt rDof, rOff, r; 7969 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 7970 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 7971 for (r = 0; r < rDof; r++) { 7972 PetscInt s; 7973 7974 a = anchors[rOff + r]; 7975 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 7976 ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr); 7977 for (s = 0; s < aDof; s++) { 7978 j[offset++] = aOff + s; 7979 } 7980 } 7981 } 7982 } 7983 } 7984 else { 7985 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 7986 for (q = 0; q < dof; q++) { 7987 PetscInt rDof, rOff, r; 7988 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 7989 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 7990 for (r = 0; r < rDof; r++) { 7991 PetscInt s; 7992 7993 a = anchors[rOff + r]; 7994 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 7995 ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr); 7996 for (s = 0; s < aDof; s++) { 7997 j[offset++] = aOff + s; 7998 } 7999 } 8000 } 8001 } 8002 } 8003 ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr); 8004 ierr = PetscFree(i);CHKERRQ(ierr); 8005 ierr = PetscFree(j);CHKERRQ(ierr); 8006 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 8007 PetscFunctionReturn(0); 8008 } 8009 8010 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 8011 { 8012 DM_Plex *plex = (DM_Plex *)dm->data; 8013 PetscSection anchorSection, section, cSec; 8014 Mat cMat; 8015 PetscErrorCode ierr; 8016 8017 PetscFunctionBegin; 8018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8019 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 8020 if (anchorSection) { 8021 PetscInt Nf; 8022 8023 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 8024 ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr); 8025 ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr); 8026 ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr); 8027 if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);} 8028 ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr); 8029 ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr); 8030 ierr = MatDestroy(&cMat);CHKERRQ(ierr); 8031 } 8032 PetscFunctionReturn(0); 8033 } 8034 8035 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 8036 { 8037 IS subis; 8038 PetscSection section, subsection; 8039 PetscErrorCode ierr; 8040 8041 PetscFunctionBegin; 8042 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 8043 if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 8044 if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 8045 /* Create subdomain */ 8046 ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr); 8047 /* Create submodel */ 8048 ierr = DMPlexCreateSubpointIS(*subdm, &subis);CHKERRQ(ierr); 8049 ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr); 8050 ierr = ISDestroy(&subis);CHKERRQ(ierr); 8051 ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr); 8052 ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr); 8053 ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr); 8054 /* Create map from submodel to global model */ 8055 if (is) { 8056 PetscSection sectionGlobal, subsectionGlobal; 8057 IS spIS; 8058 const PetscInt *spmap; 8059 PetscInt *subIndices; 8060 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 8061 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 8062 8063 ierr = DMPlexCreateSubpointIS(*subdm, &spIS);CHKERRQ(ierr); 8064 ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr); 8065 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 8066 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 8067 ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr); 8068 ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr); 8069 for (p = pStart; p < pEnd; ++p) { 8070 PetscInt gdof, pSubSize = 0; 8071 8072 ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr); 8073 if (gdof > 0) { 8074 for (f = 0; f < Nf; ++f) { 8075 PetscInt fdof, fcdof; 8076 8077 ierr = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr); 8078 ierr = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr); 8079 pSubSize += fdof-fcdof; 8080 } 8081 subSize += pSubSize; 8082 if (pSubSize) { 8083 if (bs < 0) { 8084 bs = pSubSize; 8085 } else if (bs != pSubSize) { 8086 /* Layout does not admit a pointwise block size */ 8087 bs = 1; 8088 } 8089 } 8090 } 8091 } 8092 /* Must have same blocksize on all procs (some might have no points) */ 8093 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 8094 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 8095 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 8096 else {bs = bsMinMax[0];} 8097 ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr); 8098 for (p = pStart; p < pEnd; ++p) { 8099 PetscInt gdof, goff; 8100 8101 ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr); 8102 if (gdof > 0) { 8103 const PetscInt point = spmap[p]; 8104 8105 ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr); 8106 for (f = 0; f < Nf; ++f) { 8107 PetscInt fdof, fcdof, fc, f2, poff = 0; 8108 8109 /* Can get rid of this loop by storing field information in the global section */ 8110 for (f2 = 0; f2 < f; ++f2) { 8111 ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr); 8112 ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr); 8113 poff += fdof-fcdof; 8114 } 8115 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 8116 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 8117 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 8118 subIndices[subOff] = goff+poff+fc; 8119 } 8120 } 8121 } 8122 } 8123 ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr); 8124 ierr = ISDestroy(&spIS);CHKERRQ(ierr); 8125 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr); 8126 if (bs > 1) { 8127 /* We need to check that the block size does not come from non-contiguous fields */ 8128 PetscInt i, j, set = 1; 8129 for (i = 0; i < subSize; i += bs) { 8130 for (j = 0; j < bs; ++j) { 8131 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 8132 } 8133 } 8134 if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);} 8135 } 8136 /* Attach nullspace */ 8137 for (f = 0; f < Nf; ++f) { 8138 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 8139 if ((*subdm)->nullspaceConstructors[f]) break; 8140 } 8141 if (f < Nf) { 8142 MatNullSpace nullSpace; 8143 8144 ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, &nullSpace);CHKERRQ(ierr); 8145 ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr); 8146 ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); 8147 } 8148 } 8149 PetscFunctionReturn(0); 8150 } 8151 8152 /*@ 8153 DMPlexMonitorThroughput - Report the cell throughput of FE integration 8154 8155 Input Parameter: 8156 - dm - The DM 8157 8158 Level: developer 8159 8160 Options Database Keys: 8161 . -dm_plex_monitor_throughput - Activate the monitor 8162 8163 .seealso: DMSetFromOptions(), DMPlexCreate() 8164 @*/ 8165 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 8166 { 8167 PetscStageLog stageLog; 8168 PetscLogEvent event; 8169 PetscLogStage stage; 8170 PetscEventPerfInfo eventInfo; 8171 PetscReal cellRate, flopRate; 8172 PetscInt cStart, cEnd, Nf, N; 8173 const char *name; 8174 PetscErrorCode ierr; 8175 8176 PetscFunctionBegin; 8177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8178 #if defined(PETSC_USE_LOG) 8179 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 8180 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 8181 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 8182 ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr); 8183 ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr); 8184 ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr); 8185 ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr); 8186 N = (cEnd - cStart)*Nf*eventInfo.count; 8187 flopRate = eventInfo.flops/eventInfo.time; 8188 cellRate = N/eventInfo.time; 8189 ierr = 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));CHKERRQ(ierr); 8190 #else 8191 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 8192 #endif 8193 PetscFunctionReturn(0); 8194 } 8195