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