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