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