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