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