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 DMPlexIsSimplex - Is the first cell in this mesh a simplex? 17 18 Input Parameter: 19 . dm - The DMPlex object 20 21 Output Parameter: 22 . simplex - Flag checking for a simplex 23 24 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 25 If the mesh has no cells, this returns PETSC_FALSE. 26 27 Level: intermediate 28 29 .seealso DMPlexGetSimplexOrBoxCells(), DMPlexGetCellType(), DMPlexGetHeightStratum(), DMPolytopeTypeGetNumVertices() 30 @*/ 31 PetscErrorCode DMPlexIsSimplex(DM dm, PetscBool *simplex) 32 { 33 DMPolytopeType ct; 34 PetscInt cStart, cEnd; 35 PetscErrorCode ierr; 36 37 PetscFunctionBegin; 38 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 39 if (cEnd <= cStart) {*simplex = PETSC_FALSE; PetscFunctionReturn(0);} 40 ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 41 *simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 42 PetscFunctionReturn(0); 43 } 44 45 /*@ 46 DMPlexGetSimplexOrBoxCells - Get the range of cells which are neither prisms nor ghost FV cells 47 48 Input Parameter: 49 + dm - The DMPlex object 50 - height - The cell height in the Plex, 0 is the default 51 52 Output Parameters: 53 + cStart - The first "normal" cell 54 - cEnd - The upper bound on "normal"" cells 55 56 Note: This just gives the first range of cells found. If the mesh has several cell types, it will only give the first. 57 58 Level: developer 59 60 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 61 @*/ 62 PetscErrorCode DMPlexGetSimplexOrBoxCells(DM dm, PetscInt height, PetscInt *cStart, PetscInt *cEnd) 63 { 64 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 65 PetscInt cS, cE, c; 66 PetscErrorCode ierr; 67 68 PetscFunctionBegin; 69 ierr = DMPlexGetHeightStratum(dm, PetscMax(height, 0), &cS, &cE);CHKERRQ(ierr); 70 for (c = cS; c < cE; ++c) { 71 DMPolytopeType cct; 72 73 ierr = DMPlexGetCellType(dm, c, &cct);CHKERRQ(ierr); 74 if ((PetscInt) cct < 0) break; 75 switch (cct) { 76 case DM_POLYTOPE_POINT: 77 case DM_POLYTOPE_SEGMENT: 78 case DM_POLYTOPE_TRIANGLE: 79 case DM_POLYTOPE_QUADRILATERAL: 80 case DM_POLYTOPE_TETRAHEDRON: 81 case DM_POLYTOPE_HEXAHEDRON: 82 ct = cct; 83 break; 84 default: break; 85 } 86 if (ct != DM_POLYTOPE_UNKNOWN) break; 87 } 88 if (ct != DM_POLYTOPE_UNKNOWN) { 89 DMLabel ctLabel; 90 91 ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr); 92 ierr = DMLabelGetStratumBounds(ctLabel, ct, &cS, &cE);CHKERRQ(ierr); 93 } 94 if (cStart) *cStart = cS; 95 if (cEnd) *cEnd = cE; 96 PetscFunctionReturn(0); 97 } 98 99 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 100 { 101 PetscInt cdim, pStart, pEnd, vStart, vEnd, cStart, cEnd; 102 PetscInt vcdof[2] = {0,0}, globalvcdof[2]; 103 PetscErrorCode ierr; 104 105 PetscFunctionBegin; 106 *ft = PETSC_VTK_INVALID; 107 ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr); 108 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 109 ierr = DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 110 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 111 if (field >= 0) { 112 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vcdof[0]);CHKERRQ(ierr);} 113 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &vcdof[1]);CHKERRQ(ierr);} 114 } else { 115 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vcdof[0]);CHKERRQ(ierr);} 116 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &vcdof[1]);CHKERRQ(ierr);} 117 } 118 ierr = MPI_Allreduce(vcdof, globalvcdof, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr); 119 if (globalvcdof[0]) { 120 *sStart = vStart; 121 *sEnd = vEnd; 122 if (globalvcdof[0] == cdim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 123 else *ft = PETSC_VTK_POINT_FIELD; 124 } else if (globalvcdof[1]) { 125 *sStart = cStart; 126 *sEnd = cEnd; 127 if (globalvcdof[1] == cdim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 128 else *ft = PETSC_VTK_CELL_FIELD; 129 } else { 130 if (field >= 0) { 131 const char *fieldname; 132 133 ierr = PetscSectionGetFieldName(section, field, &fieldname);CHKERRQ(ierr); 134 ierr = PetscInfo2((PetscObject) dm, "Could not classify VTK output type of section field %D \"%s\"\n", field, fieldname);CHKERRQ(ierr); 135 } else { 136 ierr = PetscInfo((PetscObject) dm, "Could not classify VTK output type of section\"%s\"\n");CHKERRQ(ierr); 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 static PetscErrorCode VecView_Plex_Local_Draw(Vec v, PetscViewer viewer) 143 { 144 DM dm; 145 PetscSection s; 146 PetscDraw draw, popup; 147 DM cdm; 148 PetscSection coordSection; 149 Vec coordinates; 150 const PetscScalar *coords, *array; 151 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 152 PetscReal vbound[2], time; 153 PetscBool isnull, flg; 154 PetscInt dim, Nf, f, Nc, comp, vStart, vEnd, cStart, cEnd, c, N, level, step, w = 0; 155 const char *name; 156 char title[PETSC_MAX_PATH_LEN]; 157 PetscErrorCode ierr; 158 159 PetscFunctionBegin; 160 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 161 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 162 if (isnull) PetscFunctionReturn(0); 163 164 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 165 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 166 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D. Use PETSCVIEWERGLVIS", dim); 167 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 168 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 169 ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr); 170 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 171 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 172 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 173 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 174 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 175 176 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 177 ierr = DMGetOutputSequenceNumber(dm, &step, &time);CHKERRQ(ierr); 178 179 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 180 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 181 for (c = 0; c < N; c += dim) { 182 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 183 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 184 } 185 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 186 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 187 188 /* Could implement something like DMDASelectFields() */ 189 for (f = 0; f < Nf; ++f) { 190 DM fdm = dm; 191 Vec fv = v; 192 IS fis; 193 char prefix[PETSC_MAX_PATH_LEN]; 194 const char *fname; 195 196 ierr = PetscSectionGetFieldComponents(s, f, &Nc);CHKERRQ(ierr); 197 ierr = PetscSectionGetFieldName(s, f, &fname);CHKERRQ(ierr); 198 199 if (v->hdr.prefix) {ierr = PetscStrncpy(prefix, v->hdr.prefix,sizeof(prefix));CHKERRQ(ierr);} 200 else {prefix[0] = '\0';} 201 if (Nf > 1) { 202 ierr = DMCreateSubDM(dm, 1, &f, &fis, &fdm);CHKERRQ(ierr); 203 ierr = VecGetSubVector(v, fis, &fv);CHKERRQ(ierr); 204 ierr = PetscStrlcat(prefix, fname,sizeof(prefix));CHKERRQ(ierr); 205 ierr = PetscStrlcat(prefix, "_",sizeof(prefix));CHKERRQ(ierr); 206 } 207 for (comp = 0; comp < Nc; ++comp, ++w) { 208 PetscInt nmax = 2; 209 210 ierr = PetscViewerDrawGetDraw(viewer, w, &draw);CHKERRQ(ierr); 211 if (Nc > 1) {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s_%D Step: %D Time: %.4g", name, fname, comp, step, time);CHKERRQ(ierr);} 212 else {ierr = PetscSNPrintf(title, sizeof(title), "%s:%s Step: %D Time: %.4g", name, fname, step, time);CHKERRQ(ierr);} 213 ierr = PetscDrawSetTitle(draw, title);CHKERRQ(ierr); 214 215 /* TODO Get max and min only for this component */ 216 ierr = PetscOptionsGetRealArray(NULL, prefix, "-vec_view_bounds", vbound, &nmax, &flg);CHKERRQ(ierr); 217 if (!flg) { 218 ierr = VecMin(fv, NULL, &vbound[0]);CHKERRQ(ierr); 219 ierr = VecMax(fv, NULL, &vbound[1]);CHKERRQ(ierr); 220 if (vbound[1] <= vbound[0]) vbound[1] = vbound[0] + 1.0; 221 } 222 ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr); 223 ierr = PetscDrawScalePopup(popup, vbound[0], vbound[1]);CHKERRQ(ierr); 224 ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr); 225 226 ierr = VecGetArrayRead(fv, &array);CHKERRQ(ierr); 227 for (c = cStart; c < cEnd; ++c) { 228 PetscScalar *coords = NULL, *a = NULL; 229 PetscInt numCoords, color[4] = {-1,-1,-1,-1}; 230 231 ierr = DMPlexPointLocalRead(fdm, c, array, &a);CHKERRQ(ierr); 232 if (a) { 233 color[0] = PetscDrawRealToColor(PetscRealPart(a[comp]), vbound[0], vbound[1]); 234 color[1] = color[2] = color[3] = color[0]; 235 } else { 236 PetscScalar *vals = NULL; 237 PetscInt numVals, va; 238 239 ierr = DMPlexVecGetClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 240 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); 241 switch (numVals/Nc) { 242 case 3: /* P1 Triangle */ 243 case 4: /* P1 Quadrangle */ 244 for (va = 0; va < numVals/Nc; ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp]), vbound[0], vbound[1]); 245 break; 246 case 6: /* P2 Triangle */ 247 case 8: /* P2 Quadrangle */ 248 for (va = 0; va < numVals/(Nc*2); ++va) color[va] = PetscDrawRealToColor(PetscRealPart(vals[va*Nc+comp + numVals/(Nc*2)]), vbound[0], vbound[1]); 249 break; 250 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of values for cell closure %D cannot be handled", numVals/Nc); 251 } 252 ierr = DMPlexVecRestoreClosure(fdm, NULL, fv, c, &numVals, &vals);CHKERRQ(ierr); 253 } 254 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 255 switch (numCoords) { 256 case 6: 257 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); 258 break; 259 case 8: 260 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); 261 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); 262 break; 263 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 264 } 265 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 266 } 267 ierr = VecRestoreArrayRead(fv, &array);CHKERRQ(ierr); 268 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 269 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 270 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 271 } 272 if (Nf > 1) { 273 ierr = VecRestoreSubVector(v, fis, &fv);CHKERRQ(ierr); 274 ierr = ISDestroy(&fis);CHKERRQ(ierr); 275 ierr = DMDestroy(&fdm);CHKERRQ(ierr); 276 } 277 } 278 PetscFunctionReturn(0); 279 } 280 281 static PetscErrorCode VecView_Plex_Local_VTK(Vec v, PetscViewer viewer) 282 { 283 DM dm; 284 Vec locv; 285 const char *name; 286 PetscSection section; 287 PetscInt pStart, pEnd; 288 PetscInt numFields; 289 PetscViewerVTKFieldType ft; 290 PetscErrorCode ierr; 291 292 PetscFunctionBegin; 293 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 294 ierr = DMCreateLocalVector(dm, &locv);CHKERRQ(ierr); /* VTK viewer requires exclusive ownership of the vector */ 295 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 296 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 297 ierr = VecCopy(v, locv);CHKERRQ(ierr); 298 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 299 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 300 if (!numFields) { 301 ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr); 302 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, PETSC_DEFAULT, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 303 } else { 304 PetscInt f; 305 306 for (f = 0; f < numFields; f++) { 307 ierr = DMPlexGetFieldType_Internal(dm, section, f, &pStart, &pEnd, &ft);CHKERRQ(ierr); 308 if (ft == PETSC_VTK_INVALID) continue; 309 ierr = PetscObjectReference((PetscObject)locv);CHKERRQ(ierr); 310 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, f, ft, PETSC_TRUE,(PetscObject) locv);CHKERRQ(ierr); 311 } 312 ierr = VecDestroy(&locv);CHKERRQ(ierr); 313 } 314 PetscFunctionReturn(0); 315 } 316 317 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 318 { 319 DM dm; 320 PetscBool isvtk, ishdf5, isdraw, isglvis; 321 PetscErrorCode ierr; 322 323 PetscFunctionBegin; 324 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 325 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 326 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 327 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 328 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 329 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 330 if (isvtk || ishdf5 || isdraw || isglvis) { 331 PetscInt i,numFields; 332 PetscObject fe; 333 PetscBool fem = PETSC_FALSE; 334 Vec locv = v; 335 const char *name; 336 PetscInt step; 337 PetscReal time; 338 339 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 340 for (i=0; i<numFields; i++) { 341 ierr = DMGetField(dm, i, NULL, &fe);CHKERRQ(ierr); 342 if (fe->classid == PETSCFE_CLASSID) { fem = PETSC_TRUE; break; } 343 } 344 if (fem) { 345 PetscObject isZero; 346 347 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 348 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 349 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 350 ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr); 351 ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr); 352 ierr = VecCopy(v, locv);CHKERRQ(ierr); 353 ierr = DMGetOutputSequenceNumber(dm, NULL, &time);CHKERRQ(ierr); 354 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locv, time, NULL, NULL, NULL);CHKERRQ(ierr); 355 } 356 if (isvtk) { 357 ierr = VecView_Plex_Local_VTK(locv, viewer);CHKERRQ(ierr); 358 } else if (ishdf5) { 359 #if defined(PETSC_HAVE_HDF5) 360 ierr = VecView_Plex_Local_HDF5_Internal(locv, viewer);CHKERRQ(ierr); 361 #else 362 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 363 #endif 364 } else if (isdraw) { 365 ierr = VecView_Plex_Local_Draw(locv, viewer);CHKERRQ(ierr); 366 } else if (isglvis) { 367 ierr = DMGetOutputSequenceNumber(dm, &step, NULL);CHKERRQ(ierr); 368 ierr = PetscViewerGLVisSetSnapId(viewer, step);CHKERRQ(ierr); 369 ierr = VecView_GLVis(locv, viewer);CHKERRQ(ierr); 370 } 371 if (fem) { 372 ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr); 373 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 374 } 375 } else { 376 PetscBool isseq; 377 378 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 379 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 380 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 381 } 382 PetscFunctionReturn(0); 383 } 384 385 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 386 { 387 DM dm; 388 PetscBool isvtk, ishdf5, isdraw, isglvis, isexodusii; 389 PetscErrorCode ierr; 390 391 PetscFunctionBegin; 392 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 393 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 394 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 395 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 396 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 397 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 398 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr); 399 if (isvtk || isdraw || isglvis) { 400 Vec locv; 401 PetscObject isZero; 402 const char *name; 403 404 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 405 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 406 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 407 ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 408 ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 409 ierr = PetscObjectQuery((PetscObject) v, "__Vec_bc_zero__", &isZero);CHKERRQ(ierr); 410 ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", isZero);CHKERRQ(ierr); 411 ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr); 412 ierr = PetscObjectCompose((PetscObject) locv, "__Vec_bc_zero__", NULL);CHKERRQ(ierr); 413 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 414 } else if (ishdf5) { 415 #if defined(PETSC_HAVE_HDF5) 416 ierr = VecView_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 417 #else 418 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 419 #endif 420 } else if (isexodusii) { 421 #if defined(PETSC_HAVE_EXODUSII) 422 ierr = VecView_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr); 423 #else 424 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 425 #endif 426 } else { 427 PetscBool isseq; 428 429 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 430 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 431 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 432 } 433 PetscFunctionReturn(0); 434 } 435 436 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 437 { 438 DM dm; 439 MPI_Comm comm; 440 PetscViewerFormat format; 441 Vec v; 442 PetscBool isvtk, ishdf5; 443 PetscErrorCode ierr; 444 445 PetscFunctionBegin; 446 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 447 ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr); 448 if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 449 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 450 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 451 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 452 if (format == PETSC_VIEWER_NATIVE) { 453 /* Natural ordering is the common case for DMDA, NATIVE means plain vector, for PLEX is the opposite */ 454 /* this need a better fix */ 455 if (dm->useNatural) { 456 if (dm->sfNatural) { 457 const char *vecname; 458 PetscInt n, nroots; 459 460 ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr); 461 ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 462 if (n == nroots) { 463 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 464 ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr); 465 ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr); 466 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 467 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 468 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 469 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 470 } else v = originalv; 471 } else v = originalv; 472 473 if (ishdf5) { 474 #if defined(PETSC_HAVE_HDF5) 475 ierr = VecView_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 476 #else 477 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 478 #endif 479 } else if (isvtk) { 480 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 481 } else { 482 PetscBool isseq; 483 484 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 485 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 486 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 487 } 488 if (v != originalv) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);} 489 PetscFunctionReturn(0); 490 } 491 492 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 493 { 494 DM dm; 495 PetscBool ishdf5; 496 PetscErrorCode ierr; 497 498 PetscFunctionBegin; 499 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 500 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 501 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 502 if (ishdf5) { 503 DM dmBC; 504 Vec gv; 505 const char *name; 506 507 ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr); 508 ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr); 509 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 510 ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr); 511 ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr); 512 ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 513 ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 514 ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr); 515 } else { 516 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 517 } 518 PetscFunctionReturn(0); 519 } 520 521 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 522 { 523 DM dm; 524 PetscBool ishdf5,isexodusii; 525 PetscErrorCode ierr; 526 527 PetscFunctionBegin; 528 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 529 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 530 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 531 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodusii);CHKERRQ(ierr); 532 if (ishdf5) { 533 #if defined(PETSC_HAVE_HDF5) 534 ierr = VecLoad_Plex_HDF5_Internal(v, viewer);CHKERRQ(ierr); 535 #else 536 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 537 #endif 538 } else if (isexodusii) { 539 #if defined(PETSC_HAVE_EXODUSII) 540 ierr = VecLoad_PlexExodusII_Internal(v, viewer);CHKERRQ(ierr); 541 #else 542 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "ExodusII not supported in this build.\nPlease reconfigure using --download-exodusii"); 543 #endif 544 } else { 545 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 546 } 547 PetscFunctionReturn(0); 548 } 549 550 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 551 { 552 DM dm; 553 PetscViewerFormat format; 554 PetscBool ishdf5; 555 PetscErrorCode ierr; 556 557 PetscFunctionBegin; 558 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 559 if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 560 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 561 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 562 if (format == PETSC_VIEWER_NATIVE) { 563 if (dm->useNatural) { 564 if (dm->sfNatural) { 565 if (ishdf5) { 566 #if defined(PETSC_HAVE_HDF5) 567 Vec v; 568 const char *vecname; 569 570 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 571 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 572 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 573 ierr = VecLoad_Plex_HDF5_Native_Internal(v, viewer);CHKERRQ(ierr); 574 ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr); 575 ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr); 576 ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr); 577 #else 578 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 579 #endif 580 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 581 } 582 } else { 583 ierr = VecLoad_Default(originalv, viewer);CHKERRQ(ierr); 584 } 585 } 586 PetscFunctionReturn(0); 587 } 588 589 PETSC_UNUSED static PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 590 { 591 PetscSection coordSection; 592 Vec coordinates; 593 DMLabel depthLabel, celltypeLabel; 594 const char *name[4]; 595 const PetscScalar *a; 596 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 597 PetscErrorCode ierr; 598 599 PetscFunctionBegin; 600 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 601 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 602 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 603 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 604 ierr = DMPlexGetCellTypeLabel(dm, &celltypeLabel);CHKERRQ(ierr); 605 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 606 ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr); 607 ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr); 608 name[0] = "vertex"; 609 name[1] = "edge"; 610 name[dim-1] = "face"; 611 name[dim] = "cell"; 612 for (c = cStart; c < cEnd; ++c) { 613 PetscInt *closure = NULL; 614 PetscInt closureSize, cl, ct; 615 616 ierr = DMLabelGetValue(celltypeLabel, c, &ct);CHKERRQ(ierr); 617 ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D polytope type %s:\n", c, DMPolytopeTypes[ct]);CHKERRQ(ierr); 618 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 619 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 620 for (cl = 0; cl < closureSize*2; cl += 2) { 621 PetscInt point = closure[cl], depth, dof, off, d, p; 622 623 if ((point < pStart) || (point >= pEnd)) continue; 624 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 625 if (!dof) continue; 626 ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr); 627 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 628 ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr); 629 for (p = 0; p < dof/dim; ++p) { 630 ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr); 631 for (d = 0; d < dim; ++d) { 632 if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 633 ierr = PetscViewerASCIIPrintf(viewer, "%g", (double) PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr); 634 } 635 ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr); 636 } 637 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 638 } 639 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 640 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 641 } 642 ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr); 643 PetscFunctionReturn(0); 644 } 645 646 static PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 647 { 648 DM_Plex *mesh = (DM_Plex*) dm->data; 649 DM cdm; 650 PetscSection coordSection; 651 Vec coordinates; 652 PetscViewerFormat format; 653 PetscErrorCode ierr; 654 655 PetscFunctionBegin; 656 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 657 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 658 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 659 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 660 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 661 const char *name; 662 PetscInt dim, cellHeight, maxConeSize, maxSupportSize; 663 PetscInt pStart, pEnd, p, numLabels, l; 664 PetscMPIInt rank, size; 665 666 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr); 667 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr); 668 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 669 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 670 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 671 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 672 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 673 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 674 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 675 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 676 ierr = PetscViewerASCIIPrintf(viewer, "Supports:\n", name);CHKERRQ(ierr); 677 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 678 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max support size: %D\n", rank, maxSupportSize);CHKERRQ(ierr); 679 for (p = pStart; p < pEnd; ++p) { 680 PetscInt dof, off, s; 681 682 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 683 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 684 for (s = off; s < off+dof; ++s) { 685 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr); 686 } 687 } 688 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 689 ierr = PetscViewerASCIIPrintf(viewer, "Cones:\n", name);CHKERRQ(ierr); 690 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max cone size: %D\n", rank, maxConeSize);CHKERRQ(ierr); 691 for (p = pStart; p < pEnd; ++p) { 692 PetscInt dof, off, c; 693 694 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 695 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 696 for (c = off; c < off+dof; ++c) { 697 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr); 698 } 699 } 700 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 701 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 702 if (coordSection && coordinates) { 703 ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr); 704 } 705 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 706 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 707 for (l = 0; l < numLabels; ++l) { 708 DMLabel label; 709 PetscBool isdepth; 710 const char *name; 711 712 ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr); 713 ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr); 714 if (isdepth) continue; 715 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 716 ierr = DMLabelView(label, viewer);CHKERRQ(ierr); 717 } 718 if (size > 1) { 719 PetscSF sf; 720 721 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 722 ierr = PetscSFView(sf, viewer);CHKERRQ(ierr); 723 } 724 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 725 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 726 const char *name, *color; 727 const char *defcolors[3] = {"gray", "orange", "green"}; 728 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 729 char lname[PETSC_MAX_PATH_LEN]; 730 PetscReal scale = 2.0; 731 PetscReal tikzscale = 1.0; 732 PetscBool useNumbers = PETSC_TRUE, useLabels, useColors; 733 double tcoords[3]; 734 PetscScalar *coords; 735 PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p; 736 PetscMPIInt rank, size; 737 char **names, **colors, **lcolors; 738 PetscBool plotEdges, flg, lflg; 739 PetscBT wp = NULL; 740 PetscInt pEnd, pStart; 741 742 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 743 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 744 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 745 numLabels = PetscMax(numLabels, 10); 746 numColors = 10; 747 numLColors = 10; 748 ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr); 749 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr); 750 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_tikzscale", &tikzscale, NULL);CHKERRQ(ierr); 751 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr); 752 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr); 753 if (!useLabels) numLabels = 0; 754 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr); 755 if (!useColors) { 756 numColors = 3; 757 for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);} 758 } 759 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr); 760 if (!useColors) { 761 numLColors = 4; 762 for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);} 763 } 764 ierr = PetscOptionsGetString(((PetscObject) viewer)->options, ((PetscObject) viewer)->prefix, "-dm_plex_view_label_filter", lname, sizeof(lname), &lflg);CHKERRQ(ierr); 765 plotEdges = (PetscBool)(depth > 1 && useNumbers && dim < 3); 766 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_edges", &plotEdges, &flg);CHKERRQ(ierr); 767 if (flg && plotEdges && depth < dim) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh must be interpolated"); 768 if (depth < dim) plotEdges = PETSC_FALSE; 769 770 /* filter points with labelvalue != labeldefaultvalue */ 771 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 772 if (lflg) { 773 DMLabel lbl; 774 775 ierr = DMGetLabel(dm, lname, &lbl);CHKERRQ(ierr); 776 if (lbl) { 777 PetscInt val, defval; 778 779 ierr = DMLabelGetDefaultValue(lbl, &defval);CHKERRQ(ierr); 780 ierr = PetscBTCreate(pEnd-pStart, &wp);CHKERRQ(ierr); 781 for (c = pStart; c < pEnd; c++) { 782 PetscInt *closure = NULL; 783 PetscInt closureSize; 784 785 ierr = DMLabelGetValue(lbl, c, &val);CHKERRQ(ierr); 786 if (val == defval) continue; 787 788 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 789 for (p = 0; p < closureSize*2; p += 2) { 790 ierr = PetscBTSet(wp, closure[p] - pStart);CHKERRQ(ierr); 791 } 792 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 793 } 794 } 795 } 796 797 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRMPI(ierr); 798 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRMPI(ierr); 799 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 800 ierr = PetscViewerASCIIPrintf(viewer, "\ 801 \\documentclass[tikz]{standalone}\n\n\ 802 \\usepackage{pgflibraryshapes}\n\ 803 \\usetikzlibrary{backgrounds}\n\ 804 \\usetikzlibrary{arrows}\n\ 805 \\begin{document}\n");CHKERRQ(ierr); 806 if (size > 1) { 807 ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr); 808 for (p = 0; p < size; ++p) { 809 if (p > 0 && p == size-1) { 810 ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr); 811 } else if (p > 0) { 812 ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr); 813 } 814 ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr); 815 } 816 ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr); 817 } 818 ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", (double) tikzscale);CHKERRQ(ierr); 819 820 /* Plot vertices */ 821 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 822 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 823 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 824 for (v = vStart; v < vEnd; ++v) { 825 PetscInt off, dof, d; 826 PetscBool isLabeled = PETSC_FALSE; 827 828 if (wp && !PetscBTLookup(wp,v - pStart)) continue; 829 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 830 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 831 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 832 if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof); 833 for (d = 0; d < dof; ++d) { 834 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 835 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 836 } 837 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 838 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 839 for (d = 0; d < dof; ++d) { 840 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 841 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) tcoords[d]);CHKERRQ(ierr); 842 } 843 color = colors[rank%numColors]; 844 for (l = 0; l < numLabels; ++l) { 845 PetscInt val; 846 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 847 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 848 } 849 if (useNumbers) { 850 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr); 851 } else { 852 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 853 } 854 } 855 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 856 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 857 /* Plot cells */ 858 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 859 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr); 860 if (dim == 3 || !useNumbers) { 861 for (e = eStart; e < eEnd; ++e) { 862 const PetscInt *cone; 863 864 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 865 color = colors[rank%numColors]; 866 for (l = 0; l < numLabels; ++l) { 867 PetscInt val; 868 ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr); 869 if (val >= 0) {color = lcolors[l%numLColors]; break;} 870 } 871 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 872 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr); 873 } 874 } else { 875 for (c = cStart; c < cEnd; ++c) { 876 PetscInt *closure = NULL; 877 PetscInt closureSize, firstPoint = -1; 878 879 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 880 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 881 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr); 882 for (p = 0; p < closureSize*2; p += 2) { 883 const PetscInt point = closure[p]; 884 885 if ((point < vStart) || (point >= vEnd)) continue; 886 if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);} 887 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr); 888 if (firstPoint < 0) firstPoint = point; 889 } 890 /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */ 891 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr); 892 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 893 } 894 } 895 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 896 for (c = cStart; c < cEnd; ++c) { 897 double ccoords[3] = {0.0, 0.0, 0.0}; 898 PetscBool isLabeled = PETSC_FALSE; 899 PetscInt *closure = NULL; 900 PetscInt closureSize, dof, d, n = 0; 901 902 if (wp && !PetscBTLookup(wp,c - pStart)) continue; 903 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 904 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 905 for (p = 0; p < closureSize*2; p += 2) { 906 const PetscInt point = closure[p]; 907 PetscInt off; 908 909 if ((point < vStart) || (point >= vEnd)) continue; 910 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 911 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 912 for (d = 0; d < dof; ++d) { 913 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 914 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 915 } 916 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 917 if (dof == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 918 for (d = 0; d < dof; ++d) {ccoords[d] += tcoords[d];} 919 ++n; 920 } 921 for (d = 0; d < dof; ++d) {ccoords[d] /= n;} 922 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 923 for (d = 0; d < dof; ++d) { 924 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 925 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double) ccoords[d]);CHKERRQ(ierr); 926 } 927 color = colors[rank%numColors]; 928 for (l = 0; l < numLabels; ++l) { 929 PetscInt val; 930 ierr = DMGetLabelValue(dm, names[l], c, &val);CHKERRQ(ierr); 931 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 932 } 933 if (useNumbers) { 934 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", c, rank, color, c);CHKERRQ(ierr); 935 } else { 936 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", c, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 937 } 938 } 939 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 940 /* Plot edges */ 941 if (plotEdges) { 942 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 943 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 944 for (e = eStart; e < eEnd; ++e) { 945 const PetscInt *cone; 946 PetscInt coneSize, offA, offB, dof, d; 947 948 if (wp && !PetscBTLookup(wp,e - pStart)) continue; 949 ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr); 950 if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize); 951 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 952 ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr); 953 ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr); 954 ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr); 955 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 956 for (d = 0; d < dof; ++d) { 957 tcoords[d] = (double) (0.5*scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 958 tcoords[d] = PetscAbs(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 959 } 960 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 961 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 962 for (d = 0; d < dof; ++d) { 963 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 964 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr); 965 } 966 color = colors[rank%numColors]; 967 for (l = 0; l < numLabels; ++l) { 968 PetscInt val; 969 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 970 if (val >= 0) {color = lcolors[l%numLColors]; break;} 971 } 972 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr); 973 } 974 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 975 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 976 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 977 } 978 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 979 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 980 ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr); 981 ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr); 982 for (l = 0; l < numLabels; ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);} 983 for (c = 0; c < numColors; ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);} 984 for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);} 985 ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr); 986 ierr = PetscBTDestroy(&wp);CHKERRQ(ierr); 987 } else if (format == PETSC_VIEWER_LOAD_BALANCE) { 988 Vec cown,acown; 989 VecScatter sct; 990 ISLocalToGlobalMapping g2l; 991 IS gid,acis; 992 MPI_Comm comm,ncomm = MPI_COMM_NULL; 993 MPI_Group ggroup,ngroup; 994 PetscScalar *array,nid; 995 const PetscInt *idxs; 996 PetscInt *idxs2,*start,*adjacency,*work; 997 PetscInt64 lm[3],gm[3]; 998 PetscInt i,c,cStart,cEnd,cum,numVertices,ect,ectn,cellHeight; 999 PetscMPIInt d1,d2,rank; 1000 1001 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 1002 ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr); 1003 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1004 ierr = MPI_Comm_split_type(comm,MPI_COMM_TYPE_SHARED,rank,MPI_INFO_NULL,&ncomm);CHKERRMPI(ierr); 1005 #endif 1006 if (ncomm != MPI_COMM_NULL) { 1007 ierr = MPI_Comm_group(comm,&ggroup);CHKERRMPI(ierr); 1008 ierr = MPI_Comm_group(ncomm,&ngroup);CHKERRMPI(ierr); 1009 d1 = 0; 1010 ierr = MPI_Group_translate_ranks(ngroup,1,&d1,ggroup,&d2);CHKERRMPI(ierr); 1011 nid = d2; 1012 ierr = MPI_Group_free(&ggroup);CHKERRMPI(ierr); 1013 ierr = MPI_Group_free(&ngroup);CHKERRMPI(ierr); 1014 ierr = MPI_Comm_free(&ncomm);CHKERRMPI(ierr); 1015 } else nid = 0.0; 1016 1017 /* Get connectivity */ 1018 ierr = DMPlexGetVTKCellHeight(dm,&cellHeight);CHKERRQ(ierr); 1019 ierr = DMPlexCreatePartitionerGraph(dm,cellHeight,&numVertices,&start,&adjacency,&gid);CHKERRQ(ierr); 1020 1021 /* filter overlapped local cells */ 1022 ierr = DMPlexGetHeightStratum(dm,cellHeight,&cStart,&cEnd);CHKERRQ(ierr); 1023 ierr = ISGetIndices(gid,&idxs);CHKERRQ(ierr); 1024 ierr = ISGetLocalSize(gid,&cum);CHKERRQ(ierr); 1025 ierr = PetscMalloc1(cum,&idxs2);CHKERRQ(ierr); 1026 for (c = cStart, cum = 0; c < cEnd; c++) { 1027 if (idxs[c-cStart] < 0) continue; 1028 idxs2[cum++] = idxs[c-cStart]; 1029 } 1030 ierr = ISRestoreIndices(gid,&idxs);CHKERRQ(ierr); 1031 if (numVertices != cum) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %D != %D",numVertices,cum); 1032 ierr = ISDestroy(&gid);CHKERRQ(ierr); 1033 ierr = ISCreateGeneral(comm,numVertices,idxs2,PETSC_OWN_POINTER,&gid);CHKERRQ(ierr); 1034 1035 /* support for node-aware cell locality */ 1036 ierr = ISCreateGeneral(comm,start[numVertices],adjacency,PETSC_USE_POINTER,&acis);CHKERRQ(ierr); 1037 ierr = VecCreateSeq(PETSC_COMM_SELF,start[numVertices],&acown);CHKERRQ(ierr); 1038 ierr = VecCreateMPI(comm,numVertices,PETSC_DECIDE,&cown);CHKERRQ(ierr); 1039 ierr = VecGetArray(cown,&array);CHKERRQ(ierr); 1040 for (c = 0; c < numVertices; c++) array[c] = nid; 1041 ierr = VecRestoreArray(cown,&array);CHKERRQ(ierr); 1042 ierr = VecScatterCreate(cown,acis,acown,NULL,&sct);CHKERRQ(ierr); 1043 ierr = VecScatterBegin(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1044 ierr = VecScatterEnd(sct,cown,acown,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1045 ierr = ISDestroy(&acis);CHKERRQ(ierr); 1046 ierr = VecScatterDestroy(&sct);CHKERRQ(ierr); 1047 ierr = VecDestroy(&cown);CHKERRQ(ierr); 1048 1049 /* compute edgeCut */ 1050 for (c = 0, cum = 0; c < numVertices; c++) cum = PetscMax(cum,start[c+1]-start[c]); 1051 ierr = PetscMalloc1(cum,&work);CHKERRQ(ierr); 1052 ierr = ISLocalToGlobalMappingCreateIS(gid,&g2l);CHKERRQ(ierr); 1053 ierr = ISLocalToGlobalMappingSetType(g2l,ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr); 1054 ierr = ISDestroy(&gid);CHKERRQ(ierr); 1055 ierr = VecGetArray(acown,&array);CHKERRQ(ierr); 1056 for (c = 0, ect = 0, ectn = 0; c < numVertices; c++) { 1057 PetscInt totl; 1058 1059 totl = start[c+1]-start[c]; 1060 ierr = ISGlobalToLocalMappingApply(g2l,IS_GTOLM_MASK,totl,adjacency+start[c],NULL,work);CHKERRQ(ierr); 1061 for (i = 0; i < totl; i++) { 1062 if (work[i] < 0) { 1063 ect += 1; 1064 ectn += (array[i + start[c]] != nid) ? 0 : 1; 1065 } 1066 } 1067 } 1068 ierr = PetscFree(work);CHKERRQ(ierr); 1069 ierr = VecRestoreArray(acown,&array);CHKERRQ(ierr); 1070 lm[0] = numVertices > 0 ? numVertices : PETSC_MAX_INT; 1071 lm[1] = -numVertices; 1072 ierr = MPIU_Allreduce(lm,gm,2,MPIU_INT64,MPI_MIN,comm);CHKERRMPI(ierr); 1073 ierr = PetscViewerASCIIPrintf(viewer," Cell balance: %.2f (max %D, min %D",-((double)gm[1])/((double)gm[0]),-(PetscInt)gm[1],(PetscInt)gm[0]);CHKERRQ(ierr); 1074 lm[0] = ect; /* edgeCut */ 1075 lm[1] = ectn; /* node-aware edgeCut */ 1076 lm[2] = numVertices > 0 ? 0 : 1; /* empty processes */ 1077 ierr = MPIU_Allreduce(lm,gm,3,MPIU_INT64,MPI_SUM,comm);CHKERRMPI(ierr); 1078 ierr = PetscViewerASCIIPrintf(viewer,", empty %D)\n",(PetscInt)gm[2]);CHKERRQ(ierr); 1079 #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY) 1080 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); 1081 #else 1082 ierr = PetscViewerASCIIPrintf(viewer," Edge Cut: %D (on node %.3f)\n",(PetscInt)(gm[0]/2),0.0);CHKERRQ(ierr); 1083 #endif 1084 ierr = ISLocalToGlobalMappingDestroy(&g2l);CHKERRQ(ierr); 1085 ierr = PetscFree(start);CHKERRQ(ierr); 1086 ierr = PetscFree(adjacency);CHKERRQ(ierr); 1087 ierr = VecDestroy(&acown);CHKERRQ(ierr); 1088 } else { 1089 const char *name; 1090 PetscInt *sizes, *hybsizes, *ghostsizes; 1091 PetscInt locDepth, depth, cellHeight, dim, d; 1092 PetscInt pStart, pEnd, p, gcStart, gcEnd, gcNum; 1093 PetscInt numLabels, l; 1094 DMPolytopeType ct0 = DM_POLYTOPE_UNKNOWN; 1095 MPI_Comm comm; 1096 PetscMPIInt size, rank; 1097 1098 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 1099 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 1100 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 1101 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1102 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1103 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 1104 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimension%s:\n", name, dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1105 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimension%s:\n", dim, dim == 1 ? "" : "s");CHKERRQ(ierr);} 1106 if (cellHeight) {ierr = PetscViewerASCIIPrintf(viewer, " Cells are at height %D\n", cellHeight);CHKERRQ(ierr);} 1107 ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr); 1108 ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRMPI(ierr); 1109 ierr = DMPlexGetGhostCellStratum(dm, &gcStart, &gcEnd);CHKERRQ(ierr); 1110 gcNum = gcEnd - gcStart; 1111 ierr = PetscCalloc3(size,&sizes,size,&hybsizes,size,&ghostsizes);CHKERRQ(ierr); 1112 for (d = 0; d <= depth; d++) { 1113 PetscInt Nc[2] = {0, 0}, ict; 1114 1115 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 1116 if (pStart < pEnd) {ierr = DMPlexGetCellType(dm, pStart, &ct0);CHKERRQ(ierr);} 1117 ict = ct0; 1118 ierr = MPI_Bcast(&ict, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr); 1119 ct0 = (DMPolytopeType) ict; 1120 for (p = pStart; p < pEnd; ++p) { 1121 DMPolytopeType ct; 1122 1123 ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr); 1124 if (ct == ct0) ++Nc[0]; 1125 else ++Nc[1]; 1126 } 1127 ierr = MPI_Gather(&Nc[0], 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr); 1128 ierr = MPI_Gather(&Nc[1], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr); 1129 if (d == depth) {ierr = MPI_Gather(&gcNum, 1, MPIU_INT, ghostsizes, 1, MPIU_INT, 0, comm);CHKERRMPI(ierr);} 1130 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", (depth == 1) && d ? dim : d);CHKERRQ(ierr); 1131 for (p = 0; p < size; ++p) { 1132 if (!rank) { 1133 ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]+hybsizes[p]);CHKERRQ(ierr); 1134 if (hybsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " (%D)", hybsizes[p]);CHKERRQ(ierr);} 1135 if (ghostsizes[p] > 0) {ierr = PetscViewerASCIIPrintf(viewer, " [%D]", ghostsizes[p]);CHKERRQ(ierr);} 1136 } 1137 } 1138 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 1139 } 1140 ierr = PetscFree3(sizes,hybsizes,ghostsizes);CHKERRQ(ierr); 1141 { 1142 const PetscReal *maxCell; 1143 const PetscReal *L; 1144 const DMBoundaryType *bd; 1145 PetscBool per, localized; 1146 1147 ierr = DMGetPeriodicity(dm, &per, &maxCell, &L, &bd);CHKERRQ(ierr); 1148 ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr); 1149 if (per) { 1150 ierr = PetscViewerASCIIPrintf(viewer, "Periodic mesh (");CHKERRQ(ierr); 1151 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 1152 for (d = 0; d < dim; ++d) { 1153 if (bd && d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 1154 if (bd) {ierr = PetscViewerASCIIPrintf(viewer, "%s", DMBoundaryTypes[bd[d]]);CHKERRQ(ierr);} 1155 } 1156 ierr = PetscViewerASCIIPrintf(viewer, ") coordinates %s\n", localized ? "localized" : "not localized");CHKERRQ(ierr); 1157 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 1158 } 1159 } 1160 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 1161 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 1162 for (l = 0; l < numLabels; ++l) { 1163 DMLabel label; 1164 const char *name; 1165 IS valueIS; 1166 const PetscInt *values; 1167 PetscInt numValues, v; 1168 1169 ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr); 1170 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1171 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 1172 ierr = PetscViewerASCIIPrintf(viewer, " %s: %D strata with value/size (", name, numValues);CHKERRQ(ierr); 1173 ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr); 1174 ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr); 1175 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 1176 for (v = 0; v < numValues; ++v) { 1177 PetscInt size; 1178 1179 ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr); 1180 if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 1181 ierr = PetscViewerASCIIPrintf(viewer, "%D (%D)", values[v], size);CHKERRQ(ierr); 1182 } 1183 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 1184 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 1185 ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr); 1186 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 1187 } 1188 /* If no fields are specified, people do not want to see adjacency */ 1189 if (dm->Nf) { 1190 PetscInt f; 1191 1192 for (f = 0; f < dm->Nf; ++f) { 1193 const char *name; 1194 1195 ierr = PetscObjectGetName(dm->fields[f].disc, &name);CHKERRQ(ierr); 1196 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Field %s:\n", name);CHKERRQ(ierr);} 1197 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1198 if (dm->fields[f].label) {ierr = DMLabelView(dm->fields[f].label, viewer);CHKERRQ(ierr);} 1199 if (dm->fields[f].adjacency[0]) { 1200 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM++\n");CHKERRQ(ierr);} 1201 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FVM\n");CHKERRQ(ierr);} 1202 } else { 1203 if (dm->fields[f].adjacency[1]) {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FEM\n");CHKERRQ(ierr);} 1204 else {ierr = PetscViewerASCIIPrintf(viewer, "adjacency FUNKY\n");CHKERRQ(ierr);} 1205 } 1206 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1207 } 1208 } 1209 ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr); 1210 if (cdm) { 1211 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 1212 ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr); 1213 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 1214 } 1215 } 1216 PetscFunctionReturn(0); 1217 } 1218 1219 static PetscErrorCode DMPlexDrawCell(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[]) 1220 { 1221 DMPolytopeType ct; 1222 PetscMPIInt rank; 1223 PetscErrorCode ierr; 1224 1225 PetscFunctionBegin; 1226 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr); 1227 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 1228 switch (ct) { 1229 case DM_POLYTOPE_TRIANGLE: 1230 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1231 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1232 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1233 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1234 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1235 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1236 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1237 break; 1238 case DM_POLYTOPE_QUADRILATERAL: 1239 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), 1240 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1241 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1242 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1243 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), 1244 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1245 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2, 1246 PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2);CHKERRQ(ierr); 1247 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1248 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1249 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1250 ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 1251 break; 1252 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1253 } 1254 PetscFunctionReturn(0); 1255 } 1256 1257 static PetscErrorCode DMPlexDrawCellHighOrder(DM dm, PetscDraw draw, PetscInt cell, const PetscScalar coords[], PetscInt edgeDiv, PetscReal refCoords[], PetscReal edgeCoords[]) 1258 { 1259 DMPolytopeType ct; 1260 PetscReal centroid[2] = {0., 0.}; 1261 PetscMPIInt rank; 1262 PetscInt fillColor, v, e, d; 1263 PetscErrorCode ierr; 1264 1265 PetscFunctionBegin; 1266 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr); 1267 ierr = DMPlexGetCellType(dm, cell, &ct);CHKERRQ(ierr); 1268 fillColor = PETSC_DRAW_WHITE + rank % (PETSC_DRAW_BASIC_COLORS-2) + 2; 1269 switch (ct) { 1270 case DM_POLYTOPE_TRIANGLE: 1271 { 1272 PetscReal refVertices[6] = {-1., -1., 1., -1., -1., 1.}; 1273 1274 for (v = 0; v < 3; ++v) {centroid[0] += PetscRealPart(coords[v*2+0])/3.;centroid[1] += PetscRealPart(coords[v*2+1])/3.;} 1275 for (e = 0; e < 3; ++e) { 1276 refCoords[0] = refVertices[e*2+0]; 1277 refCoords[1] = refVertices[e*2+1]; 1278 for (d = 1; d <= edgeDiv; ++d) { 1279 refCoords[d*2+0] = refCoords[0] + (refVertices[(e+1)%3 * 2 + 0] - refCoords[0])*d/edgeDiv; 1280 refCoords[d*2+1] = refCoords[1] + (refVertices[(e+1)%3 * 2 + 1] - refCoords[1])*d/edgeDiv; 1281 } 1282 ierr = DMPlexReferenceToCoordinates(dm, cell, edgeDiv+1, refCoords, edgeCoords);CHKERRQ(ierr); 1283 for (d = 0; d < edgeDiv; ++d) { 1284 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); 1285 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); 1286 } 1287 } 1288 } 1289 break; 1290 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells of type %s", DMPolytopeTypes[ct]); 1291 } 1292 PetscFunctionReturn(0); 1293 } 1294 1295 static PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 1296 { 1297 PetscDraw draw; 1298 DM cdm; 1299 PetscSection coordSection; 1300 Vec coordinates; 1301 const PetscScalar *coords; 1302 PetscReal xyl[2],xyr[2],bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 1303 PetscReal *refCoords, *edgeCoords; 1304 PetscBool isnull, drawAffine = PETSC_TRUE; 1305 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, edgeDiv = 4; 1306 PetscErrorCode ierr; 1307 1308 PetscFunctionBegin; 1309 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 1310 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 1311 ierr = PetscOptionsGetBool(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_view_draw_affine", &drawAffine, NULL);CHKERRQ(ierr); 1312 if (!drawAffine) {ierr = PetscMalloc2((edgeDiv+1)*dim, &refCoords, (edgeDiv+1)*dim, &edgeCoords);CHKERRQ(ierr);} 1313 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 1314 ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr); 1315 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 1316 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1317 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1318 1319 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 1320 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 1321 if (isnull) PetscFunctionReturn(0); 1322 ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr); 1323 1324 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 1325 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 1326 for (c = 0; c < N; c += dim) { 1327 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 1328 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 1329 } 1330 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 1331 ierr = MPIU_Allreduce(&bound[0],xyl,2,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr); 1332 ierr = MPIU_Allreduce(&bound[2],xyr,2,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr); 1333 ierr = PetscDrawSetCoordinates(draw, xyl[0], xyl[1], xyr[0], xyr[1]);CHKERRQ(ierr); 1334 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 1335 1336 for (c = cStart; c < cEnd; ++c) { 1337 PetscScalar *coords = NULL; 1338 PetscInt numCoords; 1339 1340 ierr = DMPlexVecGetClosureAtDepth_Internal(dm, coordSection, coordinates, c, 0, &numCoords, &coords);CHKERRQ(ierr); 1341 if (drawAffine) { 1342 ierr = DMPlexDrawCell(dm, draw, c, coords);CHKERRQ(ierr); 1343 } else { 1344 ierr = DMPlexDrawCellHighOrder(dm, draw, c, coords, edgeDiv, refCoords, edgeCoords);CHKERRQ(ierr); 1345 } 1346 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 1347 } 1348 if (!drawAffine) {ierr = PetscFree2(refCoords, edgeCoords);CHKERRQ(ierr);} 1349 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 1350 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 1351 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 1352 PetscFunctionReturn(0); 1353 } 1354 1355 #if defined(PETSC_HAVE_EXODUSII) 1356 #include <exodusII.h> 1357 #include <petscviewerexodusii.h> 1358 #endif 1359 1360 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 1361 { 1362 PetscBool iascii, ishdf5, isvtk, isdraw, flg, isglvis, isexodus; 1363 char name[PETSC_MAX_PATH_LEN]; 1364 PetscErrorCode ierr; 1365 1366 PetscFunctionBegin; 1367 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1368 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1369 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1370 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 1371 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1372 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 1373 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr); 1374 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWEREXODUSII, &isexodus);CHKERRQ(ierr); 1375 if (iascii) { 1376 PetscViewerFormat format; 1377 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1378 if (format == PETSC_VIEWER_ASCII_GLVIS) { 1379 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1380 } else { 1381 ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr); 1382 } 1383 } else if (ishdf5) { 1384 #if defined(PETSC_HAVE_HDF5) 1385 ierr = DMPlexView_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1386 #else 1387 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1388 #endif 1389 } else if (isvtk) { 1390 ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr); 1391 } else if (isdraw) { 1392 ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr); 1393 } else if (isglvis) { 1394 ierr = DMPlexView_GLVis(dm, viewer);CHKERRQ(ierr); 1395 #if defined(PETSC_HAVE_EXODUSII) 1396 } else if (isexodus) { 1397 /* 1398 exodusII requires that all sets be part of exactly one cell set. 1399 If the dm does not have a "Cell Sets" label defined, we create one 1400 with ID 1, containig all cells. 1401 Note that if the Cell Sets label is defined but does not cover all cells, 1402 we may still have a problem. This should probably be checked here or in the viewer; 1403 */ 1404 PetscInt numCS; 1405 ierr = DMGetLabelSize(dm,"Cell Sets",&numCS);CHKERRQ(ierr); 1406 if (!numCS) { 1407 PetscInt cStart, cEnd, c; 1408 ierr = DMCreateLabel(dm, "Cell Sets");CHKERRQ(ierr); 1409 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1410 for (c = cStart; c < cEnd; ++c) {ierr = DMSetLabelValue(dm, "Cell Sets", c, 1);CHKERRQ(ierr);} 1411 } 1412 ierr = DMView_PlexExodusII(dm, viewer);CHKERRQ(ierr); 1413 #endif 1414 } else { 1415 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex writing", ((PetscObject)viewer)->type_name); 1416 } 1417 /* Optionally view the partition */ 1418 ierr = PetscOptionsHasName(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_partition_view", &flg);CHKERRQ(ierr); 1419 if (flg) { 1420 Vec ranks; 1421 ierr = DMPlexCreateRankField(dm, &ranks);CHKERRQ(ierr); 1422 ierr = VecView(ranks, viewer);CHKERRQ(ierr); 1423 ierr = VecDestroy(&ranks);CHKERRQ(ierr); 1424 } 1425 /* Optionally view a label */ 1426 ierr = PetscOptionsGetString(((PetscObject) dm)->options, ((PetscObject) dm)->prefix, "-dm_label_view", name, sizeof(name), &flg);CHKERRQ(ierr); 1427 if (flg) { 1428 DMLabel label; 1429 Vec val; 1430 1431 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 1432 if (!label) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %s provided to -dm_label_view does not exist in this DM", name); 1433 ierr = DMPlexCreateLabelField(dm, label, &val);CHKERRQ(ierr); 1434 ierr = VecView(val, viewer);CHKERRQ(ierr); 1435 ierr = VecDestroy(&val);CHKERRQ(ierr); 1436 } 1437 PetscFunctionReturn(0); 1438 } 1439 1440 /*@ 1441 DMPlexTopologyView - Saves a DMPlex topology into a file 1442 1443 Collective on DM 1444 1445 Input Parameters: 1446 + dm - The DM whose topology is to be saved 1447 - viewer - The PetscViewer for saving 1448 1449 Level: advanced 1450 1451 .seealso: DMView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexTopologyLoad() 1452 @*/ 1453 PetscErrorCode DMPlexTopologyView(DM dm, PetscViewer viewer) 1454 { 1455 PetscBool ishdf5; 1456 PetscErrorCode ierr; 1457 1458 PetscFunctionBegin; 1459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1460 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1461 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1462 if (ishdf5) { 1463 #if defined(PETSC_HAVE_HDF5) 1464 PetscViewerFormat format; 1465 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1466 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1467 IS globalPointNumbering; 1468 1469 ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr); 1470 ierr = DMPlexTopologyView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr); 1471 ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr); 1472 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 output.", PetscViewerFormats[format]); 1473 #else 1474 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1475 #endif 1476 } 1477 PetscFunctionReturn(0); 1478 } 1479 1480 /*@ 1481 DMPlexCoordinatesView - Saves DMPlex coordinates into a file 1482 1483 Collective on DM 1484 1485 Input Parameters: 1486 + dm - The DM whose coordinates are to be saved 1487 - viewer - The PetscViewer for saving 1488 1489 Level: advanced 1490 1491 .seealso: DMView(), DMPlexTopologyView(), DMPlexLabelsView(), DMPlexCoordinatesLoad() 1492 @*/ 1493 PetscErrorCode DMPlexCoordinatesView(DM dm, PetscViewer viewer) 1494 { 1495 PetscBool ishdf5; 1496 PetscErrorCode ierr; 1497 1498 PetscFunctionBegin; 1499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1500 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1501 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1502 if (ishdf5) { 1503 #if defined(PETSC_HAVE_HDF5) 1504 PetscViewerFormat format; 1505 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1506 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1507 ierr = DMPlexCoordinatesView_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1508 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1509 #else 1510 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1511 #endif 1512 } 1513 PetscFunctionReturn(0); 1514 } 1515 1516 /*@ 1517 DMPlexLabelsView - Saves DMPlex labels into a file 1518 1519 Collective on DM 1520 1521 Input Parameters: 1522 + dm - The DM whose labels are to be saved 1523 - viewer - The PetscViewer for saving 1524 1525 Level: advanced 1526 1527 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsLoad() 1528 @*/ 1529 PetscErrorCode DMPlexLabelsView(DM dm, PetscViewer viewer) 1530 { 1531 PetscBool ishdf5; 1532 PetscErrorCode ierr; 1533 1534 PetscFunctionBegin; 1535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1536 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1537 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1538 if (ishdf5) { 1539 #if defined(PETSC_HAVE_HDF5) 1540 IS globalPointNumbering; 1541 PetscViewerFormat format; 1542 1543 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1544 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1545 ierr = DMPlexCreatePointNumbering(dm, &globalPointNumbering);CHKERRQ(ierr); 1546 ierr = DMPlexLabelsView_HDF5_Internal(dm, globalPointNumbering, viewer);CHKERRQ(ierr); 1547 ierr = ISDestroy(&globalPointNumbering);CHKERRQ(ierr); 1548 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1549 #else 1550 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1551 #endif 1552 } 1553 PetscFunctionReturn(0); 1554 } 1555 1556 /*@ 1557 DMPlexSectionView - Saves a section associated with a DMPlex 1558 1559 Collective on DM 1560 1561 Input Parameters: 1562 + dm - The DM that contains the topology on which the section to be saved is defined 1563 . viewer - The PetscViewer for saving 1564 - sectiondm - The DM that contains the section to be saved 1565 1566 Level: advanced 1567 1568 Notes: 1569 This function is a wrapper around PetscSectionView(); in addition to the raw section, it saves information that associates the section points to the topology (dm) points. When the topology (dm) and the section are later loaded with DMPlexTopologyLoad() and DMPlexSectionLoad(), respectively, this information is used to match section points with topology points. 1570 1571 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1572 1573 .seealso: DMView(), DMPlexTopologyView(), DMPlexCoordinatesView(), DMPlexLabelsView(), DMPlexGlobalVectorView(), DMPlexLocalVectorView(), PetscSectionView(), DMPlexSectionLoad() 1574 @*/ 1575 PetscErrorCode DMPlexSectionView(DM dm, PetscViewer viewer, DM sectiondm) 1576 { 1577 PetscBool ishdf5; 1578 PetscErrorCode ierr; 1579 1580 PetscFunctionBegin; 1581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1582 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1583 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1584 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr); 1585 if (ishdf5) { 1586 #if defined(PETSC_HAVE_HDF5) 1587 ierr = DMPlexSectionView_HDF5_Internal(dm, viewer, sectiondm);CHKERRQ(ierr); 1588 #else 1589 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1590 #endif 1591 } 1592 PetscFunctionReturn(0); 1593 } 1594 1595 /*@ 1596 DMPlexGlobalVectorView - Saves a global vector 1597 1598 Collective on DM 1599 1600 Input Parameters: 1601 + dm - The DM that represents the topology 1602 . viewer - The PetscViewer to save data with 1603 . sectiondm - The DM that contains the global section on which vec is defined 1604 - vec - The global vector to be saved 1605 1606 Level: advanced 1607 1608 Notes: 1609 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1610 1611 Typical calling sequence 1612 $ DMCreate(PETSC_COMM_WORLD, &dm); 1613 $ DMSetType(dm, DMPLEX); 1614 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1615 $ DMClone(dm, §iondm); 1616 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1617 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1618 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1619 $ PetscSectionSetChart(section, pStart, pEnd); 1620 $ PetscSectionSetUp(section); 1621 $ DMSetLocalSection(sectiondm, section); 1622 $ PetscSectionDestroy(§ion); 1623 $ DMGetGlobalVector(sectiondm, &vec); 1624 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1625 $ DMPlexTopologyView(dm, viewer); 1626 $ DMPlexSectionView(dm, viewer, sectiondm); 1627 $ DMPlexGlobalVectorView(dm, viewer, sectiondm, vec); 1628 $ DMRestoreGlobalVector(sectiondm, &vec); 1629 $ DMDestroy(§iondm); 1630 $ DMDestroy(&dm); 1631 1632 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexLocalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 1633 @*/ 1634 PetscErrorCode DMPlexGlobalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1635 { 1636 PetscBool ishdf5; 1637 PetscErrorCode ierr; 1638 1639 PetscFunctionBegin; 1640 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1641 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1642 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1643 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1644 /* Check consistency */ 1645 { 1646 PetscSection section; 1647 PetscBool includesConstraints; 1648 PetscInt m, m1; 1649 1650 ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr); 1651 ierr = DMGetGlobalSection(sectiondm, §ion);CHKERRQ(ierr); 1652 ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr); 1653 if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);} 1654 else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);} 1655 if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Global vector size (%D) != global section storage size (%D)", m1, m); 1656 } 1657 ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1658 if (ishdf5) { 1659 #if defined(PETSC_HAVE_HDF5) 1660 ierr = DMPlexGlobalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr); 1661 #else 1662 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1663 #endif 1664 } 1665 PetscFunctionReturn(0); 1666 } 1667 1668 /*@ 1669 DMPlexLocalVectorView - Saves a local vector 1670 1671 Collective on DM 1672 1673 Input Parameters: 1674 + dm - The DM that represents the topology 1675 . viewer - The PetscViewer to save data with 1676 . sectiondm - The DM that contains the local section on which vec is defined; may be the same as dm 1677 - vec - The local vector to be saved 1678 1679 Level: advanced 1680 1681 Notes: 1682 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1683 1684 Typical calling sequence 1685 $ DMCreate(PETSC_COMM_WORLD, &dm); 1686 $ DMSetType(dm, DMPLEX); 1687 $ PetscObjectSetName((PetscObject)dm, "topologydm_name"); 1688 $ DMClone(dm, §iondm); 1689 $ PetscObjectSetName((PetscObject)sectiondm, "sectiondm_name"); 1690 $ PetscSectionCreate(PETSC_COMM_WORLD, §ion); 1691 $ DMPlexGetChart(sectiondm, &pStart, &pEnd); 1692 $ PetscSectionSetChart(section, pStart, pEnd); 1693 $ PetscSectionSetUp(section); 1694 $ DMSetLocalSection(sectiondm, section); 1695 $ DMGetLocalVector(sectiondm, &vec); 1696 $ PetscObjectSetName((PetscObject)vec, "vec_name"); 1697 $ DMPlexTopologyView(dm, viewer); 1698 $ DMPlexSectionView(dm, viewer, sectiondm); 1699 $ DMPlexLocalVectorView(dm, viewer, sectiondm, vec); 1700 $ DMRestoreLocalVector(sectiondm, &vec); 1701 $ DMDestroy(§iondm); 1702 $ DMDestroy(&dm); 1703 1704 .seealso: DMPlexTopologyView(), DMPlexSectionView(), DMPlexGlobalVectorView(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad() 1705 @*/ 1706 PetscErrorCode DMPlexLocalVectorView(DM dm, PetscViewer viewer, DM sectiondm, Vec vec) 1707 { 1708 PetscBool ishdf5; 1709 PetscErrorCode ierr; 1710 1711 PetscFunctionBegin; 1712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1713 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1714 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1715 PetscValidHeaderSpecific(vec, VEC_CLASSID, 4); 1716 /* Check consistency */ 1717 { 1718 PetscSection section; 1719 PetscBool includesConstraints; 1720 PetscInt m, m1; 1721 1722 ierr = VecGetLocalSize(vec, &m1);CHKERRQ(ierr); 1723 ierr = DMGetLocalSection(sectiondm, §ion);CHKERRQ(ierr); 1724 ierr = PetscSectionGetIncludesConstraints(section, &includesConstraints);CHKERRQ(ierr); 1725 if (includesConstraints) {ierr = PetscSectionGetStorageSize(section, &m);CHKERRQ(ierr);} 1726 else {ierr = PetscSectionGetConstrainedStorageSize(section, &m);CHKERRQ(ierr);} 1727 if (m1 != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local vector size (%D) != local section storage size (%D)", m1, m); 1728 } 1729 ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1730 if (ishdf5) { 1731 #if defined(PETSC_HAVE_HDF5) 1732 ierr = DMPlexLocalVectorView_HDF5_Internal(dm, viewer, sectiondm, vec);CHKERRQ(ierr); 1733 #else 1734 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1735 #endif 1736 } 1737 PetscFunctionReturn(0); 1738 } 1739 1740 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 1741 { 1742 PetscBool ishdf5; 1743 PetscErrorCode ierr; 1744 1745 PetscFunctionBegin; 1746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1747 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1748 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1749 if (ishdf5) { 1750 #if defined(PETSC_HAVE_HDF5) 1751 PetscViewerFormat format; 1752 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1753 if (format == PETSC_VIEWER_HDF5_XDMF || format == PETSC_VIEWER_HDF5_VIZ) { 1754 ierr = DMPlexLoad_HDF5_Xdmf_Internal(dm, viewer);CHKERRQ(ierr); 1755 } else if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1756 ierr = DMPlexLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1757 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1758 PetscFunctionReturn(0); 1759 #else 1760 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1761 #endif 1762 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlex loading", ((PetscObject)viewer)->type_name); 1763 } 1764 1765 /*@ 1766 DMPlexTopologyLoad - Loads a topology into a DMPlex 1767 1768 Collective on DM 1769 1770 Input Parameters: 1771 + dm - The DM into which the topology is loaded 1772 - viewer - The PetscViewer for the saved topology 1773 1774 Output Parameters: 1775 . globalToLocalPointSF - 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 1776 1777 Level: advanced 1778 1779 .seealso: DMLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 1780 @*/ 1781 PetscErrorCode DMPlexTopologyLoad(DM dm, PetscViewer viewer, PetscSF *globalToLocalPointSF) 1782 { 1783 PetscBool ishdf5; 1784 PetscErrorCode ierr; 1785 1786 PetscFunctionBegin; 1787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1788 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1789 if (globalToLocalPointSF) PetscValidPointer(globalToLocalPointSF, 3); 1790 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1791 if (ishdf5) { 1792 #if defined(PETSC_HAVE_HDF5) 1793 PetscViewerFormat format; 1794 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1795 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1796 ierr = DMPlexTopologyLoad_HDF5_Internal(dm, viewer, globalToLocalPointSF);CHKERRQ(ierr); 1797 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1798 #else 1799 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1800 #endif 1801 } 1802 PetscFunctionReturn(0); 1803 } 1804 1805 /*@ 1806 DMPlexCoordinatesLoad - Loads coordinates into a DMPlex 1807 1808 Collective on DM 1809 1810 Input Parameters: 1811 + dm - The DM into which the coordinates are loaded 1812 - viewer - The PetscViewer for the saved coordinates 1813 1814 Level: advanced 1815 1816 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexLabelsLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 1817 @*/ 1818 PetscErrorCode DMPlexCoordinatesLoad(DM dm, PetscViewer viewer) 1819 { 1820 PetscBool ishdf5; 1821 PetscErrorCode ierr; 1822 1823 PetscFunctionBegin; 1824 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1825 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1826 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1827 if (ishdf5) { 1828 #if defined(PETSC_HAVE_HDF5) 1829 PetscViewerFormat format; 1830 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1831 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1832 ierr = DMPlexCoordinatesLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1833 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1834 #else 1835 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1836 #endif 1837 } 1838 PetscFunctionReturn(0); 1839 } 1840 1841 /*@ 1842 DMPlexLabelsLoad - Loads labels into a DMPlex 1843 1844 Collective on DM 1845 1846 Input Parameters: 1847 + dm - The DM into which the labels are loaded 1848 - viewer - The PetscViewer for the saved labels 1849 1850 Level: advanced 1851 1852 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMView(), PetscViewerHDF5Open(), PetscViewerPushFormat() 1853 @*/ 1854 PetscErrorCode DMPlexLabelsLoad(DM dm, PetscViewer viewer) 1855 { 1856 PetscBool ishdf5; 1857 PetscErrorCode ierr; 1858 1859 PetscFunctionBegin; 1860 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1861 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1862 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 1863 if (ishdf5) { 1864 #if defined(PETSC_HAVE_HDF5) 1865 PetscViewerFormat format; 1866 1867 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1868 if (format == PETSC_VIEWER_HDF5_PETSC || format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_NATIVE) { 1869 ierr = DMPlexLabelsLoad_HDF5_Internal(dm, viewer);CHKERRQ(ierr); 1870 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "PetscViewerFormat %s not supported for HDF5 input.", PetscViewerFormats[format]); 1871 #else 1872 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1873 #endif 1874 } 1875 PetscFunctionReturn(0); 1876 } 1877 1878 /*@ 1879 DMPlexSectionLoad - Loads section into a DMPlex 1880 1881 Collective on DM 1882 1883 Input Parameters: 1884 + dm - The DM that represents the topology 1885 . viewer - The PetscViewer that represents the on-disk section (sectionA) 1886 . sectiondm - The DM into which the on-disk section (sectionA) is migrated 1887 - globalToLocalPointSF - The SF returned by DMPlexTopologyLoad() when loading dm from viewer 1888 1889 Output Parameters 1890 + globalDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a global Vec associated with the sectiondm's global section (NULL if not needed) 1891 - localDofSF - The SF that migrates any on-disk Vec data associated with sectionA into a local Vec associated with the sectiondm's local section (NULL if not needed) 1892 1893 Level: advanced 1894 1895 Notes: 1896 This function is a wrapper around PetscSectionLoad(); it loads, in addition to the raw section, a list of global point numbers that associates each on-disk section point with a global point number in [0, NX), where NX is the number of topology points in dm. Noting that globalToLocalPointSF associates each topology point in dm with a global number in [0, NX), one can readily establish an association of the on-disk section points with the topology points. 1897 1898 In general dm and sectiondm are two different objects, the former carrying the topology and the latter carrying the section, and have been given a topology name and a section name, respectively, with PetscObjectSetName(). In practice, however, they can be the same object if it carries both topology and section; in that case the name of the object is used as both the topology name and the section name. 1899 1900 The output parameter, globalDofSF (localDofSF), can later be used with DMPlexGlobalVectorLoad() (DMPlexLocalVectorLoad()) to load on-disk vectors into global (local) vectors associated with sectiondm's global (local) section. 1901 1902 Example using 2 processes: 1903 $ NX (number of points on dm): 4 1904 $ sectionA : the on-disk section 1905 $ vecA : a vector associated with sectionA 1906 $ sectionB : sectiondm's local section constructed in this function 1907 $ vecB (local) : a vector associated with sectiondm's local section 1908 $ vecB (global) : a vector associated with sectiondm's global section 1909 $ 1910 $ rank 0 rank 1 1911 $ vecA (global) : [.0 .4 .1 | .2 .3] <- to be loaded in DMPlexGlobalVectorLoad() or DMPlexLocalVectorLoad() 1912 $ sectionA->atlasOff : 0 2 | 1 <- loaded in PetscSectionLoad() 1913 $ sectionA->atlasDof : 1 3 | 1 <- loaded in PetscSectionLoad() 1914 $ sectionA's global point numbers: 0 2 | 3 <- loaded in DMPlexSectionLoad() 1915 $ [0, NX) : 0 1 | 2 3 <- conceptual partition used in globalToLocalPointSF 1916 $ sectionB's global point numbers: 0 1 3 | 3 2 <- associated with [0, NX) by globalToLocalPointSF 1917 $ sectionB->atlasDof : 1 0 1 | 1 3 1918 $ sectionB->atlasOff (no perm) : 0 1 1 | 0 1 1919 $ vecB (local) : [.0 .4] | [.4 .1 .2 .3] <- to be constructed by calling DMPlexLocalVectorLoad() with localDofSF 1920 $ vecB (global) : [.0 .4 | .1 .2 .3] <- to be constructed by calling DMPlexGlobalVectorLoad() with globalDofSF 1921 $ 1922 $ where "|" represents a partition of loaded data, and global point 3 is assumed to be owned by rank 0. 1923 1924 .seealso: DMLoad(), DMPlexTopologyLoad(), DMPlexCoordinatesLoad(), DMPlexLabelsLoad(), DMPlexGlobalVectorLoad(), DMPlexLocalVectorLoad(), PetscSectionLoad(), DMPlexSectionView() 1925 @*/ 1926 PetscErrorCode DMPlexSectionLoad(DM dm, PetscViewer viewer, DM sectiondm, PetscSF globalToLocalPointSF, PetscSF *globalDofSF, PetscSF *localDofSF) 1927 { 1928 PetscBool ishdf5; 1929 PetscErrorCode ierr; 1930 1931 PetscFunctionBegin; 1932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1933 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1934 PetscValidHeaderSpecific(sectiondm, DM_CLASSID, 3); 1935 PetscValidHeaderSpecific(globalToLocalPointSF, PETSCSF_CLASSID, 4); 1936 if (globalDofSF) PetscValidPointer(globalDofSF, 5); 1937 if (localDofSF) PetscValidPointer(localDofSF, 6); 1938 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr); 1939 if (ishdf5) { 1940 #if defined(PETSC_HAVE_HDF5) 1941 ierr = DMPlexSectionLoad_HDF5_Internal(dm, viewer, sectiondm, globalToLocalPointSF, globalDofSF, localDofSF);CHKERRQ(ierr); 1942 #else 1943 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 1944 #endif 1945 } 1946 PetscFunctionReturn(0); 1947 } 1948 1949 PetscErrorCode DMDestroy_Plex(DM dm) 1950 { 1951 DM_Plex *mesh = (DM_Plex*) dm->data; 1952 PetscErrorCode ierr; 1953 1954 PetscFunctionBegin; 1955 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL);CHKERRQ(ierr); 1956 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexInsertBoundaryValues_C", NULL);CHKERRQ(ierr); 1957 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C", NULL);CHKERRQ(ierr); 1958 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMInterpolateSolution_C", NULL);CHKERRQ(ierr); 1959 if (--mesh->refct > 0) PetscFunctionReturn(0); 1960 ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr); 1961 ierr = PetscFree(mesh->cones);CHKERRQ(ierr); 1962 ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr); 1963 ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); 1964 ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr); 1965 ierr = PetscFree(mesh->supports);CHKERRQ(ierr); 1966 ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr); 1967 ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr); 1968 ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr); 1969 ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); 1970 ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr); 1971 ierr = ISDestroy(&mesh->subpointIS);CHKERRQ(ierr); 1972 ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr); 1973 ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr); 1974 ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr); 1975 ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr); 1976 ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr); 1977 ierr = PetscFree(mesh->parents);CHKERRQ(ierr); 1978 ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr); 1979 ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr); 1980 ierr = PetscFree(mesh->children);CHKERRQ(ierr); 1981 ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr); 1982 ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr); 1983 ierr = PetscFree(mesh->neighbors);CHKERRQ(ierr); 1984 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 1985 ierr = PetscFree(mesh);CHKERRQ(ierr); 1986 PetscFunctionReturn(0); 1987 } 1988 1989 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 1990 { 1991 PetscSection sectionGlobal; 1992 PetscInt bs = -1, mbs; 1993 PetscInt localSize; 1994 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 1995 PetscErrorCode ierr; 1996 MatType mtype; 1997 ISLocalToGlobalMapping ltog; 1998 1999 PetscFunctionBegin; 2000 ierr = MatInitializePackage();CHKERRQ(ierr); 2001 mtype = dm->mattype; 2002 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 2003 /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */ 2004 ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); 2005 ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr); 2006 ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 2007 ierr = MatSetType(*J, mtype);CHKERRQ(ierr); 2008 ierr = MatSetFromOptions(*J);CHKERRQ(ierr); 2009 ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr); 2010 if (mbs > 1) bs = mbs; 2011 ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr); 2012 ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr); 2013 ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr); 2014 ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr); 2015 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 2016 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 2017 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 2018 ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr); 2019 if (!isShell) { 2020 PetscSection subSection; 2021 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 2022 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal[2], bsMinMax[2], *ltogidx, lsize; 2023 PetscInt pStart, pEnd, p, dof, cdof; 2024 2025 /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */ 2026 if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */ 2027 PetscSection section; 2028 PetscInt size; 2029 2030 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 2031 ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr); 2032 ierr = PetscMalloc1(size,<ogidx);CHKERRQ(ierr); 2033 ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr); 2034 } else { 2035 ierr = DMGetLocalToGlobalMapping(dm,<og);CHKERRQ(ierr); 2036 } 2037 ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr); 2038 for (p = pStart, lsize = 0; p < pEnd; ++p) { 2039 PetscInt bdof; 2040 2041 ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr); 2042 ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr); 2043 dof = dof < 0 ? -(dof+1) : dof; 2044 bdof = cdof && (dof-cdof) ? 1 : dof; 2045 if (dof) { 2046 if (bs < 0) {bs = bdof;} 2047 else if (bs != bdof) {bs = 1; if (!isMatIS) break;} 2048 } 2049 if (isMatIS) { 2050 PetscInt loff,c,off; 2051 ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr); 2052 ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr); 2053 for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c; 2054 } 2055 } 2056 /* Must have same blocksize on all procs (some might have no points) */ 2057 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 2058 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 2059 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 2060 else {bs = bsMinMax[0];} 2061 bs = PetscMax(1,bs); 2062 if (isMatIS) { /* Must reduce indices by blocksize */ 2063 PetscInt l; 2064 2065 lsize = lsize/bs; 2066 if (bs > 1) for (l = 0; l < lsize; ++l) ltogidx[l] = ltogidx[l*bs]/bs; 2067 ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);CHKERRQ(ierr); 2068 } 2069 ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr); 2070 if (isMatIS) { 2071 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 2072 } 2073 ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr); 2074 ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr); 2075 ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr); 2076 } 2077 ierr = MatSetDM(*J, dm);CHKERRQ(ierr); 2078 PetscFunctionReturn(0); 2079 } 2080 2081 /*@ 2082 DMPlexGetSubdomainSection - Returns the section associated with the subdomain 2083 2084 Not collective 2085 2086 Input Parameter: 2087 . mesh - The DMPlex 2088 2089 Output Parameters: 2090 . subsection - The subdomain section 2091 2092 Level: developer 2093 2094 .seealso: 2095 @*/ 2096 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 2097 { 2098 DM_Plex *mesh = (DM_Plex*) dm->data; 2099 PetscErrorCode ierr; 2100 2101 PetscFunctionBegin; 2102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2103 if (!mesh->subdomainSection) { 2104 PetscSection section; 2105 PetscSF sf; 2106 2107 ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr); 2108 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 2109 ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr); 2110 ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); 2111 } 2112 *subsection = mesh->subdomainSection; 2113 PetscFunctionReturn(0); 2114 } 2115 2116 /*@ 2117 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 2118 2119 Not collective 2120 2121 Input Parameter: 2122 . mesh - The DMPlex 2123 2124 Output Parameters: 2125 + pStart - The first mesh point 2126 - pEnd - The upper bound for mesh points 2127 2128 Level: beginner 2129 2130 .seealso: DMPlexCreate(), DMPlexSetChart() 2131 @*/ 2132 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 2133 { 2134 DM_Plex *mesh = (DM_Plex*) dm->data; 2135 PetscErrorCode ierr; 2136 2137 PetscFunctionBegin; 2138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2139 ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 2140 PetscFunctionReturn(0); 2141 } 2142 2143 /*@ 2144 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 2145 2146 Not collective 2147 2148 Input Parameters: 2149 + mesh - The DMPlex 2150 . pStart - The first mesh point 2151 - pEnd - The upper bound for mesh points 2152 2153 Output Parameters: 2154 2155 Level: beginner 2156 2157 .seealso: DMPlexCreate(), DMPlexGetChart() 2158 @*/ 2159 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 2160 { 2161 DM_Plex *mesh = (DM_Plex*) dm->data; 2162 PetscErrorCode ierr; 2163 2164 PetscFunctionBegin; 2165 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2166 ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 2167 ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 2168 PetscFunctionReturn(0); 2169 } 2170 2171 /*@ 2172 DMPlexGetConeSize - Return the number of in-edges for this point in the DAG 2173 2174 Not collective 2175 2176 Input Parameters: 2177 + mesh - The DMPlex 2178 - p - The point, which must lie in the chart set with DMPlexSetChart() 2179 2180 Output Parameter: 2181 . size - The cone size for point p 2182 2183 Level: beginner 2184 2185 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 2186 @*/ 2187 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 2188 { 2189 DM_Plex *mesh = (DM_Plex*) dm->data; 2190 PetscErrorCode ierr; 2191 2192 PetscFunctionBegin; 2193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2194 PetscValidPointer(size, 3); 2195 ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 2196 PetscFunctionReturn(0); 2197 } 2198 2199 /*@ 2200 DMPlexSetConeSize - Set the number of in-edges for this point in the DAG 2201 2202 Not collective 2203 2204 Input Parameters: 2205 + mesh - The DMPlex 2206 . p - The point, which must lie in the chart set with DMPlexSetChart() 2207 - size - The cone size for point p 2208 2209 Output Parameter: 2210 2211 Note: 2212 This should be called after DMPlexSetChart(). 2213 2214 Level: beginner 2215 2216 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 2217 @*/ 2218 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 2219 { 2220 DM_Plex *mesh = (DM_Plex*) dm->data; 2221 PetscErrorCode ierr; 2222 2223 PetscFunctionBegin; 2224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2225 ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 2226 2227 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 2228 PetscFunctionReturn(0); 2229 } 2230 2231 /*@ 2232 DMPlexAddConeSize - Add the given number of in-edges to this point in the DAG 2233 2234 Not collective 2235 2236 Input Parameters: 2237 + mesh - The DMPlex 2238 . p - The point, which must lie in the chart set with DMPlexSetChart() 2239 - size - The additional cone size for point p 2240 2241 Output Parameter: 2242 2243 Note: 2244 This should be called after DMPlexSetChart(). 2245 2246 Level: beginner 2247 2248 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 2249 @*/ 2250 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 2251 { 2252 DM_Plex *mesh = (DM_Plex*) dm->data; 2253 PetscInt csize; 2254 PetscErrorCode ierr; 2255 2256 PetscFunctionBegin; 2257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2258 ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr); 2259 ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr); 2260 2261 mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize); 2262 PetscFunctionReturn(0); 2263 } 2264 2265 /*@C 2266 DMPlexGetCone - Return the points on the in-edges for this point in the DAG 2267 2268 Not collective 2269 2270 Input Parameters: 2271 + dm - The DMPlex 2272 - p - The point, which must lie in the chart set with DMPlexSetChart() 2273 2274 Output Parameter: 2275 . cone - An array of points which are on the in-edges for point p 2276 2277 Level: beginner 2278 2279 Fortran Notes: 2280 Since it returns an array, this routine is only available in Fortran 90, and you must 2281 include petsc.h90 in your code. 2282 You must also call DMPlexRestoreCone() after you finish using the returned array. 2283 DMPlexRestoreCone() is not needed/available in C. 2284 2285 .seealso: DMPlexGetConeSize(), DMPlexSetCone(), DMPlexGetConeTuple(), DMPlexSetChart() 2286 @*/ 2287 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 2288 { 2289 DM_Plex *mesh = (DM_Plex*) dm->data; 2290 PetscInt off; 2291 PetscErrorCode ierr; 2292 2293 PetscFunctionBegin; 2294 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2295 PetscValidPointer(cone, 3); 2296 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2297 *cone = &mesh->cones[off]; 2298 PetscFunctionReturn(0); 2299 } 2300 2301 /*@C 2302 DMPlexGetConeTuple - Return the points on the in-edges of several points in the DAG 2303 2304 Not collective 2305 2306 Input Parameters: 2307 + dm - The DMPlex 2308 - p - The IS of points, which must lie in the chart set with DMPlexSetChart() 2309 2310 Output Parameter: 2311 + pConesSection - PetscSection describing the layout of pCones 2312 - pCones - An array of points which are on the in-edges for the point set p 2313 2314 Level: intermediate 2315 2316 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeRecursive(), DMPlexSetChart() 2317 @*/ 2318 PetscErrorCode DMPlexGetConeTuple(DM dm, IS p, PetscSection *pConesSection, IS *pCones) 2319 { 2320 PetscSection cs, newcs; 2321 PetscInt *cones; 2322 PetscInt *newarr=NULL; 2323 PetscInt n; 2324 PetscErrorCode ierr; 2325 2326 PetscFunctionBegin; 2327 ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); 2328 ierr = DMPlexGetConeSection(dm, &cs);CHKERRQ(ierr); 2329 ierr = PetscSectionExtractDofsFromArray(cs, MPIU_INT, cones, p, &newcs, pCones ? ((void**)&newarr) : NULL);CHKERRQ(ierr); 2330 if (pConesSection) *pConesSection = newcs; 2331 if (pCones) { 2332 ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr); 2333 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)p), n, newarr, PETSC_OWN_POINTER, pCones);CHKERRQ(ierr); 2334 } 2335 PetscFunctionReturn(0); 2336 } 2337 2338 /*@ 2339 DMPlexGetConeRecursiveVertices - Expand each given point into its cone points and do that recursively until we end up just with vertices. 2340 2341 Not collective 2342 2343 Input Parameters: 2344 + dm - The DMPlex 2345 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2346 2347 Output Parameter: 2348 . expandedPoints - An array of vertices recursively expanded from input points 2349 2350 Level: advanced 2351 2352 Notes: 2353 Like DMPlexGetConeRecursive but returns only the 0-depth IS (i.e. vertices only) and no sections. 2354 There is no corresponding Restore function, just call ISDestroy() on the returned IS to deallocate. 2355 2356 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexRestoreConeRecursive(), DMPlexGetDepth() 2357 @*/ 2358 PetscErrorCode DMPlexGetConeRecursiveVertices(DM dm, IS points, IS *expandedPoints) 2359 { 2360 IS *expandedPointsAll; 2361 PetscInt depth; 2362 PetscErrorCode ierr; 2363 2364 PetscFunctionBegin; 2365 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2366 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2367 PetscValidPointer(expandedPoints, 3); 2368 ierr = DMPlexGetConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 2369 *expandedPoints = expandedPointsAll[0]; 2370 ierr = PetscObjectReference((PetscObject)expandedPointsAll[0]); 2371 ierr = DMPlexRestoreConeRecursive(dm, points, &depth, &expandedPointsAll, NULL);CHKERRQ(ierr); 2372 PetscFunctionReturn(0); 2373 } 2374 2375 /*@ 2376 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). 2377 2378 Not collective 2379 2380 Input Parameters: 2381 + dm - The DMPlex 2382 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2383 2384 Output Parameter: 2385 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2386 . expandedPoints - (optional) An array of index sets with recursively expanded cones 2387 - sections - (optional) An array of sections which describe mappings from points to their cone points 2388 2389 Level: advanced 2390 2391 Notes: 2392 Like DMPlexGetConeTuple() but recursive. 2393 2394 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. 2395 For example, for d=0 it contains only vertices, for d=1 it can contain vertices and edges, etc. 2396 2397 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: 2398 (1) DAG points in expandedPoints[d+1] with depth d+1 to their cone points in expandedPoints[d]; 2399 (2) DAG points in expandedPoints[d+1] with depth in [0,d] to the same points in expandedPoints[d]. 2400 2401 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexRestoreConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2402 @*/ 2403 PetscErrorCode DMPlexGetConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2404 { 2405 const PetscInt *arr0=NULL, *cone=NULL; 2406 PetscInt *arr=NULL, *newarr=NULL; 2407 PetscInt d, depth_, i, n, newn, cn, co, start, end; 2408 IS *expandedPoints_; 2409 PetscSection *sections_; 2410 PetscErrorCode ierr; 2411 2412 PetscFunctionBegin; 2413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2414 PetscValidHeaderSpecific(points, IS_CLASSID, 2); 2415 if (depth) PetscValidIntPointer(depth, 3); 2416 if (expandedPoints) PetscValidPointer(expandedPoints, 4); 2417 if (sections) PetscValidPointer(sections, 5); 2418 ierr = ISGetLocalSize(points, &n);CHKERRQ(ierr); 2419 ierr = ISGetIndices(points, &arr0);CHKERRQ(ierr); 2420 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 2421 ierr = PetscCalloc1(depth_, &expandedPoints_);CHKERRQ(ierr); 2422 ierr = PetscCalloc1(depth_, §ions_);CHKERRQ(ierr); 2423 arr = (PetscInt*) arr0; /* this is ok because first generation of arr is not modified */ 2424 for (d=depth_-1; d>=0; d--) { 2425 ierr = PetscSectionCreate(PETSC_COMM_SELF, §ions_[d]);CHKERRQ(ierr); 2426 ierr = PetscSectionSetChart(sections_[d], 0, n);CHKERRQ(ierr); 2427 for (i=0; i<n; i++) { 2428 ierr = DMPlexGetDepthStratum(dm, d+1, &start, &end);CHKERRQ(ierr); 2429 if (arr[i] >= start && arr[i] < end) { 2430 ierr = DMPlexGetConeSize(dm, arr[i], &cn);CHKERRQ(ierr); 2431 ierr = PetscSectionSetDof(sections_[d], i, cn);CHKERRQ(ierr); 2432 } else { 2433 ierr = PetscSectionSetDof(sections_[d], i, 1);CHKERRQ(ierr); 2434 } 2435 } 2436 ierr = PetscSectionSetUp(sections_[d]);CHKERRQ(ierr); 2437 ierr = PetscSectionGetStorageSize(sections_[d], &newn);CHKERRQ(ierr); 2438 ierr = PetscMalloc1(newn, &newarr);CHKERRQ(ierr); 2439 for (i=0; i<n; i++) { 2440 ierr = PetscSectionGetDof(sections_[d], i, &cn);CHKERRQ(ierr); 2441 ierr = PetscSectionGetOffset(sections_[d], i, &co);CHKERRQ(ierr); 2442 if (cn > 1) { 2443 ierr = DMPlexGetCone(dm, arr[i], &cone);CHKERRQ(ierr); 2444 ierr = PetscMemcpy(&newarr[co], cone, cn*sizeof(PetscInt));CHKERRQ(ierr); 2445 } else { 2446 newarr[co] = arr[i]; 2447 } 2448 } 2449 ierr = ISCreateGeneral(PETSC_COMM_SELF, newn, newarr, PETSC_OWN_POINTER, &expandedPoints_[d]);CHKERRQ(ierr); 2450 arr = newarr; 2451 n = newn; 2452 } 2453 ierr = ISRestoreIndices(points, &arr0);CHKERRQ(ierr); 2454 *depth = depth_; 2455 if (expandedPoints) *expandedPoints = expandedPoints_; 2456 else { 2457 for (d=0; d<depth_; d++) {ierr = ISDestroy(&expandedPoints_[d]);CHKERRQ(ierr);} 2458 ierr = PetscFree(expandedPoints_);CHKERRQ(ierr); 2459 } 2460 if (sections) *sections = sections_; 2461 else { 2462 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(§ions_[d]);CHKERRQ(ierr);} 2463 ierr = PetscFree(sections_);CHKERRQ(ierr); 2464 } 2465 PetscFunctionReturn(0); 2466 } 2467 2468 /*@ 2469 DMPlexRestoreConeRecursive - Deallocates arrays created by DMPlexGetConeRecursive 2470 2471 Not collective 2472 2473 Input Parameters: 2474 + dm - The DMPlex 2475 - points - The IS of points, which must lie in the chart set with DMPlexSetChart() 2476 2477 Output Parameter: 2478 + depth - (optional) Size of the output arrays, equal to DMPlex depth, returned by DMPlexGetDepth() 2479 . expandedPoints - (optional) An array of recursively expanded cones 2480 - sections - (optional) An array of sections which describe mappings from points to their cone points 2481 2482 Level: advanced 2483 2484 Notes: 2485 See DMPlexGetConeRecursive() for details. 2486 2487 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexGetConeTuple(), DMPlexGetConeRecursive(), DMPlexGetConeRecursiveVertices(), DMPlexGetDepth() 2488 @*/ 2489 PetscErrorCode DMPlexRestoreConeRecursive(DM dm, IS points, PetscInt *depth, IS *expandedPoints[], PetscSection *sections[]) 2490 { 2491 PetscInt d, depth_; 2492 PetscErrorCode ierr; 2493 2494 PetscFunctionBegin; 2495 ierr = DMPlexGetDepth(dm, &depth_);CHKERRQ(ierr); 2496 if (depth && *depth != depth_) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "depth changed since last call to DMPlexGetConeRecursive"); 2497 if (depth) *depth = 0; 2498 if (expandedPoints) { 2499 for (d=0; d<depth_; d++) {ierr = ISDestroy(&((*expandedPoints)[d]));CHKERRQ(ierr);} 2500 ierr = PetscFree(*expandedPoints);CHKERRQ(ierr); 2501 } 2502 if (sections) { 2503 for (d=0; d<depth_; d++) {ierr = PetscSectionDestroy(&((*sections)[d]));CHKERRQ(ierr);} 2504 ierr = PetscFree(*sections);CHKERRQ(ierr); 2505 } 2506 PetscFunctionReturn(0); 2507 } 2508 2509 /*@ 2510 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 2511 2512 Not collective 2513 2514 Input Parameters: 2515 + mesh - The DMPlex 2516 . p - The point, which must lie in the chart set with DMPlexSetChart() 2517 - cone - An array of points which are on the in-edges for point p 2518 2519 Output Parameter: 2520 2521 Note: 2522 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2523 2524 Developer Note: Why not call this DMPlexSetCover() 2525 2526 Level: beginner 2527 2528 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp(), DMPlexSetSupport(), DMPlexSetSupportSize() 2529 @*/ 2530 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 2531 { 2532 DM_Plex *mesh = (DM_Plex*) dm->data; 2533 PetscInt pStart, pEnd; 2534 PetscInt dof, off, c; 2535 PetscErrorCode ierr; 2536 2537 PetscFunctionBegin; 2538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2539 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2540 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2541 if (dof) PetscValidPointer(cone, 3); 2542 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2543 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); 2544 for (c = 0; c < dof; ++c) { 2545 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); 2546 mesh->cones[off+c] = cone[c]; 2547 } 2548 PetscFunctionReturn(0); 2549 } 2550 2551 /*@C 2552 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the DAG 2553 2554 Not collective 2555 2556 Input Parameters: 2557 + mesh - The DMPlex 2558 - p - The point, which must lie in the chart set with DMPlexSetChart() 2559 2560 Output Parameter: 2561 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 2562 integer giving the prescription for cone traversal. If it is negative, the cone is 2563 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 2564 the index of the cone point on which to start. 2565 2566 Level: beginner 2567 2568 Fortran Notes: 2569 Since it returns an array, this routine is only available in Fortran 90, and you must 2570 include petsc.h90 in your code. 2571 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 2572 DMPlexRestoreConeOrientation() is not needed/available in C. 2573 2574 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 2575 @*/ 2576 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 2577 { 2578 DM_Plex *mesh = (DM_Plex*) dm->data; 2579 PetscInt off; 2580 PetscErrorCode ierr; 2581 2582 PetscFunctionBegin; 2583 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2584 if (PetscDefined(USE_DEBUG)) { 2585 PetscInt dof; 2586 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2587 if (dof) PetscValidPointer(coneOrientation, 3); 2588 } 2589 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2590 2591 *coneOrientation = &mesh->coneOrientations[off]; 2592 PetscFunctionReturn(0); 2593 } 2594 2595 /*@ 2596 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the DAG 2597 2598 Not collective 2599 2600 Input Parameters: 2601 + mesh - The DMPlex 2602 . p - The point, which must lie in the chart set with DMPlexSetChart() 2603 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 2604 integer giving the prescription for cone traversal. If it is negative, the cone is 2605 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 2606 the index of the cone point on which to start. 2607 2608 Output Parameter: 2609 2610 Note: 2611 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 2612 2613 Level: beginner 2614 2615 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2616 @*/ 2617 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 2618 { 2619 DM_Plex *mesh = (DM_Plex*) dm->data; 2620 PetscInt pStart, pEnd; 2621 PetscInt dof, off, c; 2622 PetscErrorCode ierr; 2623 2624 PetscFunctionBegin; 2625 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2626 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2627 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2628 if (dof) PetscValidPointer(coneOrientation, 3); 2629 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2630 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); 2631 for (c = 0; c < dof; ++c) { 2632 PetscInt cdof, o = coneOrientation[c]; 2633 2634 ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr); 2635 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); 2636 mesh->coneOrientations[off+c] = o; 2637 } 2638 PetscFunctionReturn(0); 2639 } 2640 2641 /*@ 2642 DMPlexInsertCone - Insert a point into the in-edges for the point p in the DAG 2643 2644 Not collective 2645 2646 Input Parameters: 2647 + mesh - The DMPlex 2648 . p - The point, which must lie in the chart set with DMPlexSetChart() 2649 . conePos - The local index in the cone where the point should be put 2650 - conePoint - The mesh point to insert 2651 2652 Level: beginner 2653 2654 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2655 @*/ 2656 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 2657 { 2658 DM_Plex *mesh = (DM_Plex*) dm->data; 2659 PetscInt pStart, pEnd; 2660 PetscInt dof, off; 2661 PetscErrorCode ierr; 2662 2663 PetscFunctionBegin; 2664 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2665 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2666 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); 2667 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); 2668 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2669 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2670 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); 2671 mesh->cones[off+conePos] = conePoint; 2672 PetscFunctionReturn(0); 2673 } 2674 2675 /*@ 2676 DMPlexInsertConeOrientation - Insert a point orientation for the in-edge for the point p in the DAG 2677 2678 Not collective 2679 2680 Input Parameters: 2681 + mesh - The DMPlex 2682 . p - The point, which must lie in the chart set with DMPlexSetChart() 2683 . conePos - The local index in the cone where the point should be put 2684 - coneOrientation - The point orientation to insert 2685 2686 Level: beginner 2687 2688 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2689 @*/ 2690 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 2691 { 2692 DM_Plex *mesh = (DM_Plex*) dm->data; 2693 PetscInt pStart, pEnd; 2694 PetscInt dof, off; 2695 PetscErrorCode ierr; 2696 2697 PetscFunctionBegin; 2698 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2699 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 2700 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); 2701 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2702 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2703 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); 2704 mesh->coneOrientations[off+conePos] = coneOrientation; 2705 PetscFunctionReturn(0); 2706 } 2707 2708 /*@ 2709 DMPlexGetSupportSize - Return the number of out-edges for this point in the DAG 2710 2711 Not collective 2712 2713 Input Parameters: 2714 + mesh - The DMPlex 2715 - p - The point, which must lie in the chart set with DMPlexSetChart() 2716 2717 Output Parameter: 2718 . size - The support size for point p 2719 2720 Level: beginner 2721 2722 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 2723 @*/ 2724 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 2725 { 2726 DM_Plex *mesh = (DM_Plex*) dm->data; 2727 PetscErrorCode ierr; 2728 2729 PetscFunctionBegin; 2730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2731 PetscValidPointer(size, 3); 2732 ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2733 PetscFunctionReturn(0); 2734 } 2735 2736 /*@ 2737 DMPlexSetSupportSize - Set the number of out-edges for this point in the DAG 2738 2739 Not collective 2740 2741 Input Parameters: 2742 + mesh - The DMPlex 2743 . p - The point, which must lie in the chart set with DMPlexSetChart() 2744 - size - The support size for point p 2745 2746 Output Parameter: 2747 2748 Note: 2749 This should be called after DMPlexSetChart(). 2750 2751 Level: beginner 2752 2753 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 2754 @*/ 2755 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 2756 { 2757 DM_Plex *mesh = (DM_Plex*) dm->data; 2758 PetscErrorCode ierr; 2759 2760 PetscFunctionBegin; 2761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2762 ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 2763 2764 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 2765 PetscFunctionReturn(0); 2766 } 2767 2768 /*@C 2769 DMPlexGetSupport - Return the points on the out-edges for this point in the DAG 2770 2771 Not collective 2772 2773 Input Parameters: 2774 + mesh - The DMPlex 2775 - p - The point, which must lie in the chart set with DMPlexSetChart() 2776 2777 Output Parameter: 2778 . support - An array of points which are on the out-edges for point p 2779 2780 Level: beginner 2781 2782 Fortran Notes: 2783 Since it returns an array, this routine is only available in Fortran 90, and you must 2784 include petsc.h90 in your code. 2785 You must also call DMPlexRestoreSupport() after you finish using the returned array. 2786 DMPlexRestoreSupport() is not needed/available in C. 2787 2788 .seealso: DMPlexGetSupportSize(), DMPlexSetSupport(), DMPlexGetCone(), DMPlexSetChart() 2789 @*/ 2790 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 2791 { 2792 DM_Plex *mesh = (DM_Plex*) dm->data; 2793 PetscInt off; 2794 PetscErrorCode ierr; 2795 2796 PetscFunctionBegin; 2797 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2798 PetscValidPointer(support, 3); 2799 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2800 *support = &mesh->supports[off]; 2801 PetscFunctionReturn(0); 2802 } 2803 2804 /*@ 2805 DMPlexSetSupport - Set the points on the out-edges for this point in the DAG, that is the list of points that this point covers 2806 2807 Not collective 2808 2809 Input Parameters: 2810 + mesh - The DMPlex 2811 . p - The point, which must lie in the chart set with DMPlexSetChart() 2812 - support - An array of points which are on the out-edges for point p 2813 2814 Output Parameter: 2815 2816 Note: 2817 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 2818 2819 Level: beginner 2820 2821 .seealso: DMPlexSetCone(), DMPlexSetConeSize(), DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 2822 @*/ 2823 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 2824 { 2825 DM_Plex *mesh = (DM_Plex*) dm->data; 2826 PetscInt pStart, pEnd; 2827 PetscInt dof, off, c; 2828 PetscErrorCode ierr; 2829 2830 PetscFunctionBegin; 2831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2832 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2833 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2834 if (dof) PetscValidPointer(support, 3); 2835 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2836 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); 2837 for (c = 0; c < dof; ++c) { 2838 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); 2839 mesh->supports[off+c] = support[c]; 2840 } 2841 PetscFunctionReturn(0); 2842 } 2843 2844 /*@ 2845 DMPlexInsertSupport - Insert a point into the out-edges for the point p in the DAG 2846 2847 Not collective 2848 2849 Input Parameters: 2850 + mesh - The DMPlex 2851 . p - The point, which must lie in the chart set with DMPlexSetChart() 2852 . supportPos - The local index in the cone where the point should be put 2853 - supportPoint - The mesh point to insert 2854 2855 Level: beginner 2856 2857 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 2858 @*/ 2859 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 2860 { 2861 DM_Plex *mesh = (DM_Plex*) dm->data; 2862 PetscInt pStart, pEnd; 2863 PetscInt dof, off; 2864 PetscErrorCode ierr; 2865 2866 PetscFunctionBegin; 2867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2868 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 2869 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2870 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 2871 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); 2872 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); 2873 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); 2874 mesh->supports[off+supportPos] = supportPoint; 2875 PetscFunctionReturn(0); 2876 } 2877 2878 /*@C 2879 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the DAG 2880 2881 Not collective 2882 2883 Input Parameters: 2884 + mesh - The DMPlex 2885 . p - The point, which must lie in the chart set with DMPlexSetChart() 2886 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 2887 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 2888 2889 Output Parameters: 2890 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 2891 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 2892 2893 Note: 2894 If using internal storage (points is NULL on input), each call overwrites the last output. 2895 2896 Fortran Notes: 2897 Since it returns an array, this routine is only available in Fortran 90, and you must 2898 include petsc.h90 in your code. 2899 2900 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2901 2902 Level: beginner 2903 2904 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 2905 @*/ 2906 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 2907 { 2908 DM_Plex *mesh = (DM_Plex*) dm->data; 2909 PetscInt *closure, *fifo; 2910 const PetscInt *tmp = NULL, *tmpO = NULL; 2911 PetscInt tmpSize, t; 2912 PetscInt depth = 0, maxSize; 2913 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 2914 PetscErrorCode ierr; 2915 2916 PetscFunctionBegin; 2917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2918 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2919 /* This is only 1-level */ 2920 if (useCone) { 2921 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 2922 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 2923 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 2924 } else { 2925 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 2926 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 2927 } 2928 if (depth == 1) { 2929 if (*points) { 2930 closure = *points; 2931 } else { 2932 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 2933 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2934 } 2935 closure[0] = p; closure[1] = 0; 2936 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 2937 closure[closureSize] = tmp[t]; 2938 closure[closureSize+1] = tmpO ? tmpO[t] : 0; 2939 } 2940 if (numPoints) *numPoints = closureSize/2; 2941 if (points) *points = closure; 2942 PetscFunctionReturn(0); 2943 } 2944 { 2945 PetscInt c, coneSeries, s,supportSeries; 2946 2947 c = mesh->maxConeSize; 2948 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 2949 s = mesh->maxSupportSize; 2950 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 2951 maxSize = 2*PetscMax(coneSeries,supportSeries); 2952 } 2953 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 2954 if (*points) { 2955 closure = *points; 2956 } else { 2957 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 2958 } 2959 closure[0] = p; closure[1] = 0; 2960 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 2961 const PetscInt cp = tmp[t]; 2962 const PetscInt co = tmpO ? tmpO[t] : 0; 2963 2964 closure[closureSize] = cp; 2965 closure[closureSize+1] = co; 2966 fifo[fifoSize] = cp; 2967 fifo[fifoSize+1] = co; 2968 } 2969 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 2970 while (fifoSize - fifoStart) { 2971 const PetscInt q = fifo[fifoStart]; 2972 const PetscInt o = fifo[fifoStart+1]; 2973 const PetscInt rev = o >= 0 ? 0 : 1; 2974 const PetscInt off = rev ? -(o+1) : o; 2975 2976 if (useCone) { 2977 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 2978 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 2979 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 2980 } else { 2981 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 2982 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 2983 tmpO = NULL; 2984 } 2985 for (t = 0; t < tmpSize; ++t) { 2986 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 2987 const PetscInt cp = tmp[i]; 2988 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 2989 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 2990 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 2991 PetscInt co = tmpO ? tmpO[i] : 0; 2992 PetscInt c; 2993 2994 if (rev) { 2995 PetscInt childSize, coff; 2996 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 2997 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 2998 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 2999 } 3000 /* Check for duplicate */ 3001 for (c = 0; c < closureSize; c += 2) { 3002 if (closure[c] == cp) break; 3003 } 3004 if (c == closureSize) { 3005 closure[closureSize] = cp; 3006 closure[closureSize+1] = co; 3007 fifo[fifoSize] = cp; 3008 fifo[fifoSize+1] = co; 3009 closureSize += 2; 3010 fifoSize += 2; 3011 } 3012 } 3013 fifoStart += 2; 3014 } 3015 if (numPoints) *numPoints = closureSize/2; 3016 if (points) *points = closure; 3017 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 3018 PetscFunctionReturn(0); 3019 } 3020 3021 /*@C 3022 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 3023 3024 Not collective 3025 3026 Input Parameters: 3027 + mesh - The DMPlex 3028 . p - The point, which must lie in the chart set with DMPlexSetChart() 3029 . orientation - The orientation of the point 3030 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 3031 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 3032 3033 Output Parameters: 3034 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 3035 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 3036 3037 Note: 3038 If using internal storage (points is NULL on input), each call overwrites the last output. 3039 3040 Fortran Notes: 3041 Since it returns an array, this routine is only available in Fortran 90, and you must 3042 include petsc.h90 in your code. 3043 3044 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3045 3046 Level: beginner 3047 3048 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3049 @*/ 3050 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3051 { 3052 DM_Plex *mesh = (DM_Plex*) dm->data; 3053 PetscInt *closure, *fifo; 3054 const PetscInt *tmp = NULL, *tmpO = NULL; 3055 PetscInt tmpSize, t; 3056 PetscInt depth = 0, maxSize; 3057 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 3058 PetscErrorCode ierr; 3059 3060 PetscFunctionBegin; 3061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3062 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3063 /* This is only 1-level */ 3064 if (useCone) { 3065 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 3066 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 3067 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 3068 } else { 3069 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 3070 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 3071 } 3072 if (depth == 1) { 3073 if (*points) { 3074 closure = *points; 3075 } else { 3076 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 3077 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 3078 } 3079 closure[0] = p; closure[1] = ornt; 3080 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 3081 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 3082 closure[closureSize] = tmp[i]; 3083 closure[closureSize+1] = tmpO ? tmpO[i] : 0; 3084 } 3085 if (numPoints) *numPoints = closureSize/2; 3086 if (points) *points = closure; 3087 PetscFunctionReturn(0); 3088 } 3089 { 3090 PetscInt c, coneSeries, s,supportSeries; 3091 3092 c = mesh->maxConeSize; 3093 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 3094 s = mesh->maxSupportSize; 3095 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 3096 maxSize = 2*PetscMax(coneSeries,supportSeries); 3097 } 3098 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 3099 if (*points) { 3100 closure = *points; 3101 } else { 3102 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &closure);CHKERRQ(ierr); 3103 } 3104 closure[0] = p; closure[1] = ornt; 3105 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 3106 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 3107 const PetscInt cp = tmp[i]; 3108 PetscInt co = tmpO ? tmpO[i] : 0; 3109 3110 if (ornt < 0) { 3111 PetscInt childSize, coff; 3112 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 3113 coff = co < 0 ? -(tmpO[i]+1) : tmpO[i]; 3114 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 3115 } 3116 closure[closureSize] = cp; 3117 closure[closureSize+1] = co; 3118 fifo[fifoSize] = cp; 3119 fifo[fifoSize+1] = co; 3120 } 3121 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 3122 while (fifoSize - fifoStart) { 3123 const PetscInt q = fifo[fifoStart]; 3124 const PetscInt o = fifo[fifoStart+1]; 3125 const PetscInt rev = o >= 0 ? 0 : 1; 3126 const PetscInt off = rev ? -(o+1) : o; 3127 3128 if (useCone) { 3129 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 3130 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 3131 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 3132 } else { 3133 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 3134 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 3135 tmpO = NULL; 3136 } 3137 for (t = 0; t < tmpSize; ++t) { 3138 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 3139 const PetscInt cp = tmp[i]; 3140 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 3141 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 3142 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 3143 PetscInt co = tmpO ? tmpO[i] : 0; 3144 PetscInt c; 3145 3146 if (rev) { 3147 PetscInt childSize, coff; 3148 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 3149 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 3150 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 3151 } 3152 /* Check for duplicate */ 3153 for (c = 0; c < closureSize; c += 2) { 3154 if (closure[c] == cp) break; 3155 } 3156 if (c == closureSize) { 3157 closure[closureSize] = cp; 3158 closure[closureSize+1] = co; 3159 fifo[fifoSize] = cp; 3160 fifo[fifoSize+1] = co; 3161 closureSize += 2; 3162 fifoSize += 2; 3163 } 3164 } 3165 fifoStart += 2; 3166 } 3167 if (numPoints) *numPoints = closureSize/2; 3168 if (points) *points = closure; 3169 ierr = DMRestoreWorkArray(dm, maxSize, MPIU_INT, &fifo);CHKERRQ(ierr); 3170 PetscFunctionReturn(0); 3171 } 3172 3173 /*@C 3174 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the DAG 3175 3176 Not collective 3177 3178 Input Parameters: 3179 + mesh - The DMPlex 3180 . p - The point, which must lie in the chart set with DMPlexSetChart() 3181 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 3182 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit 3183 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit 3184 3185 Note: 3186 If not using internal storage (points is not NULL on input), this call is unnecessary 3187 3188 Fortran Notes: 3189 Since it returns an array, this routine is only available in Fortran 90, and you must 3190 include petsc.h90 in your code. 3191 3192 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3193 3194 Level: beginner 3195 3196 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 3197 @*/ 3198 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 3199 { 3200 PetscErrorCode ierr; 3201 3202 PetscFunctionBegin; 3203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3204 if (numPoints) PetscValidIntPointer(numPoints,4); 3205 if (points) PetscValidPointer(points,5); 3206 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, points);CHKERRQ(ierr); 3207 if (numPoints) *numPoints = 0; 3208 PetscFunctionReturn(0); 3209 } 3210 3211 /*@ 3212 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the DAG 3213 3214 Not collective 3215 3216 Input Parameter: 3217 . mesh - The DMPlex 3218 3219 Output Parameters: 3220 + maxConeSize - The maximum number of in-edges 3221 - maxSupportSize - The maximum number of out-edges 3222 3223 Level: beginner 3224 3225 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 3226 @*/ 3227 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 3228 { 3229 DM_Plex *mesh = (DM_Plex*) dm->data; 3230 3231 PetscFunctionBegin; 3232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3233 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 3234 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 3235 PetscFunctionReturn(0); 3236 } 3237 3238 PetscErrorCode DMSetUp_Plex(DM dm) 3239 { 3240 DM_Plex *mesh = (DM_Plex*) dm->data; 3241 PetscInt size; 3242 PetscErrorCode ierr; 3243 3244 PetscFunctionBegin; 3245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3246 ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr); 3247 ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr); 3248 ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr); 3249 ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr); 3250 ierr = PetscLogObjectMemory((PetscObject) dm, size*2*sizeof(PetscInt));CHKERRQ(ierr); 3251 if (mesh->maxSupportSize) { 3252 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 3253 ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr); 3254 ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr); 3255 ierr = PetscLogObjectMemory((PetscObject) dm, size*sizeof(PetscInt));CHKERRQ(ierr); 3256 } 3257 PetscFunctionReturn(0); 3258 } 3259 3260 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 3261 { 3262 PetscErrorCode ierr; 3263 3264 PetscFunctionBegin; 3265 if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);} 3266 ierr = DMCreateSectionSubDM(dm, numFields, fields, is, subdm);CHKERRQ(ierr); 3267 if (subdm) {(*subdm)->useNatural = dm->useNatural;} 3268 if (dm->useNatural && dm->sfMigration) { 3269 PetscSF sfMigrationInv,sfNatural; 3270 PetscSection section, sectionSeq; 3271 3272 (*subdm)->sfMigration = dm->sfMigration; 3273 ierr = PetscObjectReference((PetscObject) dm->sfMigration);CHKERRQ(ierr); 3274 ierr = DMGetLocalSection((*subdm), §ion);CHKERRQ(ierr); 3275 ierr = PetscSFCreateInverseSF((*subdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 3276 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*subdm)), §ionSeq);CHKERRQ(ierr); 3277 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 3278 3279 ierr = DMPlexCreateGlobalToNaturalSF(*subdm, sectionSeq, (*subdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 3280 (*subdm)->sfNatural = sfNatural; 3281 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 3282 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 3283 } 3284 PetscFunctionReturn(0); 3285 } 3286 3287 PetscErrorCode DMCreateSuperDM_Plex(DM dms[], PetscInt len, IS **is, DM *superdm) 3288 { 3289 PetscErrorCode ierr; 3290 PetscInt i = 0; 3291 3292 PetscFunctionBegin; 3293 ierr = DMClone(dms[0], superdm);CHKERRQ(ierr); 3294 ierr = DMCreateSectionSuperDM(dms, len, is, superdm);CHKERRQ(ierr); 3295 (*superdm)->useNatural = PETSC_FALSE; 3296 for (i = 0; i < len; i++) { 3297 if (dms[i]->useNatural && dms[i]->sfMigration) { 3298 PetscSF sfMigrationInv,sfNatural; 3299 PetscSection section, sectionSeq; 3300 3301 (*superdm)->sfMigration = dms[i]->sfMigration; 3302 ierr = PetscObjectReference((PetscObject) dms[i]->sfMigration);CHKERRQ(ierr); 3303 (*superdm)->useNatural = PETSC_TRUE; 3304 ierr = DMGetLocalSection((*superdm), §ion);CHKERRQ(ierr); 3305 ierr = PetscSFCreateInverseSF((*superdm)->sfMigration, &sfMigrationInv);CHKERRQ(ierr); 3306 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) (*superdm)), §ionSeq);CHKERRQ(ierr); 3307 ierr = PetscSFDistributeSection(sfMigrationInv, section, NULL, sectionSeq);CHKERRQ(ierr); 3308 3309 ierr = DMPlexCreateGlobalToNaturalSF(*superdm, sectionSeq, (*superdm)->sfMigration, &sfNatural);CHKERRQ(ierr); 3310 (*superdm)->sfNatural = sfNatural; 3311 ierr = PetscSectionDestroy(§ionSeq);CHKERRQ(ierr); 3312 ierr = PetscSFDestroy(&sfMigrationInv);CHKERRQ(ierr); 3313 break; 3314 } 3315 } 3316 PetscFunctionReturn(0); 3317 } 3318 3319 /*@ 3320 DMPlexSymmetrize - Create support (out-edge) information from cone (in-edge) information 3321 3322 Not collective 3323 3324 Input Parameter: 3325 . mesh - The DMPlex 3326 3327 Output Parameter: 3328 3329 Note: 3330 This should be called after all calls to DMPlexSetCone() 3331 3332 Level: beginner 3333 3334 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 3335 @*/ 3336 PetscErrorCode DMPlexSymmetrize(DM dm) 3337 { 3338 DM_Plex *mesh = (DM_Plex*) dm->data; 3339 PetscInt *offsets; 3340 PetscInt supportSize; 3341 PetscInt pStart, pEnd, p; 3342 PetscErrorCode ierr; 3343 3344 PetscFunctionBegin; 3345 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3346 if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 3347 ierr = PetscLogEventBegin(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 3348 /* Calculate support sizes */ 3349 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3350 for (p = pStart; p < pEnd; ++p) { 3351 PetscInt dof, off, c; 3352 3353 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 3354 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 3355 for (c = off; c < off+dof; ++c) { 3356 ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr); 3357 } 3358 } 3359 for (p = pStart; p < pEnd; ++p) { 3360 PetscInt dof; 3361 3362 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 3363 3364 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 3365 } 3366 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 3367 /* Calculate supports */ 3368 ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr); 3369 ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr); 3370 ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr); 3371 for (p = pStart; p < pEnd; ++p) { 3372 PetscInt dof, off, c; 3373 3374 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 3375 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 3376 for (c = off; c < off+dof; ++c) { 3377 const PetscInt q = mesh->cones[c]; 3378 PetscInt offS; 3379 3380 ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr); 3381 3382 mesh->supports[offS+offsets[q]] = p; 3383 ++offsets[q]; 3384 } 3385 } 3386 ierr = PetscFree(offsets);CHKERRQ(ierr); 3387 ierr = PetscLogEventEnd(DMPLEX_Symmetrize,dm,0,0,0);CHKERRQ(ierr); 3388 PetscFunctionReturn(0); 3389 } 3390 3391 static PetscErrorCode DMPlexCreateDepthStratum(DM dm, DMLabel label, PetscInt depth, PetscInt pStart, PetscInt pEnd) 3392 { 3393 IS stratumIS; 3394 PetscErrorCode ierr; 3395 3396 PetscFunctionBegin; 3397 if (pStart >= pEnd) PetscFunctionReturn(0); 3398 if (PetscDefined(USE_DEBUG)) { 3399 PetscInt qStart, qEnd, numLevels, level; 3400 PetscBool overlap = PETSC_FALSE; 3401 ierr = DMLabelGetNumValues(label, &numLevels);CHKERRQ(ierr); 3402 for (level = 0; level < numLevels; level++) { 3403 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 3404 if ((pStart >= qStart && pStart < qEnd) || (pEnd > qStart && pEnd <= qEnd)) {overlap = PETSC_TRUE; break;} 3405 } 3406 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); 3407 } 3408 ierr = ISCreateStride(PETSC_COMM_SELF, pEnd-pStart, pStart, 1, &stratumIS);CHKERRQ(ierr); 3409 ierr = DMLabelSetStratumIS(label, depth, stratumIS);CHKERRQ(ierr); 3410 ierr = ISDestroy(&stratumIS);CHKERRQ(ierr); 3411 PetscFunctionReturn(0); 3412 } 3413 3414 /*@ 3415 DMPlexStratify - The DAG for most topologies is a graded poset (https://en.wikipedia.org/wiki/Graded_poset), and 3416 can be illustrated by a Hasse Diagram (https://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 3417 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 3418 the DAG. 3419 3420 Collective on dm 3421 3422 Input Parameter: 3423 . mesh - The DMPlex 3424 3425 Output Parameter: 3426 3427 Notes: 3428 Concretely, DMPlexStratify() creates a new label named "depth" containing the depth in the DAG of each point. For cell-vertex 3429 meshes, vertices are depth 0 and cells are depth 1. For fully interpolated meshes, depth 0 for vertices, 1 for edges, and so on 3430 until cells have depth equal to the dimension of the mesh. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 3431 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 3432 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 3433 3434 The depth of a point is calculated by executing a breadth-first search (BFS) on the DAG. This could produce surprising results 3435 if run on a partially interpolated mesh, meaning one that had some edges and faces, but not others. For example, suppose that 3436 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 3437 to interpolate only that one (e0), so that 3438 $ cone(c0) = {e0, v2} 3439 $ cone(e0) = {v0, v1} 3440 If DMPlexStratify() is run on this mesh, it will give depths 3441 $ depth 0 = {v0, v1, v2} 3442 $ depth 1 = {e0, c0} 3443 where the triangle has been given depth 1, instead of 2, because it is reachable from vertex v2. 3444 3445 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 3446 3447 Level: beginner 3448 3449 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexComputeCellTypes() 3450 @*/ 3451 PetscErrorCode DMPlexStratify(DM dm) 3452 { 3453 DM_Plex *mesh = (DM_Plex*) dm->data; 3454 DMLabel label; 3455 PetscInt pStart, pEnd, p; 3456 PetscInt numRoots = 0, numLeaves = 0; 3457 PetscErrorCode ierr; 3458 3459 PetscFunctionBegin; 3460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3461 ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 3462 3463 /* Create depth label */ 3464 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3465 ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr); 3466 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3467 3468 { 3469 /* Initialize roots and count leaves */ 3470 PetscInt sMin = PETSC_MAX_INT; 3471 PetscInt sMax = PETSC_MIN_INT; 3472 PetscInt coneSize, supportSize; 3473 3474 for (p = pStart; p < pEnd; ++p) { 3475 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 3476 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 3477 if (!coneSize && supportSize) { 3478 sMin = PetscMin(p, sMin); 3479 sMax = PetscMax(p, sMax); 3480 ++numRoots; 3481 } else if (!supportSize && coneSize) { 3482 ++numLeaves; 3483 } else if (!supportSize && !coneSize) { 3484 /* Isolated points */ 3485 sMin = PetscMin(p, sMin); 3486 sMax = PetscMax(p, sMax); 3487 } 3488 } 3489 ierr = DMPlexCreateDepthStratum(dm, label, 0, sMin, sMax+1);CHKERRQ(ierr); 3490 } 3491 3492 if (numRoots + numLeaves == (pEnd - pStart)) { 3493 PetscInt sMin = PETSC_MAX_INT; 3494 PetscInt sMax = PETSC_MIN_INT; 3495 PetscInt coneSize, supportSize; 3496 3497 for (p = pStart; p < pEnd; ++p) { 3498 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 3499 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 3500 if (!supportSize && coneSize) { 3501 sMin = PetscMin(p, sMin); 3502 sMax = PetscMax(p, sMax); 3503 } 3504 } 3505 ierr = DMPlexCreateDepthStratum(dm, label, 1, sMin, sMax+1);CHKERRQ(ierr); 3506 } else { 3507 PetscInt level = 0; 3508 PetscInt qStart, qEnd, q; 3509 3510 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 3511 while (qEnd > qStart) { 3512 PetscInt sMin = PETSC_MAX_INT; 3513 PetscInt sMax = PETSC_MIN_INT; 3514 3515 for (q = qStart; q < qEnd; ++q) { 3516 const PetscInt *support; 3517 PetscInt supportSize, s; 3518 3519 ierr = DMPlexGetSupportSize(dm, q, &supportSize);CHKERRQ(ierr); 3520 ierr = DMPlexGetSupport(dm, q, &support);CHKERRQ(ierr); 3521 for (s = 0; s < supportSize; ++s) { 3522 sMin = PetscMin(support[s], sMin); 3523 sMax = PetscMax(support[s], sMax); 3524 } 3525 } 3526 ierr = DMLabelGetNumValues(label, &level);CHKERRQ(ierr); 3527 ierr = DMPlexCreateDepthStratum(dm, label, level, sMin, sMax+1);CHKERRQ(ierr); 3528 ierr = DMLabelGetStratumBounds(label, level, &qStart, &qEnd);CHKERRQ(ierr); 3529 } 3530 } 3531 { /* just in case there is an empty process */ 3532 PetscInt numValues, maxValues = 0, v; 3533 3534 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 3535 ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr); 3536 for (v = numValues; v < maxValues; v++) { 3537 ierr = DMLabelAddStratum(label, v);CHKERRQ(ierr); 3538 } 3539 } 3540 ierr = PetscObjectStateGet((PetscObject) label, &mesh->depthState);CHKERRQ(ierr); 3541 ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 3542 PetscFunctionReturn(0); 3543 } 3544 3545 PetscErrorCode DMPlexComputeCellType_Internal(DM dm, PetscInt p, PetscInt pdepth, DMPolytopeType *pt) 3546 { 3547 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3548 PetscInt dim, depth, pheight, coneSize; 3549 PetscErrorCode ierr; 3550 3551 PetscFunctionBeginHot; 3552 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3553 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3554 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 3555 pheight = depth - pdepth; 3556 if (depth <= 1) { 3557 switch (pdepth) { 3558 case 0: ct = DM_POLYTOPE_POINT;break; 3559 case 1: 3560 switch (coneSize) { 3561 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3562 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3563 case 4: 3564 switch (dim) { 3565 case 2: ct = DM_POLYTOPE_QUADRILATERAL;break; 3566 case 3: ct = DM_POLYTOPE_TETRAHEDRON;break; 3567 default: break; 3568 } 3569 break; 3570 case 5: ct = DM_POLYTOPE_PYRAMID;break; 3571 case 6: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3572 case 8: ct = DM_POLYTOPE_HEXAHEDRON;break; 3573 default: break; 3574 } 3575 } 3576 } else { 3577 if (pdepth == 0) { 3578 ct = DM_POLYTOPE_POINT; 3579 } else if (pheight == 0) { 3580 switch (dim) { 3581 case 1: 3582 switch (coneSize) { 3583 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3584 default: break; 3585 } 3586 break; 3587 case 2: 3588 switch (coneSize) { 3589 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3590 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3591 default: break; 3592 } 3593 break; 3594 case 3: 3595 switch (coneSize) { 3596 case 4: ct = DM_POLYTOPE_TETRAHEDRON;break; 3597 case 5: 3598 { 3599 const PetscInt *cone; 3600 PetscInt faceConeSize; 3601 3602 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 3603 ierr = DMPlexGetConeSize(dm, cone[0], &faceConeSize);CHKERRQ(ierr); 3604 switch (faceConeSize) { 3605 case 3: ct = DM_POLYTOPE_TRI_PRISM_TENSOR;break; 3606 case 4: ct = DM_POLYTOPE_PYRAMID;break; 3607 } 3608 } 3609 break; 3610 case 6: ct = DM_POLYTOPE_HEXAHEDRON;break; 3611 default: break; 3612 } 3613 break; 3614 default: break; 3615 } 3616 } else if (pheight > 0) { 3617 switch (coneSize) { 3618 case 2: ct = DM_POLYTOPE_SEGMENT;break; 3619 case 3: ct = DM_POLYTOPE_TRIANGLE;break; 3620 case 4: ct = DM_POLYTOPE_QUADRILATERAL;break; 3621 default: break; 3622 } 3623 } 3624 } 3625 *pt = ct; 3626 PetscFunctionReturn(0); 3627 } 3628 3629 /*@ 3630 DMPlexComputeCellTypes - Infer the polytope type of every cell using its dimension and cone size. 3631 3632 Collective on dm 3633 3634 Input Parameter: 3635 . mesh - The DMPlex 3636 3637 DMPlexComputeCellTypes() should be called after all calls to DMPlexSymmetrize() and DMPlexStratify() 3638 3639 Level: developer 3640 3641 Note: This function is normally called automatically by Plex when a cell type is requested. It creates an 3642 internal DMLabel named "celltype" which can be directly accessed using DMGetLabel(). A user may disable 3643 automatic creation by creating the label manually, using DMCreateLabel(dm, "celltype"). 3644 3645 .seealso: DMPlexCreate(), DMPlexSymmetrize(), DMPlexStratify(), DMGetLabel(), DMCreateLabel() 3646 @*/ 3647 PetscErrorCode DMPlexComputeCellTypes(DM dm) 3648 { 3649 DM_Plex *mesh; 3650 DMLabel ctLabel; 3651 PetscInt pStart, pEnd, p; 3652 PetscErrorCode ierr; 3653 3654 PetscFunctionBegin; 3655 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3656 mesh = (DM_Plex *) dm->data; 3657 ierr = DMCreateLabel(dm, "celltype");CHKERRQ(ierr); 3658 ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr); 3659 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3660 for (p = pStart; p < pEnd; ++p) { 3661 DMPolytopeType ct = DM_POLYTOPE_UNKNOWN; 3662 PetscInt pdepth; 3663 3664 ierr = DMPlexGetPointDepth(dm, p, &pdepth);CHKERRQ(ierr); 3665 ierr = DMPlexComputeCellType_Internal(dm, p, pdepth, &ct);CHKERRQ(ierr); 3666 if (ct == DM_POLYTOPE_UNKNOWN) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Point %D is screwed up", p); 3667 ierr = DMLabelSetValue(ctLabel, p, ct);CHKERRQ(ierr); 3668 } 3669 ierr = PetscObjectStateGet((PetscObject) ctLabel, &mesh->celltypeState);CHKERRQ(ierr); 3670 ierr = PetscObjectViewFromOptions((PetscObject) ctLabel, NULL, "-dm_plex_celltypes_view");CHKERRQ(ierr); 3671 PetscFunctionReturn(0); 3672 } 3673 3674 /*@C 3675 DMPlexGetJoin - Get an array for the join of the set of points 3676 3677 Not Collective 3678 3679 Input Parameters: 3680 + dm - The DMPlex object 3681 . numPoints - The number of input points for the join 3682 - points - The input points 3683 3684 Output Parameters: 3685 + numCoveredPoints - The number of points in the join 3686 - coveredPoints - The points in the join 3687 3688 Level: intermediate 3689 3690 Note: Currently, this is restricted to a single level join 3691 3692 Fortran Notes: 3693 Since it returns an array, this routine is only available in Fortran 90, and you must 3694 include petsc.h90 in your code. 3695 3696 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3697 3698 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 3699 @*/ 3700 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3701 { 3702 DM_Plex *mesh = (DM_Plex*) dm->data; 3703 PetscInt *join[2]; 3704 PetscInt joinSize, i = 0; 3705 PetscInt dof, off, p, c, m; 3706 PetscErrorCode ierr; 3707 3708 PetscFunctionBegin; 3709 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3710 PetscValidIntPointer(points, 3); 3711 PetscValidIntPointer(numCoveredPoints, 4); 3712 PetscValidPointer(coveredPoints, 5); 3713 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3714 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3715 /* Copy in support of first point */ 3716 ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr); 3717 ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr); 3718 for (joinSize = 0; joinSize < dof; ++joinSize) { 3719 join[i][joinSize] = mesh->supports[off+joinSize]; 3720 } 3721 /* Check each successive support */ 3722 for (p = 1; p < numPoints; ++p) { 3723 PetscInt newJoinSize = 0; 3724 3725 ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr); 3726 ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr); 3727 for (c = 0; c < dof; ++c) { 3728 const PetscInt point = mesh->supports[off+c]; 3729 3730 for (m = 0; m < joinSize; ++m) { 3731 if (point == join[i][m]) { 3732 join[1-i][newJoinSize++] = point; 3733 break; 3734 } 3735 } 3736 } 3737 joinSize = newJoinSize; 3738 i = 1-i; 3739 } 3740 *numCoveredPoints = joinSize; 3741 *coveredPoints = join[i]; 3742 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3743 PetscFunctionReturn(0); 3744 } 3745 3746 /*@C 3747 DMPlexRestoreJoin - Restore an array for the join of the set of points 3748 3749 Not Collective 3750 3751 Input Parameters: 3752 + dm - The DMPlex object 3753 . numPoints - The number of input points for the join 3754 - points - The input points 3755 3756 Output Parameters: 3757 + numCoveredPoints - The number of points in the join 3758 - coveredPoints - The points in the join 3759 3760 Fortran Notes: 3761 Since it returns an array, this routine is only available in Fortran 90, and you must 3762 include petsc.h90 in your code. 3763 3764 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3765 3766 Level: intermediate 3767 3768 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 3769 @*/ 3770 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3771 { 3772 PetscErrorCode ierr; 3773 3774 PetscFunctionBegin; 3775 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3776 if (points) PetscValidIntPointer(points,3); 3777 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3778 PetscValidPointer(coveredPoints, 5); 3779 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3780 if (numCoveredPoints) *numCoveredPoints = 0; 3781 PetscFunctionReturn(0); 3782 } 3783 3784 /*@C 3785 DMPlexGetFullJoin - Get an array for the join of the set of points 3786 3787 Not Collective 3788 3789 Input Parameters: 3790 + dm - The DMPlex object 3791 . numPoints - The number of input points for the join 3792 - points - The input points 3793 3794 Output Parameters: 3795 + numCoveredPoints - The number of points in the join 3796 - coveredPoints - The points in the join 3797 3798 Fortran Notes: 3799 Since it returns an array, this routine is only available in Fortran 90, and you must 3800 include petsc.h90 in your code. 3801 3802 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3803 3804 Level: intermediate 3805 3806 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 3807 @*/ 3808 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3809 { 3810 DM_Plex *mesh = (DM_Plex*) dm->data; 3811 PetscInt *offsets, **closures; 3812 PetscInt *join[2]; 3813 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 3814 PetscInt p, d, c, m, ms; 3815 PetscErrorCode ierr; 3816 3817 PetscFunctionBegin; 3818 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3819 PetscValidIntPointer(points, 3); 3820 PetscValidIntPointer(numCoveredPoints, 4); 3821 PetscValidPointer(coveredPoints, 5); 3822 3823 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3824 ierr = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr); 3825 ierr = DMGetWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3826 ms = mesh->maxSupportSize; 3827 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 3828 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[0]);CHKERRQ(ierr); 3829 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &join[1]);CHKERRQ(ierr); 3830 3831 for (p = 0; p < numPoints; ++p) { 3832 PetscInt closureSize; 3833 3834 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr); 3835 3836 offsets[p*(depth+2)+0] = 0; 3837 for (d = 0; d < depth+1; ++d) { 3838 PetscInt pStart, pEnd, i; 3839 3840 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 3841 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 3842 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 3843 offsets[p*(depth+2)+d+1] = i; 3844 break; 3845 } 3846 } 3847 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 3848 } 3849 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); 3850 } 3851 for (d = 0; d < depth+1; ++d) { 3852 PetscInt dof; 3853 3854 /* Copy in support of first point */ 3855 dof = offsets[d+1] - offsets[d]; 3856 for (joinSize = 0; joinSize < dof; ++joinSize) { 3857 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 3858 } 3859 /* Check each successive cone */ 3860 for (p = 1; p < numPoints && joinSize; ++p) { 3861 PetscInt newJoinSize = 0; 3862 3863 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 3864 for (c = 0; c < dof; ++c) { 3865 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 3866 3867 for (m = 0; m < joinSize; ++m) { 3868 if (point == join[i][m]) { 3869 join[1-i][newJoinSize++] = point; 3870 break; 3871 } 3872 } 3873 } 3874 joinSize = newJoinSize; 3875 i = 1-i; 3876 } 3877 if (joinSize) break; 3878 } 3879 *numCoveredPoints = joinSize; 3880 *coveredPoints = join[i]; 3881 for (p = 0; p < numPoints; ++p) { 3882 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr); 3883 } 3884 ierr = PetscFree(closures);CHKERRQ(ierr); 3885 ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), MPIU_INT, &offsets);CHKERRQ(ierr); 3886 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, MPIU_INT, &join[1-i]);CHKERRQ(ierr); 3887 PetscFunctionReturn(0); 3888 } 3889 3890 /*@C 3891 DMPlexGetMeet - Get an array for the meet of the set of points 3892 3893 Not Collective 3894 3895 Input Parameters: 3896 + dm - The DMPlex object 3897 . numPoints - The number of input points for the meet 3898 - points - The input points 3899 3900 Output Parameters: 3901 + numCoveredPoints - The number of points in the meet 3902 - coveredPoints - The points in the meet 3903 3904 Level: intermediate 3905 3906 Note: Currently, this is restricted to a single level meet 3907 3908 Fortran Notes: 3909 Since it returns an array, this routine is only available in Fortran 90, and you must 3910 include petsc.h90 in your code. 3911 3912 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3913 3914 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 3915 @*/ 3916 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 3917 { 3918 DM_Plex *mesh = (DM_Plex*) dm->data; 3919 PetscInt *meet[2]; 3920 PetscInt meetSize, i = 0; 3921 PetscInt dof, off, p, c, m; 3922 PetscErrorCode ierr; 3923 3924 PetscFunctionBegin; 3925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3926 PetscValidPointer(points, 3); 3927 PetscValidPointer(numCoveringPoints, 4); 3928 PetscValidPointer(coveringPoints, 5); 3929 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 3930 ierr = DMGetWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 3931 /* Copy in cone of first point */ 3932 ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr); 3933 ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr); 3934 for (meetSize = 0; meetSize < dof; ++meetSize) { 3935 meet[i][meetSize] = mesh->cones[off+meetSize]; 3936 } 3937 /* Check each successive cone */ 3938 for (p = 1; p < numPoints; ++p) { 3939 PetscInt newMeetSize = 0; 3940 3941 ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr); 3942 ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr); 3943 for (c = 0; c < dof; ++c) { 3944 const PetscInt point = mesh->cones[off+c]; 3945 3946 for (m = 0; m < meetSize; ++m) { 3947 if (point == meet[i][m]) { 3948 meet[1-i][newMeetSize++] = point; 3949 break; 3950 } 3951 } 3952 } 3953 meetSize = newMeetSize; 3954 i = 1-i; 3955 } 3956 *numCoveringPoints = meetSize; 3957 *coveringPoints = meet[i]; 3958 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 3959 PetscFunctionReturn(0); 3960 } 3961 3962 /*@C 3963 DMPlexRestoreMeet - Restore an array for the meet of the set of points 3964 3965 Not Collective 3966 3967 Input Parameters: 3968 + dm - The DMPlex object 3969 . numPoints - The number of input points for the meet 3970 - points - The input points 3971 3972 Output Parameters: 3973 + numCoveredPoints - The number of points in the meet 3974 - coveredPoints - The points in the meet 3975 3976 Level: intermediate 3977 3978 Fortran Notes: 3979 Since it returns an array, this routine is only available in Fortran 90, and you must 3980 include petsc.h90 in your code. 3981 3982 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 3983 3984 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 3985 @*/ 3986 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 3987 { 3988 PetscErrorCode ierr; 3989 3990 PetscFunctionBegin; 3991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3992 if (points) PetscValidIntPointer(points,3); 3993 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 3994 PetscValidPointer(coveredPoints,5); 3995 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, (void*) coveredPoints);CHKERRQ(ierr); 3996 if (numCoveredPoints) *numCoveredPoints = 0; 3997 PetscFunctionReturn(0); 3998 } 3999 4000 /*@C 4001 DMPlexGetFullMeet - Get an array for the meet of the set of points 4002 4003 Not Collective 4004 4005 Input Parameters: 4006 + dm - The DMPlex object 4007 . numPoints - The number of input points for the meet 4008 - points - The input points 4009 4010 Output Parameters: 4011 + numCoveredPoints - The number of points in the meet 4012 - coveredPoints - The points in the meet 4013 4014 Level: intermediate 4015 4016 Fortran Notes: 4017 Since it returns an array, this routine is only available in Fortran 90, and you must 4018 include petsc.h90 in your code. 4019 4020 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 4021 4022 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 4023 @*/ 4024 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 4025 { 4026 DM_Plex *mesh = (DM_Plex*) dm->data; 4027 PetscInt *offsets, **closures; 4028 PetscInt *meet[2]; 4029 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 4030 PetscInt p, h, c, m, mc; 4031 PetscErrorCode ierr; 4032 4033 PetscFunctionBegin; 4034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4035 PetscValidPointer(points, 3); 4036 PetscValidPointer(numCoveredPoints, 4); 4037 PetscValidPointer(coveredPoints, 5); 4038 4039 ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr); 4040 ierr = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr); 4041 ierr = DMGetWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 4042 mc = mesh->maxConeSize; 4043 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 4044 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[0]);CHKERRQ(ierr); 4045 ierr = DMGetWorkArray(dm, maxSize, MPIU_INT, &meet[1]);CHKERRQ(ierr); 4046 4047 for (p = 0; p < numPoints; ++p) { 4048 PetscInt closureSize; 4049 4050 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr); 4051 4052 offsets[p*(height+2)+0] = 0; 4053 for (h = 0; h < height+1; ++h) { 4054 PetscInt pStart, pEnd, i; 4055 4056 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 4057 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 4058 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 4059 offsets[p*(height+2)+h+1] = i; 4060 break; 4061 } 4062 } 4063 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 4064 } 4065 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); 4066 } 4067 for (h = 0; h < height+1; ++h) { 4068 PetscInt dof; 4069 4070 /* Copy in cone of first point */ 4071 dof = offsets[h+1] - offsets[h]; 4072 for (meetSize = 0; meetSize < dof; ++meetSize) { 4073 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 4074 } 4075 /* Check each successive cone */ 4076 for (p = 1; p < numPoints && meetSize; ++p) { 4077 PetscInt newMeetSize = 0; 4078 4079 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 4080 for (c = 0; c < dof; ++c) { 4081 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 4082 4083 for (m = 0; m < meetSize; ++m) { 4084 if (point == meet[i][m]) { 4085 meet[1-i][newMeetSize++] = point; 4086 break; 4087 } 4088 } 4089 } 4090 meetSize = newMeetSize; 4091 i = 1-i; 4092 } 4093 if (meetSize) break; 4094 } 4095 *numCoveredPoints = meetSize; 4096 *coveredPoints = meet[i]; 4097 for (p = 0; p < numPoints; ++p) { 4098 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr); 4099 } 4100 ierr = PetscFree(closures);CHKERRQ(ierr); 4101 ierr = DMRestoreWorkArray(dm, numPoints*(height+2), MPIU_INT, &offsets);CHKERRQ(ierr); 4102 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, MPIU_INT, &meet[1-i]);CHKERRQ(ierr); 4103 PetscFunctionReturn(0); 4104 } 4105 4106 /*@C 4107 DMPlexEqual - Determine if two DMs have the same topology 4108 4109 Not Collective 4110 4111 Input Parameters: 4112 + dmA - A DMPlex object 4113 - dmB - A DMPlex object 4114 4115 Output Parameters: 4116 . equal - PETSC_TRUE if the topologies are identical 4117 4118 Level: intermediate 4119 4120 Notes: 4121 We are not solving graph isomorphism, so we do not permutation. 4122 4123 .seealso: DMPlexGetCone() 4124 @*/ 4125 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 4126 { 4127 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 4128 PetscErrorCode ierr; 4129 4130 PetscFunctionBegin; 4131 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4132 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4133 PetscValidPointer(equal, 3); 4134 4135 *equal = PETSC_FALSE; 4136 ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr); 4137 ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr); 4138 if (depth != depthB) PetscFunctionReturn(0); 4139 ierr = DMPlexGetChart(dmA, &pStart, &pEnd);CHKERRQ(ierr); 4140 ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr); 4141 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 4142 for (p = pStart; p < pEnd; ++p) { 4143 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 4144 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 4145 4146 ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr); 4147 ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr); 4148 ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr); 4149 ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr); 4150 ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr); 4151 ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr); 4152 if (coneSize != coneSizeB) PetscFunctionReturn(0); 4153 for (c = 0; c < coneSize; ++c) { 4154 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 4155 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 4156 } 4157 ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr); 4158 ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr); 4159 ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr); 4160 ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr); 4161 if (supportSize != supportSizeB) PetscFunctionReturn(0); 4162 for (s = 0; s < supportSize; ++s) { 4163 if (support[s] != supportB[s]) PetscFunctionReturn(0); 4164 } 4165 } 4166 *equal = PETSC_TRUE; 4167 PetscFunctionReturn(0); 4168 } 4169 4170 /*@C 4171 DMPlexGetNumFaceVertices - Returns the number of vertices on a face 4172 4173 Not Collective 4174 4175 Input Parameters: 4176 + dm - The DMPlex 4177 . cellDim - The cell dimension 4178 - numCorners - The number of vertices on a cell 4179 4180 Output Parameters: 4181 . numFaceVertices - The number of vertices on a face 4182 4183 Level: developer 4184 4185 Notes: 4186 Of course this can only work for a restricted set of symmetric shapes 4187 4188 .seealso: DMPlexGetCone() 4189 @*/ 4190 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 4191 { 4192 MPI_Comm comm; 4193 PetscErrorCode ierr; 4194 4195 PetscFunctionBegin; 4196 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 4197 PetscValidPointer(numFaceVertices,4); 4198 switch (cellDim) { 4199 case 0: 4200 *numFaceVertices = 0; 4201 break; 4202 case 1: 4203 *numFaceVertices = 1; 4204 break; 4205 case 2: 4206 switch (numCorners) { 4207 case 3: /* triangle */ 4208 *numFaceVertices = 2; /* Edge has 2 vertices */ 4209 break; 4210 case 4: /* quadrilateral */ 4211 *numFaceVertices = 2; /* Edge has 2 vertices */ 4212 break; 4213 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 4214 *numFaceVertices = 3; /* Edge has 3 vertices */ 4215 break; 4216 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 4217 *numFaceVertices = 3; /* Edge has 3 vertices */ 4218 break; 4219 default: 4220 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 4221 } 4222 break; 4223 case 3: 4224 switch (numCorners) { 4225 case 4: /* tetradehdron */ 4226 *numFaceVertices = 3; /* Face has 3 vertices */ 4227 break; 4228 case 6: /* tet cohesive cells */ 4229 *numFaceVertices = 4; /* Face has 4 vertices */ 4230 break; 4231 case 8: /* hexahedron */ 4232 *numFaceVertices = 4; /* Face has 4 vertices */ 4233 break; 4234 case 9: /* tet cohesive Lagrange cells */ 4235 *numFaceVertices = 6; /* Face has 6 vertices */ 4236 break; 4237 case 10: /* quadratic tetrahedron */ 4238 *numFaceVertices = 6; /* Face has 6 vertices */ 4239 break; 4240 case 12: /* hex cohesive Lagrange cells */ 4241 *numFaceVertices = 6; /* Face has 6 vertices */ 4242 break; 4243 case 18: /* quadratic tet cohesive Lagrange cells */ 4244 *numFaceVertices = 6; /* Face has 6 vertices */ 4245 break; 4246 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 4247 *numFaceVertices = 9; /* Face has 9 vertices */ 4248 break; 4249 default: 4250 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 4251 } 4252 break; 4253 default: 4254 SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim); 4255 } 4256 PetscFunctionReturn(0); 4257 } 4258 4259 /*@ 4260 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4261 4262 Not Collective 4263 4264 Input Parameter: 4265 . dm - The DMPlex object 4266 4267 Output Parameter: 4268 . depthLabel - The DMLabel recording point depth 4269 4270 Level: developer 4271 4272 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), 4273 @*/ 4274 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4275 { 4276 PetscFunctionBegin; 4277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4278 PetscValidPointer(depthLabel, 2); 4279 *depthLabel = dm->depthLabel; 4280 PetscFunctionReturn(0); 4281 } 4282 4283 /*@ 4284 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4285 4286 Not Collective 4287 4288 Input Parameter: 4289 . dm - The DMPlex object 4290 4291 Output Parameter: 4292 . depth - The number of strata (breadth first levels) in the DAG 4293 4294 Level: developer 4295 4296 Notes: 4297 This returns maximum of point depths over all points, i.e. maximum value of the label returned by DMPlexGetDepthLabel(). 4298 The point depth is described more in detail in DMPlexGetDepthStratum(). 4299 An empty mesh gives -1. 4300 4301 .seealso: DMPlexGetDepthLabel(), DMPlexGetDepthStratum(), DMPlexGetPointDepth(), DMPlexSymmetrize() 4302 @*/ 4303 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4304 { 4305 DMLabel label; 4306 PetscInt d = 0; 4307 PetscErrorCode ierr; 4308 4309 PetscFunctionBegin; 4310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4311 PetscValidPointer(depth, 2); 4312 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4313 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 4314 *depth = d-1; 4315 PetscFunctionReturn(0); 4316 } 4317 4318 /*@ 4319 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4320 4321 Not Collective 4322 4323 Input Parameters: 4324 + dm - The DMPlex object 4325 - stratumValue - The requested depth 4326 4327 Output Parameters: 4328 + start - The first point at this depth 4329 - end - One beyond the last point at this depth 4330 4331 Notes: 4332 Depth indexing is related to topological dimension. Depth stratum 0 contains the lowest topological dimension points, 4333 often "vertices". If the mesh is "interpolated" (see DMPlexInterpolate()), then depth stratum 1 contains the next 4334 higher dimension, e.g., "edges". 4335 4336 Level: developer 4337 4338 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth(), DMPlexGetDepthLabel(), DMPlexGetPointDepth(), DMPlexSymmetrize(), DMPlexInterpolate() 4339 @*/ 4340 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4341 { 4342 DMLabel label; 4343 PetscInt pStart, pEnd; 4344 PetscErrorCode ierr; 4345 4346 PetscFunctionBegin; 4347 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4348 if (start) {PetscValidPointer(start, 3); *start = 0;} 4349 if (end) {PetscValidPointer(end, 4); *end = 0;} 4350 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4351 if (pStart == pEnd) PetscFunctionReturn(0); 4352 if (stratumValue < 0) { 4353 if (start) *start = pStart; 4354 if (end) *end = pEnd; 4355 PetscFunctionReturn(0); 4356 } 4357 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4358 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4359 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 4360 PetscFunctionReturn(0); 4361 } 4362 4363 /*@ 4364 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4365 4366 Not Collective 4367 4368 Input Parameters: 4369 + dm - The DMPlex object 4370 - stratumValue - The requested height 4371 4372 Output Parameters: 4373 + start - The first point at this height 4374 - end - One beyond the last point at this height 4375 4376 Notes: 4377 Height indexing is related to topological codimension. Height stratum 0 contains the highest topological dimension 4378 points, often called "cells" or "elements". If the mesh is "interpolated" (see DMPlexInterpolate()), then height 4379 stratum 1 contains the boundary of these "cells", often called "faces" or "facets". 4380 4381 Level: developer 4382 4383 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth(), DMPlexGetPointHeight() 4384 @*/ 4385 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4386 { 4387 DMLabel label; 4388 PetscInt depth, pStart, pEnd; 4389 PetscErrorCode ierr; 4390 4391 PetscFunctionBegin; 4392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4393 if (start) {PetscValidPointer(start, 3); *start = 0;} 4394 if (end) {PetscValidPointer(end, 4); *end = 0;} 4395 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4396 if (pStart == pEnd) PetscFunctionReturn(0); 4397 if (stratumValue < 0) { 4398 if (start) *start = pStart; 4399 if (end) *end = pEnd; 4400 PetscFunctionReturn(0); 4401 } 4402 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4403 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4404 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 4405 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 4406 PetscFunctionReturn(0); 4407 } 4408 4409 /*@ 4410 DMPlexGetPointDepth - Get the depth of a given point 4411 4412 Not Collective 4413 4414 Input Parameter: 4415 + dm - The DMPlex object 4416 - point - The point 4417 4418 Output Parameter: 4419 . depth - The depth of the point 4420 4421 Level: intermediate 4422 4423 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointHeight() 4424 @*/ 4425 PetscErrorCode DMPlexGetPointDepth(DM dm, PetscInt point, PetscInt *depth) 4426 { 4427 PetscErrorCode ierr; 4428 4429 PetscFunctionBegin; 4430 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4431 PetscValidIntPointer(depth, 3); 4432 ierr = DMLabelGetValue(dm->depthLabel, point, depth);CHKERRQ(ierr); 4433 PetscFunctionReturn(0); 4434 } 4435 4436 /*@ 4437 DMPlexGetPointHeight - Get the height of a given point 4438 4439 Not Collective 4440 4441 Input Parameter: 4442 + dm - The DMPlex object 4443 - point - The point 4444 4445 Output Parameter: 4446 . height - The height of the point 4447 4448 Level: intermediate 4449 4450 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexGetPointDepth() 4451 @*/ 4452 PetscErrorCode DMPlexGetPointHeight(DM dm, PetscInt point, PetscInt *height) 4453 { 4454 PetscInt n, pDepth; 4455 PetscErrorCode ierr; 4456 4457 PetscFunctionBegin; 4458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4459 PetscValidIntPointer(height, 3); 4460 ierr = DMLabelGetNumValues(dm->depthLabel, &n);CHKERRQ(ierr); 4461 ierr = DMLabelGetValue(dm->depthLabel, point, &pDepth);CHKERRQ(ierr); 4462 *height = n - 1 - pDepth; /* DAG depth is n-1 */ 4463 PetscFunctionReturn(0); 4464 } 4465 4466 /*@ 4467 DMPlexGetCellTypeLabel - Get the DMLabel recording the polytope type of each cell 4468 4469 Not Collective 4470 4471 Input Parameter: 4472 . dm - The DMPlex object 4473 4474 Output Parameter: 4475 . celltypeLabel - The DMLabel recording cell polytope type 4476 4477 Note: This function will trigger automatica computation of cell types. This can be disabled by calling 4478 DMCreateLabel(dm, "celltype") beforehand. 4479 4480 Level: developer 4481 4482 .seealso: DMPlexGetCellType(), DMPlexGetDepthLabel(), DMCreateLabel() 4483 @*/ 4484 PetscErrorCode DMPlexGetCellTypeLabel(DM dm, DMLabel *celltypeLabel) 4485 { 4486 PetscErrorCode ierr; 4487 4488 PetscFunctionBegin; 4489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4490 PetscValidPointer(celltypeLabel, 2); 4491 if (!dm->celltypeLabel) {ierr = DMPlexComputeCellTypes(dm);CHKERRQ(ierr);} 4492 *celltypeLabel = dm->celltypeLabel; 4493 PetscFunctionReturn(0); 4494 } 4495 4496 /*@ 4497 DMPlexGetCellType - Get the polytope type of a given cell 4498 4499 Not Collective 4500 4501 Input Parameter: 4502 + dm - The DMPlex object 4503 - cell - The cell 4504 4505 Output Parameter: 4506 . celltype - The polytope type of the cell 4507 4508 Level: intermediate 4509 4510 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth() 4511 @*/ 4512 PetscErrorCode DMPlexGetCellType(DM dm, PetscInt cell, DMPolytopeType *celltype) 4513 { 4514 DMLabel label; 4515 PetscInt ct; 4516 PetscErrorCode ierr; 4517 4518 PetscFunctionBegin; 4519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4520 PetscValidPointer(celltype, 3); 4521 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 4522 ierr = DMLabelGetValue(label, cell, &ct);CHKERRQ(ierr); 4523 if (ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %D has not been assigned a cell type", cell); 4524 *celltype = (DMPolytopeType) ct; 4525 PetscFunctionReturn(0); 4526 } 4527 4528 /*@ 4529 DMPlexSetCellType - Set the polytope type of a given cell 4530 4531 Not Collective 4532 4533 Input Parameters: 4534 + dm - The DMPlex object 4535 . cell - The cell 4536 - celltype - The polytope type of the cell 4537 4538 Note: By default, cell types will be automatically computed using DMPlexComputeCellTypes() before this function 4539 is executed. This function will override the computed type. However, if automatic classification will not succeed 4540 and a user wants to manually specify all types, the classification must be disabled by calling 4541 DMCreaateLabel(dm, "celltype") before getting or setting any cell types. 4542 4543 Level: advanced 4544 4545 .seealso: DMPlexGetCellTypeLabel(), DMPlexGetDepthLabel(), DMPlexGetDepth(), DMPlexComputeCellTypes(), DMCreateLabel() 4546 @*/ 4547 PetscErrorCode DMPlexSetCellType(DM dm, PetscInt cell, DMPolytopeType celltype) 4548 { 4549 DMLabel label; 4550 PetscErrorCode ierr; 4551 4552 PetscFunctionBegin; 4553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4554 ierr = DMPlexGetCellTypeLabel(dm, &label);CHKERRQ(ierr); 4555 ierr = DMLabelSetValue(label, cell, celltype);CHKERRQ(ierr); 4556 PetscFunctionReturn(0); 4557 } 4558 4559 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 4560 { 4561 PetscSection section, s; 4562 Mat m; 4563 PetscInt maxHeight; 4564 PetscErrorCode ierr; 4565 4566 PetscFunctionBegin; 4567 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 4568 ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr); 4569 ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr); 4570 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 4571 ierr = DMSetLocalSection(*cdm, section);CHKERRQ(ierr); 4572 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 4573 ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr); 4574 ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr); 4575 ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr); 4576 ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 4577 ierr = MatDestroy(&m);CHKERRQ(ierr); 4578 4579 ierr = DMSetNumFields(*cdm, 1);CHKERRQ(ierr); 4580 ierr = DMCreateDS(*cdm);CHKERRQ(ierr); 4581 PetscFunctionReturn(0); 4582 } 4583 4584 PetscErrorCode DMCreateCoordinateField_Plex(DM dm, DMField *field) 4585 { 4586 Vec coordsLocal; 4587 DM coordsDM; 4588 PetscErrorCode ierr; 4589 4590 PetscFunctionBegin; 4591 *field = NULL; 4592 ierr = DMGetCoordinatesLocal(dm,&coordsLocal);CHKERRQ(ierr); 4593 ierr = DMGetCoordinateDM(dm,&coordsDM);CHKERRQ(ierr); 4594 if (coordsLocal && coordsDM) { 4595 ierr = DMFieldCreateDS(coordsDM, 0, coordsLocal, field);CHKERRQ(ierr); 4596 } 4597 PetscFunctionReturn(0); 4598 } 4599 4600 /*@C 4601 DMPlexGetConeSection - Return a section which describes the layout of cone data 4602 4603 Not Collective 4604 4605 Input Parameters: 4606 . dm - The DMPlex object 4607 4608 Output Parameter: 4609 . section - The PetscSection object 4610 4611 Level: developer 4612 4613 .seealso: DMPlexGetSupportSection(), DMPlexGetCones(), DMPlexGetConeOrientations() 4614 @*/ 4615 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 4616 { 4617 DM_Plex *mesh = (DM_Plex*) dm->data; 4618 4619 PetscFunctionBegin; 4620 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4621 if (section) *section = mesh->coneSection; 4622 PetscFunctionReturn(0); 4623 } 4624 4625 /*@C 4626 DMPlexGetSupportSection - Return a section which describes the layout of support data 4627 4628 Not Collective 4629 4630 Input Parameters: 4631 . dm - The DMPlex object 4632 4633 Output Parameter: 4634 . section - The PetscSection object 4635 4636 Level: developer 4637 4638 .seealso: DMPlexGetConeSection() 4639 @*/ 4640 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 4641 { 4642 DM_Plex *mesh = (DM_Plex*) dm->data; 4643 4644 PetscFunctionBegin; 4645 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4646 if (section) *section = mesh->supportSection; 4647 PetscFunctionReturn(0); 4648 } 4649 4650 /*@C 4651 DMPlexGetCones - Return cone data 4652 4653 Not Collective 4654 4655 Input Parameters: 4656 . dm - The DMPlex object 4657 4658 Output Parameter: 4659 . cones - The cone for each point 4660 4661 Level: developer 4662 4663 .seealso: DMPlexGetConeSection() 4664 @*/ 4665 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 4666 { 4667 DM_Plex *mesh = (DM_Plex*) dm->data; 4668 4669 PetscFunctionBegin; 4670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4671 if (cones) *cones = mesh->cones; 4672 PetscFunctionReturn(0); 4673 } 4674 4675 /*@C 4676 DMPlexGetConeOrientations - Return cone orientation data 4677 4678 Not Collective 4679 4680 Input Parameters: 4681 . dm - The DMPlex object 4682 4683 Output Parameter: 4684 . coneOrientations - The cone orientation for each point 4685 4686 Level: developer 4687 4688 .seealso: DMPlexGetConeSection() 4689 @*/ 4690 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 4691 { 4692 DM_Plex *mesh = (DM_Plex*) dm->data; 4693 4694 PetscFunctionBegin; 4695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4696 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 4697 PetscFunctionReturn(0); 4698 } 4699 4700 /******************************** FEM Support **********************************/ 4701 4702 /* 4703 Returns number of components and tensor degree for the field. For interpolated meshes, line should be a point 4704 representing a line in the section. 4705 */ 4706 static PetscErrorCode PetscSectionFieldGetTensorDegree_Private(PetscSection section,PetscInt field,PetscInt line,PetscBool vertexchart,PetscInt *Nc,PetscInt *k) 4707 { 4708 PetscErrorCode ierr; 4709 4710 PetscFunctionBeginHot; 4711 ierr = PetscSectionGetFieldComponents(section, field, Nc);CHKERRQ(ierr); 4712 if (line < 0) { 4713 *k = 0; 4714 *Nc = 0; 4715 } else if (vertexchart) { /* If we only have a vertex chart, we must have degree k=1 */ 4716 *k = 1; 4717 } else { /* Assume the full interpolated mesh is in the chart; lines in particular */ 4718 /* An order k SEM disc has k-1 dofs on an edge */ 4719 ierr = PetscSectionGetFieldDof(section, line, field, k);CHKERRQ(ierr); 4720 *k = *k / *Nc + 1; 4721 } 4722 PetscFunctionReturn(0); 4723 } 4724 4725 /*@ 4726 4727 DMPlexSetClosurePermutationTensor - Create a permutation from the default (BFS) point ordering in the closure, to a 4728 lexicographic ordering over the tensor product cell (i.e., line, quad, hex, etc.), and set this permutation in the 4729 section provided (or the section of the DM). 4730 4731 Input Parameters: 4732 + dm - The DM 4733 . point - Either a cell (highest dim point) or an edge (dim 1 point), or PETSC_DETERMINE 4734 - section - The PetscSection to reorder, or NULL for the default section 4735 4736 Note: The point is used to determine the number of dofs/field on an edge. For SEM, this is related to the polynomial 4737 degree of the basis. 4738 4739 Example: 4740 A typical interpolated single-quad mesh might order points as 4741 .vb 4742 [c0, v1, v2, v3, v4, e5, e6, e7, e8] 4743 4744 v4 -- e6 -- v3 4745 | | 4746 e7 c0 e8 4747 | | 4748 v1 -- e5 -- v2 4749 .ve 4750 4751 (There is no significance to the ordering described here.) The default section for a Q3 quad might typically assign 4752 dofs in the order of points, e.g., 4753 .vb 4754 c0 -> [0,1,2,3] 4755 v1 -> [4] 4756 ... 4757 e5 -> [8, 9] 4758 .ve 4759 4760 which corresponds to the dofs 4761 .vb 4762 6 10 11 7 4763 13 2 3 15 4764 12 0 1 14 4765 4 8 9 5 4766 .ve 4767 4768 The closure in BFS ordering works through height strata (cells, edges, vertices) to produce the ordering 4769 .vb 4770 0 1 2 3 8 9 14 15 11 10 13 12 4 5 7 6 4771 .ve 4772 4773 After calling DMPlexSetClosurePermutationTensor(), the closure will be ordered lexicographically, 4774 .vb 4775 4 8 9 5 12 0 1 14 13 2 3 15 6 10 11 7 4776 .ve 4777 4778 Level: developer 4779 4780 .seealso: DMGetLocalSection(), PetscSectionSetClosurePermutation(), DMSetGlobalSection() 4781 @*/ 4782 PetscErrorCode DMPlexSetClosurePermutationTensor(DM dm, PetscInt point, PetscSection section) 4783 { 4784 DMLabel label; 4785 PetscInt dim, depth = -1, eStart = -1, Nf; 4786 PetscBool vertexchart; 4787 PetscErrorCode ierr; 4788 4789 PetscFunctionBegin; 4790 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4791 if (dim < 1) PetscFunctionReturn(0); 4792 if (point < 0) { 4793 PetscInt sStart,sEnd; 4794 4795 ierr = DMPlexGetDepthStratum(dm, 1, &sStart, &sEnd);CHKERRQ(ierr); 4796 point = sEnd-sStart ? sStart : point; 4797 } 4798 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4799 if (point >= 0) { ierr = DMLabelGetValue(label, point, &depth);CHKERRQ(ierr); } 4800 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 4801 if (depth == 1) {eStart = point;} 4802 else if (depth == dim) { 4803 const PetscInt *cone; 4804 4805 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4806 if (dim == 2) eStart = cone[0]; 4807 else if (dim == 3) { 4808 const PetscInt *cone2; 4809 ierr = DMPlexGetCone(dm, cone[0], &cone2);CHKERRQ(ierr); 4810 eStart = cone2[0]; 4811 } 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); 4812 } 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); 4813 { /* Determine whether the chart covers all points or just vertices. */ 4814 PetscInt pStart,pEnd,cStart,cEnd; 4815 ierr = DMPlexGetDepthStratum(dm,0,&pStart,&pEnd);CHKERRQ(ierr); 4816 ierr = PetscSectionGetChart(section,&cStart,&cEnd);CHKERRQ(ierr); 4817 if (pStart == cStart && pEnd == cEnd) vertexchart = PETSC_TRUE; /* Just vertices */ 4818 else vertexchart = PETSC_FALSE; /* Assume all interpolated points are in chart */ 4819 } 4820 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 4821 for (PetscInt d=1; d<=dim; d++) { 4822 PetscInt k, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 4823 PetscInt *perm; 4824 4825 for (f = 0; f < Nf; ++f) { 4826 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4827 size += PetscPowInt(k+1, d)*Nc; 4828 } 4829 ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr); 4830 for (f = 0; f < Nf; ++f) { 4831 switch (d) { 4832 case 1: 4833 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4834 /* 4835 Original ordering is [ edge of length k-1; vtx0; vtx1 ] 4836 We want [ vtx0; edge of length k-1; vtx1 ] 4837 */ 4838 for (c=0; c<Nc; c++,offset++) perm[offset] = (k-1)*Nc + c + foffset; 4839 for (i=0; i<k-1; i++) for (c=0; c<Nc; c++,offset++) perm[offset] = i*Nc + c + foffset; 4840 for (c=0; c<Nc; c++,offset++) perm[offset] = k*Nc + c + foffset; 4841 foffset = offset; 4842 break; 4843 case 2: 4844 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 4845 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4846 /* The SEM order is 4847 4848 v_lb, {e_b}, v_rb, 4849 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 4850 v_lt, reverse {e_t}, v_rt 4851 */ 4852 { 4853 const PetscInt of = 0; 4854 const PetscInt oeb = of + PetscSqr(k-1); 4855 const PetscInt oer = oeb + (k-1); 4856 const PetscInt oet = oer + (k-1); 4857 const PetscInt oel = oet + (k-1); 4858 const PetscInt ovlb = oel + (k-1); 4859 const PetscInt ovrb = ovlb + 1; 4860 const PetscInt ovrt = ovrb + 1; 4861 const PetscInt ovlt = ovrt + 1; 4862 PetscInt o; 4863 4864 /* bottom */ 4865 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 4866 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4867 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 4868 /* middle */ 4869 for (i = 0; i < k-1; ++i) { 4870 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 4871 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; 4872 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 4873 } 4874 /* top */ 4875 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 4876 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4877 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 4878 foffset = offset; 4879 } 4880 break; 4881 case 3: 4882 /* The original hex closure is 4883 4884 {c, 4885 f_b, f_t, f_f, f_b, f_r, f_l, 4886 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 4887 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 4888 */ 4889 ierr = PetscSectionFieldGetTensorDegree_Private(section,f,eStart,vertexchart,&Nc,&k);CHKERRQ(ierr); 4890 /* The SEM order is 4891 Bottom Slice 4892 v_blf, {e^{(k-1)-n}_bf}, v_brf, 4893 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 4894 v_blb, {e_bb}, v_brb, 4895 4896 Middle Slice (j) 4897 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 4898 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 4899 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 4900 4901 Top Slice 4902 v_tlf, {e_tf}, v_trf, 4903 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 4904 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 4905 */ 4906 { 4907 const PetscInt oc = 0; 4908 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 4909 const PetscInt oft = ofb + PetscSqr(k-1); 4910 const PetscInt off = oft + PetscSqr(k-1); 4911 const PetscInt ofk = off + PetscSqr(k-1); 4912 const PetscInt ofr = ofk + PetscSqr(k-1); 4913 const PetscInt ofl = ofr + PetscSqr(k-1); 4914 const PetscInt oebl = ofl + PetscSqr(k-1); 4915 const PetscInt oebb = oebl + (k-1); 4916 const PetscInt oebr = oebb + (k-1); 4917 const PetscInt oebf = oebr + (k-1); 4918 const PetscInt oetf = oebf + (k-1); 4919 const PetscInt oetr = oetf + (k-1); 4920 const PetscInt oetb = oetr + (k-1); 4921 const PetscInt oetl = oetb + (k-1); 4922 const PetscInt oerf = oetl + (k-1); 4923 const PetscInt oelf = oerf + (k-1); 4924 const PetscInt oelb = oelf + (k-1); 4925 const PetscInt oerb = oelb + (k-1); 4926 const PetscInt ovblf = oerb + (k-1); 4927 const PetscInt ovblb = ovblf + 1; 4928 const PetscInt ovbrb = ovblb + 1; 4929 const PetscInt ovbrf = ovbrb + 1; 4930 const PetscInt ovtlf = ovbrf + 1; 4931 const PetscInt ovtrf = ovtlf + 1; 4932 const PetscInt ovtrb = ovtrf + 1; 4933 const PetscInt ovtlb = ovtrb + 1; 4934 PetscInt o, n; 4935 4936 /* Bottom Slice */ 4937 /* bottom */ 4938 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 4939 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4940 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 4941 /* middle */ 4942 for (i = 0; i < k-1; ++i) { 4943 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 4944 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;} 4945 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 4946 } 4947 /* top */ 4948 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 4949 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4950 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 4951 4952 /* Middle Slice */ 4953 for (j = 0; j < k-1; ++j) { 4954 /* bottom */ 4955 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 4956 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; 4957 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 4958 /* middle */ 4959 for (i = 0; i < k-1; ++i) { 4960 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 4961 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; 4962 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 4963 } 4964 /* top */ 4965 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 4966 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; 4967 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 4968 } 4969 4970 /* Top Slice */ 4971 /* bottom */ 4972 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 4973 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4974 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 4975 /* middle */ 4976 for (i = 0; i < k-1; ++i) { 4977 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 4978 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 4979 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 4980 } 4981 /* top */ 4982 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 4983 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 4984 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 4985 4986 foffset = offset; 4987 } 4988 break; 4989 default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", d); 4990 } 4991 } 4992 if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size); 4993 /* Check permutation */ 4994 { 4995 PetscInt *check; 4996 4997 ierr = PetscMalloc1(size, &check);CHKERRQ(ierr); 4998 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]);} 4999 for (i = 0; i < size; ++i) check[perm[i]] = i; 5000 for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);} 5001 ierr = PetscFree(check);CHKERRQ(ierr); 5002 } 5003 ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, d, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr); 5004 } 5005 PetscFunctionReturn(0); 5006 } 5007 5008 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 5009 { 5010 PetscDS prob; 5011 PetscInt depth, Nf, h; 5012 DMLabel label; 5013 PetscErrorCode ierr; 5014 5015 PetscFunctionBeginHot; 5016 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 5017 Nf = prob->Nf; 5018 label = dm->depthLabel; 5019 *dspace = NULL; 5020 if (field < Nf) { 5021 PetscObject disc = prob->disc[field]; 5022 5023 if (disc->classid == PETSCFE_CLASSID) { 5024 PetscDualSpace dsp; 5025 5026 ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr); 5027 ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr); 5028 ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr); 5029 h = depth - 1 - h; 5030 if (h) { 5031 ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr); 5032 } else { 5033 *dspace = dsp; 5034 } 5035 } 5036 } 5037 PetscFunctionReturn(0); 5038 } 5039 5040 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5041 { 5042 PetscScalar *array, *vArray; 5043 const PetscInt *cone, *coneO; 5044 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 5045 PetscErrorCode ierr; 5046 5047 PetscFunctionBeginHot; 5048 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5049 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 5050 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5051 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 5052 if (!values || !*values) { 5053 if ((point >= pStart) && (point < pEnd)) { 5054 PetscInt dof; 5055 5056 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5057 size += dof; 5058 } 5059 for (p = 0; p < numPoints; ++p) { 5060 const PetscInt cp = cone[p]; 5061 PetscInt dof; 5062 5063 if ((cp < pStart) || (cp >= pEnd)) continue; 5064 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5065 size += dof; 5066 } 5067 if (!values) { 5068 if (csize) *csize = size; 5069 PetscFunctionReturn(0); 5070 } 5071 ierr = DMGetWorkArray(dm, size, MPIU_SCALAR, &array);CHKERRQ(ierr); 5072 } else { 5073 array = *values; 5074 } 5075 size = 0; 5076 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 5077 if ((point >= pStart) && (point < pEnd)) { 5078 PetscInt dof, off, d; 5079 PetscScalar *varr; 5080 5081 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5082 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5083 varr = &vArray[off]; 5084 for (d = 0; d < dof; ++d, ++offset) { 5085 array[offset] = varr[d]; 5086 } 5087 size += dof; 5088 } 5089 for (p = 0; p < numPoints; ++p) { 5090 const PetscInt cp = cone[p]; 5091 PetscInt o = coneO[p]; 5092 PetscInt dof, off, d; 5093 PetscScalar *varr; 5094 5095 if ((cp < pStart) || (cp >= pEnd)) continue; 5096 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5097 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 5098 varr = &vArray[off]; 5099 if (o >= 0) { 5100 for (d = 0; d < dof; ++d, ++offset) { 5101 array[offset] = varr[d]; 5102 } 5103 } else { 5104 for (d = dof-1; d >= 0; --d, ++offset) { 5105 array[offset] = varr[d]; 5106 } 5107 } 5108 size += dof; 5109 } 5110 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 5111 if (!*values) { 5112 if (csize) *csize = size; 5113 *values = array; 5114 } else { 5115 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 5116 *csize = size; 5117 } 5118 PetscFunctionReturn(0); 5119 } 5120 5121 /* Compress out points not in the section */ 5122 PETSC_STATIC_INLINE PetscErrorCode CompressPoints_Private(PetscSection section, PetscInt *numPoints, PetscInt points[]) 5123 { 5124 const PetscInt np = *numPoints; 5125 PetscInt pStart, pEnd, p, q; 5126 PetscErrorCode ierr; 5127 5128 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5129 for (p = 0, q = 0; p < np; ++p) { 5130 const PetscInt r = points[p*2]; 5131 if ((r >= pStart) && (r < pEnd)) { 5132 points[q*2] = r; 5133 points[q*2+1] = points[p*2+1]; 5134 ++q; 5135 } 5136 } 5137 *numPoints = q; 5138 return 0; 5139 } 5140 5141 static PetscErrorCode DMPlexTransitiveClosure_Hybrid_Internal(DM dm, PetscInt point, PetscInt np, PetscInt *numPoints, PetscInt **points) 5142 { 5143 const PetscInt *cone, *ornt; 5144 PetscInt *pts, *closure = NULL; 5145 PetscInt dim, coneSize, c, d, clSize, cl; 5146 PetscErrorCode ierr; 5147 5148 PetscFunctionBeginHot; 5149 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5150 ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr); 5151 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5152 ierr = DMPlexGetConeOrientation(dm, point, &ornt);CHKERRQ(ierr); 5153 ierr = DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 5154 ierr = DMGetWorkArray(dm, np*2, MPIU_INT, &pts);CHKERRQ(ierr); 5155 c = 0; 5156 pts[c*2+0] = point; 5157 pts[c*2+1] = 0; 5158 ++c; 5159 for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];} 5160 ierr = DMPlexGetTransitiveClosure(dm, cone[1], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 5161 for (cl = 0; cl < clSize*2; cl += 2, ++c) {pts[c*2+0] = closure[cl]; pts[c*2+1] = closure[cl+1];} 5162 ierr = DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 5163 if (dim >= 2) { 5164 for (d = 2; d < coneSize; ++d, ++c) {pts[c*2+0] = cone[d]; pts[c*2+1] = ornt[d];} 5165 } 5166 if (dim >= 3) { 5167 for (d = 2; d < coneSize; ++d) { 5168 const PetscInt fpoint = cone[d]; 5169 const PetscInt *fcone; 5170 PetscInt fconeSize, fc, i; 5171 5172 ierr = DMPlexGetConeSize(dm, fpoint, &fconeSize);CHKERRQ(ierr); 5173 ierr = DMPlexGetCone(dm, fpoint, &fcone);CHKERRQ(ierr); 5174 for (fc = 0; fc < fconeSize; ++fc) { 5175 for (i = 0; i < c; ++i) if (pts[i*2] == fcone[fc]) break; 5176 if (i == c) {pts[c*2+0] = fcone[fc]; pts[c*2+1] = 0; ++c;} 5177 } 5178 } 5179 } 5180 if (c != np) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid closure for hybrid point %D, size %D != %D", point, c, np); 5181 *numPoints = np; 5182 *points = pts; 5183 PetscFunctionReturn(0); 5184 } 5185 5186 /* Compressed closure does not apply closure permutation */ 5187 PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5188 { 5189 const PetscInt *cla = NULL; 5190 PetscInt np, *pts = NULL; 5191 PetscErrorCode ierr; 5192 5193 PetscFunctionBeginHot; 5194 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr); 5195 if (*clPoints) { 5196 PetscInt dof, off; 5197 5198 ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr); 5199 ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr); 5200 ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr); 5201 np = dof/2; 5202 pts = (PetscInt *) &cla[off]; 5203 } else { 5204 DMPolytopeType ct; 5205 5206 /* Do not make the label if it does not exist */ 5207 if (!dm->celltypeLabel) {ct = DM_POLYTOPE_POINT;} 5208 else {ierr = DMPlexGetCellType(dm, point, &ct);CHKERRQ(ierr);} 5209 switch (ct) { 5210 case DM_POLYTOPE_SEG_PRISM_TENSOR: 5211 ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 9, &np, &pts);CHKERRQ(ierr); 5212 break; 5213 case DM_POLYTOPE_TRI_PRISM_TENSOR: 5214 ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 21, &np, &pts);CHKERRQ(ierr); 5215 break; 5216 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 5217 ierr = DMPlexTransitiveClosure_Hybrid_Internal(dm, point, 27, &np, &pts);CHKERRQ(ierr); 5218 break; 5219 default: 5220 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr); 5221 } 5222 ierr = CompressPoints_Private(section, &np, pts);CHKERRQ(ierr); 5223 } 5224 *numPoints = np; 5225 *points = pts; 5226 *clp = cla; 5227 PetscFunctionReturn(0); 5228 } 5229 5230 PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 5231 { 5232 PetscErrorCode ierr; 5233 5234 PetscFunctionBeginHot; 5235 if (!*clPoints) { 5236 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr); 5237 } else { 5238 ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr); 5239 } 5240 *numPoints = 0; 5241 *points = NULL; 5242 *clSec = NULL; 5243 *clPoints = NULL; 5244 *clp = NULL; 5245 PetscFunctionReturn(0); 5246 } 5247 5248 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[]) 5249 { 5250 PetscInt offset = 0, p; 5251 const PetscInt **perms = NULL; 5252 const PetscScalar **flips = NULL; 5253 PetscErrorCode ierr; 5254 5255 PetscFunctionBeginHot; 5256 *size = 0; 5257 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5258 for (p = 0; p < numPoints; p++) { 5259 const PetscInt point = points[2*p]; 5260 const PetscInt *perm = perms ? perms[p] : NULL; 5261 const PetscScalar *flip = flips ? flips[p] : NULL; 5262 PetscInt dof, off, d; 5263 const PetscScalar *varr; 5264 5265 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5266 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5267 varr = &vArray[off]; 5268 if (clperm) { 5269 if (perm) { 5270 for (d = 0; d < dof; d++) array[clperm[offset + perm[d]]] = varr[d]; 5271 } else { 5272 for (d = 0; d < dof; d++) array[clperm[offset + d ]] = varr[d]; 5273 } 5274 if (flip) { 5275 for (d = 0; d < dof; d++) array[clperm[offset + d ]] *= flip[d]; 5276 } 5277 } else { 5278 if (perm) { 5279 for (d = 0; d < dof; d++) array[offset + perm[d]] = varr[d]; 5280 } else { 5281 for (d = 0; d < dof; d++) array[offset + d ] = varr[d]; 5282 } 5283 if (flip) { 5284 for (d = 0; d < dof; d++) array[offset + d ] *= flip[d]; 5285 } 5286 } 5287 offset += dof; 5288 } 5289 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5290 *size = offset; 5291 PetscFunctionReturn(0); 5292 } 5293 5294 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[]) 5295 { 5296 PetscInt offset = 0, f; 5297 PetscErrorCode ierr; 5298 5299 PetscFunctionBeginHot; 5300 *size = 0; 5301 for (f = 0; f < numFields; ++f) { 5302 PetscInt p; 5303 const PetscInt **perms = NULL; 5304 const PetscScalar **flips = NULL; 5305 5306 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5307 for (p = 0; p < numPoints; p++) { 5308 const PetscInt point = points[2*p]; 5309 PetscInt fdof, foff, b; 5310 const PetscScalar *varr; 5311 const PetscInt *perm = perms ? perms[p] : NULL; 5312 const PetscScalar *flip = flips ? flips[p] : NULL; 5313 5314 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5315 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 5316 varr = &vArray[foff]; 5317 if (clperm) { 5318 if (perm) {for (b = 0; b < fdof; b++) {array[clperm[offset + perm[b]]] = varr[b];}} 5319 else {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] = varr[b];}} 5320 if (flip) {for (b = 0; b < fdof; b++) {array[clperm[offset + b ]] *= flip[b];}} 5321 } else { 5322 if (perm) {for (b = 0; b < fdof; b++) {array[offset + perm[b]] = varr[b];}} 5323 else {for (b = 0; b < fdof; b++) {array[offset + b ] = varr[b];}} 5324 if (flip) {for (b = 0; b < fdof; b++) {array[offset + b ] *= flip[b];}} 5325 } 5326 offset += fdof; 5327 } 5328 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5329 } 5330 *size = offset; 5331 PetscFunctionReturn(0); 5332 } 5333 5334 /*@C 5335 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 5336 5337 Not collective 5338 5339 Input Parameters: 5340 + dm - The DM 5341 . section - The section describing the layout in v, or NULL to use the default section 5342 . v - The local vector 5343 . point - The point in the DM 5344 . csize - The size of the input values array, or NULL 5345 - values - An array to use for the values, or NULL to have it allocated automatically 5346 5347 Output Parameters: 5348 + csize - The number of values in the closure 5349 - values - The array of values. If the user provided NULL, it is a borrowed array and should not be freed 5350 5351 $ Note that DMPlexVecGetClosure/DMPlexVecRestoreClosure only allocates the values array if it set to NULL in the 5352 $ calling function. This is because DMPlexVecGetClosure() is typically called in the inner loop of a Vec or Mat 5353 $ assembly function, and a user may already have allocated storage for this operation. 5354 $ 5355 $ A typical use could be 5356 $ 5357 $ values = NULL; 5358 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 5359 $ for (cl = 0; cl < clSize; ++cl) { 5360 $ <Compute on closure> 5361 $ } 5362 $ ierr = DMPlexVecRestoreClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 5363 $ 5364 $ or 5365 $ 5366 $ PetscMalloc1(clMaxSize, &values); 5367 $ for (p = pStart; p < pEnd; ++p) { 5368 $ clSize = clMaxSize; 5369 $ ierr = DMPlexVecGetClosure(dm, NULL, v, p, &clSize, &values);CHKERRQ(ierr); 5370 $ for (cl = 0; cl < clSize; ++cl) { 5371 $ <Compute on closure> 5372 $ } 5373 $ } 5374 $ PetscFree(values); 5375 5376 Fortran Notes: 5377 Since it returns an array, this routine is only available in Fortran 90, and you must 5378 include petsc.h90 in your code. 5379 5380 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5381 5382 Level: intermediate 5383 5384 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5385 @*/ 5386 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5387 { 5388 PetscSection clSection; 5389 IS clPoints; 5390 PetscInt *points = NULL; 5391 const PetscInt *clp, *perm; 5392 PetscInt depth, numFields, numPoints, asize; 5393 PetscErrorCode ierr; 5394 5395 PetscFunctionBeginHot; 5396 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5397 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5398 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5399 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5400 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5401 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5402 if (depth == 1 && numFields < 2) { 5403 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 5404 PetscFunctionReturn(0); 5405 } 5406 /* Get points */ 5407 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5408 /* Get sizes */ 5409 asize = 0; 5410 for (PetscInt p = 0; p < numPoints*2; p += 2) { 5411 PetscInt dof; 5412 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5413 asize += dof; 5414 } 5415 if (values) { 5416 const PetscScalar *vArray; 5417 PetscInt size; 5418 5419 if (*values) { 5420 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); 5421 } else {ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, values);CHKERRQ(ierr);} 5422 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, asize, &perm);CHKERRQ(ierr); 5423 ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr); 5424 /* Get values */ 5425 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, numPoints, points, numFields, perm, vArray, &size, *values);CHKERRQ(ierr);} 5426 else {ierr = DMPlexVecGetClosure_Static(dm, section, numPoints, points, perm, vArray, &size, *values);CHKERRQ(ierr);} 5427 if (PetscUnlikely(asize != size)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Section size %D does not match Vec closure size %D", asize, size); 5428 /* Cleanup array */ 5429 ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr); 5430 } 5431 if (csize) *csize = asize; 5432 /* Cleanup points */ 5433 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5434 PetscFunctionReturn(0); 5435 } 5436 5437 PetscErrorCode DMPlexVecGetClosureAtDepth_Internal(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt depth, PetscInt *csize, PetscScalar *values[]) 5438 { 5439 DMLabel depthLabel; 5440 PetscSection clSection; 5441 IS clPoints; 5442 PetscScalar *array; 5443 const PetscScalar *vArray; 5444 PetscInt *points = NULL; 5445 const PetscInt *clp, *perm = NULL; 5446 PetscInt mdepth, numFields, numPoints, Np = 0, p, clsize, size; 5447 PetscErrorCode ierr; 5448 5449 PetscFunctionBeginHot; 5450 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5451 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5452 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5453 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5454 ierr = DMPlexGetDepth(dm, &mdepth);CHKERRQ(ierr); 5455 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 5456 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5457 if (mdepth == 1 && numFields < 2) { 5458 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 5459 PetscFunctionReturn(0); 5460 } 5461 /* Get points */ 5462 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5463 for (clsize=0,p=0; p<Np; p++) { 5464 PetscInt dof; 5465 ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr); 5466 clsize += dof; 5467 } 5468 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &perm);CHKERRQ(ierr); 5469 /* Filter points */ 5470 for (p = 0; p < numPoints*2; p += 2) { 5471 PetscInt dep; 5472 5473 ierr = DMLabelGetValue(depthLabel, points[p], &dep);CHKERRQ(ierr); 5474 if (dep != depth) continue; 5475 points[Np*2+0] = points[p]; 5476 points[Np*2+1] = points[p+1]; 5477 ++Np; 5478 } 5479 /* Get array */ 5480 if (!values || !*values) { 5481 PetscInt asize = 0, dof; 5482 5483 for (p = 0; p < Np*2; p += 2) { 5484 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5485 asize += dof; 5486 } 5487 if (!values) { 5488 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5489 if (csize) *csize = asize; 5490 PetscFunctionReturn(0); 5491 } 5492 ierr = DMGetWorkArray(dm, asize, MPIU_SCALAR, &array);CHKERRQ(ierr); 5493 } else { 5494 array = *values; 5495 } 5496 ierr = VecGetArrayRead(v, &vArray);CHKERRQ(ierr); 5497 /* Get values */ 5498 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(dm, section, Np, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);} 5499 else {ierr = DMPlexVecGetClosure_Static(dm, section, Np, points, perm, vArray, &size, array);CHKERRQ(ierr);} 5500 /* Cleanup points */ 5501 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5502 /* Cleanup array */ 5503 ierr = VecRestoreArrayRead(v, &vArray);CHKERRQ(ierr); 5504 if (!*values) { 5505 if (csize) *csize = size; 5506 *values = array; 5507 } else { 5508 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 5509 *csize = size; 5510 } 5511 PetscFunctionReturn(0); 5512 } 5513 5514 /*@C 5515 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5516 5517 Not collective 5518 5519 Input Parameters: 5520 + dm - The DM 5521 . section - The section describing the layout in v, or NULL to use the default section 5522 . v - The local vector 5523 . point - The point in the DM 5524 . csize - The number of values in the closure, or NULL 5525 - values - The array of values, which is a borrowed array and should not be freed 5526 5527 Note that the array values are discarded and not copied back into v. In order to copy values back to v, use DMPlexVecSetClosure() 5528 5529 Fortran Notes: 5530 Since it returns an array, this routine is only available in Fortran 90, and you must 5531 include petsc.h90 in your code. 5532 5533 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5534 5535 Level: intermediate 5536 5537 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5538 @*/ 5539 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5540 { 5541 PetscInt size = 0; 5542 PetscErrorCode ierr; 5543 5544 PetscFunctionBegin; 5545 /* Should work without recalculating size */ 5546 ierr = DMRestoreWorkArray(dm, size, MPIU_SCALAR, (void*) values);CHKERRQ(ierr); 5547 *values = NULL; 5548 PetscFunctionReturn(0); 5549 } 5550 5551 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 5552 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5553 5554 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[]) 5555 { 5556 PetscInt cdof; /* The number of constraints on this point */ 5557 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5558 PetscScalar *a; 5559 PetscInt off, cind = 0, k; 5560 PetscErrorCode ierr; 5561 5562 PetscFunctionBegin; 5563 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5564 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5565 a = &array[off]; 5566 if (!cdof || setBC) { 5567 if (clperm) { 5568 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.));}} 5569 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.));}} 5570 } else { 5571 if (perm) {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.));}} 5572 else {for (k = 0; k < dof; ++k) {fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.));}} 5573 } 5574 } else { 5575 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5576 if (clperm) { 5577 if (perm) {for (k = 0; k < dof; ++k) { 5578 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5579 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5580 } 5581 } else { 5582 for (k = 0; k < dof; ++k) { 5583 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5584 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5585 } 5586 } 5587 } else { 5588 if (perm) { 5589 for (k = 0; k < dof; ++k) { 5590 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5591 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5592 } 5593 } else { 5594 for (k = 0; k < dof; ++k) { 5595 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5596 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5597 } 5598 } 5599 } 5600 } 5601 PetscFunctionReturn(0); 5602 } 5603 5604 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[]) 5605 { 5606 PetscInt cdof; /* The number of constraints on this point */ 5607 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5608 PetscScalar *a; 5609 PetscInt off, cind = 0, k; 5610 PetscErrorCode ierr; 5611 5612 PetscFunctionBegin; 5613 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5614 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5615 a = &array[off]; 5616 if (cdof) { 5617 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5618 if (clperm) { 5619 if (perm) { 5620 for (k = 0; k < dof; ++k) { 5621 if ((cind < cdof) && (k == cdofs[cind])) { 5622 fuse(&a[k], values[clperm[offset+perm[k]]] * (flip ? flip[perm[k]] : 1.)); 5623 cind++; 5624 } 5625 } 5626 } else { 5627 for (k = 0; k < dof; ++k) { 5628 if ((cind < cdof) && (k == cdofs[cind])) { 5629 fuse(&a[k], values[clperm[offset+ k ]] * (flip ? flip[ k ] : 1.)); 5630 cind++; 5631 } 5632 } 5633 } 5634 } else { 5635 if (perm) { 5636 for (k = 0; k < dof; ++k) { 5637 if ((cind < cdof) && (k == cdofs[cind])) { 5638 fuse(&a[k], values[offset+perm[k]] * (flip ? flip[perm[k]] : 1.)); 5639 cind++; 5640 } 5641 } 5642 } else { 5643 for (k = 0; k < dof; ++k) { 5644 if ((cind < cdof) && (k == cdofs[cind])) { 5645 fuse(&a[k], values[offset+ k ] * (flip ? flip[ k ] : 1.)); 5646 cind++; 5647 } 5648 } 5649 } 5650 } 5651 } 5652 PetscFunctionReturn(0); 5653 } 5654 5655 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[]) 5656 { 5657 PetscScalar *a; 5658 PetscInt fdof, foff, fcdof, foffset = *offset; 5659 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5660 PetscInt cind = 0, b; 5661 PetscErrorCode ierr; 5662 5663 PetscFunctionBegin; 5664 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5665 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 5666 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 5667 a = &array[foff]; 5668 if (!fcdof || setBC) { 5669 if (clperm) { 5670 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));}} 5671 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));}} 5672 } else { 5673 if (perm) {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));}} 5674 else {for (b = 0; b < fdof; b++) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));}} 5675 } 5676 } else { 5677 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5678 if (clperm) { 5679 if (perm) { 5680 for (b = 0; b < fdof; b++) { 5681 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 5682 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 5683 } 5684 } else { 5685 for (b = 0; b < fdof; b++) { 5686 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 5687 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 5688 } 5689 } 5690 } else { 5691 if (perm) { 5692 for (b = 0; b < fdof; b++) { 5693 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 5694 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 5695 } 5696 } else { 5697 for (b = 0; b < fdof; b++) { 5698 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; continue;} 5699 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 5700 } 5701 } 5702 } 5703 } 5704 *offset += fdof; 5705 PetscFunctionReturn(0); 5706 } 5707 5708 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[]) 5709 { 5710 PetscScalar *a; 5711 PetscInt fdof, foff, fcdof, foffset = *offset; 5712 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5713 PetscInt Nc, cind = 0, ncind = 0, b; 5714 PetscBool ncSet, fcSet; 5715 PetscErrorCode ierr; 5716 5717 PetscFunctionBegin; 5718 ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr); 5719 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5720 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 5721 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 5722 a = &array[foff]; 5723 if (fcdof) { 5724 /* We just override fcdof and fcdofs with Ncc and comps */ 5725 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5726 if (clperm) { 5727 if (perm) { 5728 if (comps) { 5729 for (b = 0; b < fdof; b++) { 5730 ncSet = fcSet = PETSC_FALSE; 5731 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 5732 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 5733 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.));} 5734 } 5735 } else { 5736 for (b = 0; b < fdof; b++) { 5737 if ((cind < fcdof) && (b == fcdofs[cind])) { 5738 fuse(&a[b], values[clperm[foffset+perm[b]]] * (flip ? flip[perm[b]] : 1.)); 5739 ++cind; 5740 } 5741 } 5742 } 5743 } else { 5744 if (comps) { 5745 for (b = 0; b < fdof; b++) { 5746 ncSet = fcSet = PETSC_FALSE; 5747 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 5748 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 5749 if (ncSet && fcSet) {fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.));} 5750 } 5751 } else { 5752 for (b = 0; b < fdof; b++) { 5753 if ((cind < fcdof) && (b == fcdofs[cind])) { 5754 fuse(&a[b], values[clperm[foffset+ b ]] * (flip ? flip[ b ] : 1.)); 5755 ++cind; 5756 } 5757 } 5758 } 5759 } 5760 } else { 5761 if (perm) { 5762 if (comps) { 5763 for (b = 0; b < fdof; b++) { 5764 ncSet = fcSet = PETSC_FALSE; 5765 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 5766 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 5767 if (ncSet && fcSet) {fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.));} 5768 } 5769 } else { 5770 for (b = 0; b < fdof; b++) { 5771 if ((cind < fcdof) && (b == fcdofs[cind])) { 5772 fuse(&a[b], values[foffset+perm[b]] * (flip ? flip[perm[b]] : 1.)); 5773 ++cind; 5774 } 5775 } 5776 } 5777 } else { 5778 if (comps) { 5779 for (b = 0; b < fdof; b++) { 5780 ncSet = fcSet = PETSC_FALSE; 5781 if (b%Nc == comps[ncind]) {ncind = (ncind+1)%Ncc; ncSet = PETSC_TRUE;} 5782 if ((cind < fcdof) && (b == fcdofs[cind])) {++cind; fcSet = PETSC_TRUE;} 5783 if (ncSet && fcSet) {fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.));} 5784 } 5785 } else { 5786 for (b = 0; b < fdof; b++) { 5787 if ((cind < fcdof) && (b == fcdofs[cind])) { 5788 fuse(&a[b], values[foffset+ b ] * (flip ? flip[ b ] : 1.)); 5789 ++cind; 5790 } 5791 } 5792 } 5793 } 5794 } 5795 } 5796 *offset += fdof; 5797 PetscFunctionReturn(0); 5798 } 5799 5800 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5801 { 5802 PetscScalar *array; 5803 const PetscInt *cone, *coneO; 5804 PetscInt pStart, pEnd, p, numPoints, off, dof; 5805 PetscErrorCode ierr; 5806 5807 PetscFunctionBeginHot; 5808 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5809 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 5810 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5811 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 5812 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5813 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 5814 const PetscInt cp = !p ? point : cone[p-1]; 5815 const PetscInt o = !p ? 0 : coneO[p-1]; 5816 5817 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 5818 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5819 /* ADD_VALUES */ 5820 { 5821 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5822 PetscScalar *a; 5823 PetscInt cdof, coff, cind = 0, k; 5824 5825 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 5826 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 5827 a = &array[coff]; 5828 if (!cdof) { 5829 if (o >= 0) { 5830 for (k = 0; k < dof; ++k) { 5831 a[k] += values[off+k]; 5832 } 5833 } else { 5834 for (k = 0; k < dof; ++k) { 5835 a[k] += values[off+dof-k-1]; 5836 } 5837 } 5838 } else { 5839 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 5840 if (o >= 0) { 5841 for (k = 0; k < dof; ++k) { 5842 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5843 a[k] += values[off+k]; 5844 } 5845 } else { 5846 for (k = 0; k < dof; ++k) { 5847 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5848 a[k] += values[off+dof-k-1]; 5849 } 5850 } 5851 } 5852 } 5853 } 5854 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5855 PetscFunctionReturn(0); 5856 } 5857 5858 /*@C 5859 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 5860 5861 Not collective 5862 5863 Input Parameters: 5864 + dm - The DM 5865 . section - The section describing the layout in v, or NULL to use the default section 5866 . v - The local vector 5867 . point - The point in the DM 5868 . values - The array of values 5869 - mode - The insert mode. One of INSERT_ALL_VALUES, ADD_ALL_VALUES, INSERT_VALUES, ADD_VALUES, INSERT_BC_VALUES, and ADD_BC_VALUES, 5870 where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions. 5871 5872 Fortran Notes: 5873 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5874 5875 Level: intermediate 5876 5877 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 5878 @*/ 5879 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5880 { 5881 PetscSection clSection; 5882 IS clPoints; 5883 PetscScalar *array; 5884 PetscInt *points = NULL; 5885 const PetscInt *clp, *clperm = NULL; 5886 PetscInt depth, numFields, numPoints, p, clsize; 5887 PetscErrorCode ierr; 5888 5889 PetscFunctionBeginHot; 5890 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5891 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 5892 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5893 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5894 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5895 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5896 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 5897 ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr); 5898 PetscFunctionReturn(0); 5899 } 5900 /* Get points */ 5901 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5902 for (clsize=0,p=0; p<numPoints; p++) { 5903 PetscInt dof; 5904 ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr); 5905 clsize += dof; 5906 } 5907 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr); 5908 /* Get array */ 5909 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5910 /* Get values */ 5911 if (numFields > 0) { 5912 PetscInt offset = 0, f; 5913 for (f = 0; f < numFields; ++f) { 5914 const PetscInt **perms = NULL; 5915 const PetscScalar **flips = NULL; 5916 5917 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5918 switch (mode) { 5919 case INSERT_VALUES: 5920 for (p = 0; p < numPoints; p++) { 5921 const PetscInt point = points[2*p]; 5922 const PetscInt *perm = perms ? perms[p] : NULL; 5923 const PetscScalar *flip = flips ? flips[p] : NULL; 5924 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, clperm, values, &offset, array); 5925 } break; 5926 case INSERT_ALL_VALUES: 5927 for (p = 0; p < numPoints; p++) { 5928 const PetscInt point = points[2*p]; 5929 const PetscInt *perm = perms ? perms[p] : NULL; 5930 const PetscScalar *flip = flips ? flips[p] : NULL; 5931 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, clperm, values, &offset, array); 5932 } break; 5933 case INSERT_BC_VALUES: 5934 for (p = 0; p < numPoints; p++) { 5935 const PetscInt point = points[2*p]; 5936 const PetscInt *perm = perms ? perms[p] : NULL; 5937 const PetscScalar *flip = flips ? flips[p] : NULL; 5938 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, insert, clperm, values, &offset, array); 5939 } break; 5940 case ADD_VALUES: 5941 for (p = 0; p < numPoints; p++) { 5942 const PetscInt point = points[2*p]; 5943 const PetscInt *perm = perms ? perms[p] : NULL; 5944 const PetscScalar *flip = flips ? flips[p] : NULL; 5945 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, clperm, values, &offset, array); 5946 } break; 5947 case ADD_ALL_VALUES: 5948 for (p = 0; p < numPoints; p++) { 5949 const PetscInt point = points[2*p]; 5950 const PetscInt *perm = perms ? perms[p] : NULL; 5951 const PetscScalar *flip = flips ? flips[p] : NULL; 5952 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, clperm, values, &offset, array); 5953 } break; 5954 case ADD_BC_VALUES: 5955 for (p = 0; p < numPoints; p++) { 5956 const PetscInt point = points[2*p]; 5957 const PetscInt *perm = perms ? perms[p] : NULL; 5958 const PetscScalar *flip = flips ? flips[p] : NULL; 5959 updatePointFieldsBC_private(section, point, perm, flip, f, -1, NULL, add, clperm, values, &offset, array); 5960 } break; 5961 default: 5962 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 5963 } 5964 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5965 } 5966 } else { 5967 PetscInt dof, off; 5968 const PetscInt **perms = NULL; 5969 const PetscScalar **flips = NULL; 5970 5971 ierr = PetscSectionGetPointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 5972 switch (mode) { 5973 case INSERT_VALUES: 5974 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5975 const PetscInt point = points[2*p]; 5976 const PetscInt *perm = perms ? perms[p] : NULL; 5977 const PetscScalar *flip = flips ? flips[p] : NULL; 5978 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5979 updatePoint_private(section, point, dof, insert, PETSC_FALSE, perm, flip, clperm, values, off, array); 5980 } break; 5981 case INSERT_ALL_VALUES: 5982 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5983 const PetscInt point = points[2*p]; 5984 const PetscInt *perm = perms ? perms[p] : NULL; 5985 const PetscScalar *flip = flips ? flips[p] : NULL; 5986 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5987 updatePoint_private(section, point, dof, insert, PETSC_TRUE, perm, flip, clperm, values, off, array); 5988 } break; 5989 case INSERT_BC_VALUES: 5990 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5991 const PetscInt point = points[2*p]; 5992 const PetscInt *perm = perms ? perms[p] : NULL; 5993 const PetscScalar *flip = flips ? flips[p] : NULL; 5994 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5995 updatePointBC_private(section, point, dof, insert, perm, flip, clperm, values, off, array); 5996 } break; 5997 case ADD_VALUES: 5998 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 5999 const PetscInt point = points[2*p]; 6000 const PetscInt *perm = perms ? perms[p] : NULL; 6001 const PetscScalar *flip = flips ? flips[p] : NULL; 6002 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 6003 updatePoint_private(section, point, dof, add, PETSC_FALSE, perm, flip, clperm, values, off, array); 6004 } break; 6005 case ADD_ALL_VALUES: 6006 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6007 const PetscInt point = points[2*p]; 6008 const PetscInt *perm = perms ? perms[p] : NULL; 6009 const PetscScalar *flip = flips ? flips[p] : NULL; 6010 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 6011 updatePoint_private(section, point, dof, add, PETSC_TRUE, perm, flip, clperm, values, off, array); 6012 } break; 6013 case ADD_BC_VALUES: 6014 for (p = 0, off = 0; p < numPoints; p++, off += dof) { 6015 const PetscInt point = points[2*p]; 6016 const PetscInt *perm = perms ? perms[p] : NULL; 6017 const PetscScalar *flip = flips ? flips[p] : NULL; 6018 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 6019 updatePointBC_private(section, point, dof, add, perm, flip, clperm, values, off, array); 6020 } break; 6021 default: 6022 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6023 } 6024 ierr = PetscSectionRestorePointSyms(section,numPoints,points,&perms,&flips);CHKERRQ(ierr); 6025 } 6026 /* Cleanup points */ 6027 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6028 /* Cleanup array */ 6029 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 6030 PetscFunctionReturn(0); 6031 } 6032 6033 /* Check whether the given point is in the label. If not, update the offset to skip this point */ 6034 PETSC_STATIC_INLINE PetscErrorCode CheckPoint_Private(DMLabel label, PetscInt labelId, PetscSection section, PetscInt point, PetscInt f, PetscInt *offset) 6035 { 6036 PetscFunctionBegin; 6037 if (label) { 6038 PetscInt val, fdof; 6039 PetscErrorCode ierr; 6040 6041 /* There is a problem with this: 6042 Suppose we have two label values, defining surfaces, interecting along a line in 3D. When we add cells to the label, the cells that 6043 touch both surfaces must pick a label value. Thus we miss setting values for the surface with that other value intersecting that cell. 6044 Thus I am only going to check val != -1, not val != labelId 6045 */ 6046 ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr); 6047 if (val < 0) { 6048 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 6049 *offset += fdof; 6050 PetscFunctionReturn(1); 6051 } 6052 } 6053 PetscFunctionReturn(0); 6054 } 6055 6056 /* Unlike DMPlexVecSetClosure(), this uses plex-native closure permutation, not a user-specified permutation such as DMPlexSetClosurePermutationTensor(). */ 6057 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) 6058 { 6059 PetscSection clSection; 6060 IS clPoints; 6061 PetscScalar *array; 6062 PetscInt *points = NULL; 6063 const PetscInt *clp; 6064 PetscInt numFields, numPoints, p; 6065 PetscInt offset = 0, f; 6066 PetscErrorCode ierr; 6067 6068 PetscFunctionBeginHot; 6069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6070 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 6071 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6072 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 6073 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6074 /* Get points */ 6075 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6076 /* Get array */ 6077 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 6078 /* Get values */ 6079 for (f = 0; f < numFields; ++f) { 6080 const PetscInt **perms = NULL; 6081 const PetscScalar **flips = NULL; 6082 6083 if (!fieldActive[f]) { 6084 for (p = 0; p < numPoints*2; p += 2) { 6085 PetscInt fdof; 6086 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6087 offset += fdof; 6088 } 6089 continue; 6090 } 6091 ierr = PetscSectionGetFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 6092 switch (mode) { 6093 case INSERT_VALUES: 6094 for (p = 0; p < numPoints; p++) { 6095 const PetscInt point = points[2*p]; 6096 const PetscInt *perm = perms ? perms[p] : NULL; 6097 const PetscScalar *flip = flips ? flips[p] : NULL; 6098 ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue; 6099 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_FALSE, NULL, values, &offset, array); 6100 } break; 6101 case INSERT_ALL_VALUES: 6102 for (p = 0; p < numPoints; p++) { 6103 const PetscInt point = points[2*p]; 6104 const PetscInt *perm = perms ? perms[p] : NULL; 6105 const PetscScalar *flip = flips ? flips[p] : NULL; 6106 ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue; 6107 updatePointFields_private(section, point, perm, flip, f, insert, PETSC_TRUE, NULL, values, &offset, array); 6108 } break; 6109 case INSERT_BC_VALUES: 6110 for (p = 0; p < numPoints; p++) { 6111 const PetscInt point = points[2*p]; 6112 const PetscInt *perm = perms ? perms[p] : NULL; 6113 const PetscScalar *flip = flips ? flips[p] : NULL; 6114 ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue; 6115 updatePointFieldsBC_private(section, point, perm, flip, f, Ncc, comps, insert, NULL, values, &offset, array); 6116 } break; 6117 case ADD_VALUES: 6118 for (p = 0; p < numPoints; p++) { 6119 const PetscInt point = points[2*p]; 6120 const PetscInt *perm = perms ? perms[p] : NULL; 6121 const PetscScalar *flip = flips ? flips[p] : NULL; 6122 ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue; 6123 updatePointFields_private(section, point, perm, flip, f, add, PETSC_FALSE, NULL, values, &offset, array); 6124 } break; 6125 case ADD_ALL_VALUES: 6126 for (p = 0; p < numPoints; p++) { 6127 const PetscInt point = points[2*p]; 6128 const PetscInt *perm = perms ? perms[p] : NULL; 6129 const PetscScalar *flip = flips ? flips[p] : NULL; 6130 ierr = CheckPoint_Private(label, labelId, section, point, f, &offset); if (ierr) continue; 6131 updatePointFields_private(section, point, perm, flip, f, add, PETSC_TRUE, NULL, values, &offset, array); 6132 } break; 6133 default: 6134 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 6135 } 6136 ierr = PetscSectionRestoreFieldPointSyms(section,f,numPoints,points,&perms,&flips);CHKERRQ(ierr); 6137 } 6138 /* Cleanup points */ 6139 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 6140 /* Cleanup array */ 6141 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 6142 PetscFunctionReturn(0); 6143 } 6144 6145 static PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 6146 { 6147 PetscMPIInt rank; 6148 PetscInt i, j; 6149 PetscErrorCode ierr; 6150 6151 PetscFunctionBegin; 6152 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr); 6153 ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for point %D\n", rank, point);CHKERRQ(ierr); 6154 for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);} 6155 for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);} 6156 numCIndices = numCIndices ? numCIndices : numRIndices; 6157 if (!values) PetscFunctionReturn(0); 6158 for (i = 0; i < numRIndices; i++) { 6159 ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr); 6160 for (j = 0; j < numCIndices; j++) { 6161 #if defined(PETSC_USE_COMPLEX) 6162 ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr); 6163 #else 6164 ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr); 6165 #endif 6166 } 6167 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 6168 } 6169 PetscFunctionReturn(0); 6170 } 6171 6172 /* 6173 DMPlexGetIndicesPoint_Internal - Add the indices for dofs on a point to an index array 6174 6175 Input Parameters: 6176 + section - The section for this data layout 6177 . islocal - Is the section (and thus indices being requested) local or global? 6178 . point - The point contributing dofs with these indices 6179 . off - The global offset of this point 6180 . loff - The local offset of each field 6181 . setBC - The flag determining whether to include indices of bounsary values 6182 . perm - A permutation of the dofs on this point, or NULL 6183 - indperm - A permutation of the entire indices array, or NULL 6184 6185 Output Parameter: 6186 . indices - Indices for dofs on this point 6187 6188 Level: developer 6189 6190 Note: The indices could be local or global, depending on the value of 'off'. 6191 */ 6192 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscBool islocal,PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, const PetscInt perm[], const PetscInt indperm[], PetscInt indices[]) 6193 { 6194 PetscInt dof; /* The number of unknowns on this point */ 6195 PetscInt cdof; /* The number of constraints on this point */ 6196 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 6197 PetscInt cind = 0, k; 6198 PetscErrorCode ierr; 6199 6200 PetscFunctionBegin; 6201 if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6202 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 6203 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 6204 if (!cdof || setBC) { 6205 for (k = 0; k < dof; ++k) { 6206 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6207 const PetscInt ind = indperm ? indperm[preind] : preind; 6208 6209 indices[ind] = off + k; 6210 } 6211 } else { 6212 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 6213 for (k = 0; k < dof; ++k) { 6214 const PetscInt preind = perm ? *loff+perm[k] : *loff+k; 6215 const PetscInt ind = indperm ? indperm[preind] : preind; 6216 6217 if ((cind < cdof) && (k == cdofs[cind])) { 6218 /* Insert check for returning constrained indices */ 6219 indices[ind] = -(off+k+1); 6220 ++cind; 6221 } else { 6222 indices[ind] = off + k - (islocal ? 0 : cind); 6223 } 6224 } 6225 } 6226 *loff += dof; 6227 PetscFunctionReturn(0); 6228 } 6229 6230 /* 6231 DMPlexGetIndicesPointFields_Internal - gets section indices for a point in its canonical ordering. 6232 6233 Input Parameters: 6234 + section - a section (global or local) 6235 - islocal - PETSC_TRUE if requesting local indices (i.e., section is local); PETSC_FALSE for global 6236 . point - point within section 6237 . off - The offset of this point in the (local or global) indexed space - should match islocal and (usually) the section 6238 . foffs - array of length numFields containing the offset in canonical point ordering (the location in indices) of each field 6239 . setBC - identify constrained (boundary condition) points via involution. 6240 . perms - perms[f][permsoff][:] is a permutation of dofs within each field 6241 . permsoff - offset 6242 - indperm - index permutation 6243 6244 Output Parameter: 6245 . foffs - each entry is incremented by the number of (unconstrained if setBC=FALSE) dofs in that field 6246 . indices - array to hold indices (as defined by section) of each dof associated with point 6247 6248 Notes: 6249 If section is local and setBC=true, there is no distinction between constrained and unconstrained dofs. 6250 If section is local and setBC=false, the indices for constrained points are the involution -(i+1) of their position 6251 in the local vector. 6252 6253 If section is global and setBC=false, the indices for constrained points are negative (and their value is not 6254 significant). It is invalid to call with a global section and setBC=true. 6255 6256 Developer Note: 6257 The section is only used for field layout, so islocal is technically a statement about the offset (off). At some point 6258 in the future, global sections may have fields set, in which case we could pass the global section and obtain the 6259 offset could be obtained from the section instead of passing it explicitly as we do now. 6260 6261 Example: 6262 Suppose a point contains one field with three components, and for which the unconstrained indices are {10, 11, 12}. 6263 When the middle component is constrained, we get the array {10, -12, 12} for (islocal=TRUE, setBC=FALSE). 6264 Note that -12 is the involution of 11, so the user can involute negative indices to recover local indices. 6265 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. 6266 6267 Level: developer 6268 */ 6269 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[]) 6270 { 6271 PetscInt numFields, foff, f; 6272 PetscErrorCode ierr; 6273 6274 PetscFunctionBegin; 6275 if (!islocal && setBC) SETERRQ(PetscObjectComm((PetscObject)section),PETSC_ERR_ARG_INCOMP,"setBC incompatible with global indices; use a local section or disable setBC"); 6276 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6277 for (f = 0, foff = 0; f < numFields; ++f) { 6278 PetscInt fdof, cfdof; 6279 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6280 PetscInt cind = 0, b; 6281 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6282 6283 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 6284 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 6285 if (!cfdof || setBC) { 6286 for (b = 0; b < fdof; ++b) { 6287 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6288 const PetscInt ind = indperm ? indperm[preind] : preind; 6289 6290 indices[ind] = off+foff+b; 6291 } 6292 } else { 6293 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 6294 for (b = 0; b < fdof; ++b) { 6295 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6296 const PetscInt ind = indperm ? indperm[preind] : preind; 6297 6298 if ((cind < cfdof) && (b == fcdofs[cind])) { 6299 indices[ind] = -(off+foff+b+1); 6300 ++cind; 6301 } else { 6302 indices[ind] = off + foff + b - (islocal ? 0 : cind); 6303 } 6304 } 6305 } 6306 foff += (setBC || islocal ? fdof : (fdof - cfdof)); 6307 foffs[f] += fdof; 6308 } 6309 PetscFunctionReturn(0); 6310 } 6311 6312 /* 6313 This version believes the globalSection offsets for each field, rather than just the point offset 6314 6315 . foffs - The offset into 'indices' for each field, since it is segregated by field 6316 6317 Notes: 6318 The semantics of this function relate to that of setBC=FALSE in DMPlexGetIndicesPointFields_Internal. 6319 Since this function uses global indices, setBC=TRUE would be invalid, so no such argument exists. 6320 */ 6321 static PetscErrorCode DMPlexGetIndicesPointFieldsSplit_Internal(PetscSection section, PetscSection globalSection, PetscInt point, PetscInt foffs[], const PetscInt ***perms, PetscInt permsoff, const PetscInt indperm[], PetscInt indices[]) 6322 { 6323 PetscInt numFields, foff, f; 6324 PetscErrorCode ierr; 6325 6326 PetscFunctionBegin; 6327 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6328 for (f = 0; f < numFields; ++f) { 6329 PetscInt fdof, cfdof; 6330 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 6331 PetscInt cind = 0, b; 6332 const PetscInt *perm = (perms && perms[f]) ? perms[f][permsoff] : NULL; 6333 6334 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 6335 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 6336 ierr = PetscSectionGetFieldOffset(globalSection, point, f, &foff);CHKERRQ(ierr); 6337 if (!cfdof) { 6338 for (b = 0; b < fdof; ++b) { 6339 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6340 const PetscInt ind = indperm ? indperm[preind] : preind; 6341 6342 indices[ind] = foff+b; 6343 } 6344 } else { 6345 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 6346 for (b = 0; b < fdof; ++b) { 6347 const PetscInt preind = perm ? foffs[f]+perm[b] : foffs[f]+b; 6348 const PetscInt ind = indperm ? indperm[preind] : preind; 6349 6350 if ((cind < cfdof) && (b == fcdofs[cind])) { 6351 indices[ind] = -(foff+b+1); 6352 ++cind; 6353 } else { 6354 indices[ind] = foff+b-cind; 6355 } 6356 } 6357 } 6358 foffs[f] += fdof; 6359 } 6360 PetscFunctionReturn(0); 6361 } 6362 6363 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) 6364 { 6365 Mat cMat; 6366 PetscSection aSec, cSec; 6367 IS aIS; 6368 PetscInt aStart = -1, aEnd = -1; 6369 const PetscInt *anchors; 6370 PetscInt numFields, f, p, q, newP = 0; 6371 PetscInt newNumPoints = 0, newNumIndices = 0; 6372 PetscInt *newPoints, *indices, *newIndices; 6373 PetscInt maxAnchor, maxDof; 6374 PetscInt newOffsets[32]; 6375 PetscInt *pointMatOffsets[32]; 6376 PetscInt *newPointOffsets[32]; 6377 PetscScalar *pointMat[32]; 6378 PetscScalar *newValues=NULL,*tmpValues; 6379 PetscBool anyConstrained = PETSC_FALSE; 6380 PetscErrorCode ierr; 6381 6382 PetscFunctionBegin; 6383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6384 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6385 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 6386 6387 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 6388 /* if there are point-to-point constraints */ 6389 if (aSec) { 6390 ierr = PetscArrayzero(newOffsets, 32);CHKERRQ(ierr); 6391 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 6392 ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); 6393 /* figure out how many points are going to be in the new element matrix 6394 * (we allow double counting, because it's all just going to be summed 6395 * into the global matrix anyway) */ 6396 for (p = 0; p < 2*numPoints; p+=2) { 6397 PetscInt b = points[p]; 6398 PetscInt bDof = 0, bSecDof; 6399 6400 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 6401 if (!bSecDof) { 6402 continue; 6403 } 6404 if (b >= aStart && b < aEnd) { 6405 ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr); 6406 } 6407 if (bDof) { 6408 /* this point is constrained */ 6409 /* it is going to be replaced by its anchors */ 6410 PetscInt bOff, q; 6411 6412 anyConstrained = PETSC_TRUE; 6413 newNumPoints += bDof; 6414 ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr); 6415 for (q = 0; q < bDof; q++) { 6416 PetscInt a = anchors[bOff + q]; 6417 PetscInt aDof; 6418 6419 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 6420 newNumIndices += aDof; 6421 for (f = 0; f < numFields; ++f) { 6422 PetscInt fDof; 6423 6424 ierr = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr); 6425 newOffsets[f+1] += fDof; 6426 } 6427 } 6428 } 6429 else { 6430 /* this point is not constrained */ 6431 newNumPoints++; 6432 newNumIndices += bSecDof; 6433 for (f = 0; f < numFields; ++f) { 6434 PetscInt fDof; 6435 6436 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 6437 newOffsets[f+1] += fDof; 6438 } 6439 } 6440 } 6441 } 6442 if (!anyConstrained) { 6443 if (outNumPoints) *outNumPoints = 0; 6444 if (outNumIndices) *outNumIndices = 0; 6445 if (outPoints) *outPoints = NULL; 6446 if (outValues) *outValues = NULL; 6447 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 6448 PetscFunctionReturn(0); 6449 } 6450 6451 if (outNumPoints) *outNumPoints = newNumPoints; 6452 if (outNumIndices) *outNumIndices = newNumIndices; 6453 6454 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 6455 6456 if (!outPoints && !outValues) { 6457 if (offsets) { 6458 for (f = 0; f <= numFields; f++) { 6459 offsets[f] = newOffsets[f]; 6460 } 6461 } 6462 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 6463 PetscFunctionReturn(0); 6464 } 6465 6466 if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices); 6467 6468 ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr); 6469 6470 /* workspaces */ 6471 if (numFields) { 6472 for (f = 0; f < numFields; f++) { 6473 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 6474 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 6475 } 6476 } 6477 else { 6478 ierr = DMGetWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 6479 ierr = DMGetWorkArray(dm,numPoints,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 6480 } 6481 6482 /* get workspaces for the point-to-point matrices */ 6483 if (numFields) { 6484 PetscInt totalOffset, totalMatOffset; 6485 6486 for (p = 0; p < numPoints; p++) { 6487 PetscInt b = points[2*p]; 6488 PetscInt bDof = 0, bSecDof; 6489 6490 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 6491 if (!bSecDof) { 6492 for (f = 0; f < numFields; f++) { 6493 newPointOffsets[f][p + 1] = 0; 6494 pointMatOffsets[f][p + 1] = 0; 6495 } 6496 continue; 6497 } 6498 if (b >= aStart && b < aEnd) { 6499 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 6500 } 6501 if (bDof) { 6502 for (f = 0; f < numFields; f++) { 6503 PetscInt fDof, q, bOff, allFDof = 0; 6504 6505 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 6506 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 6507 for (q = 0; q < bDof; q++) { 6508 PetscInt a = anchors[bOff + q]; 6509 PetscInt aFDof; 6510 6511 ierr = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr); 6512 allFDof += aFDof; 6513 } 6514 newPointOffsets[f][p+1] = allFDof; 6515 pointMatOffsets[f][p+1] = fDof * allFDof; 6516 } 6517 } 6518 else { 6519 for (f = 0; f < numFields; f++) { 6520 PetscInt fDof; 6521 6522 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 6523 newPointOffsets[f][p+1] = fDof; 6524 pointMatOffsets[f][p+1] = 0; 6525 } 6526 } 6527 } 6528 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 6529 newPointOffsets[f][0] = totalOffset; 6530 pointMatOffsets[f][0] = totalMatOffset; 6531 for (p = 0; p < numPoints; p++) { 6532 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 6533 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 6534 } 6535 totalOffset = newPointOffsets[f][numPoints]; 6536 totalMatOffset = pointMatOffsets[f][numPoints]; 6537 ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 6538 } 6539 } 6540 else { 6541 for (p = 0; p < numPoints; p++) { 6542 PetscInt b = points[2*p]; 6543 PetscInt bDof = 0, bSecDof; 6544 6545 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 6546 if (!bSecDof) { 6547 newPointOffsets[0][p + 1] = 0; 6548 pointMatOffsets[0][p + 1] = 0; 6549 continue; 6550 } 6551 if (b >= aStart && b < aEnd) { 6552 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 6553 } 6554 if (bDof) { 6555 PetscInt bOff, q, allDof = 0; 6556 6557 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 6558 for (q = 0; q < bDof; q++) { 6559 PetscInt a = anchors[bOff + q], aDof; 6560 6561 ierr = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr); 6562 allDof += aDof; 6563 } 6564 newPointOffsets[0][p+1] = allDof; 6565 pointMatOffsets[0][p+1] = bSecDof * allDof; 6566 } 6567 else { 6568 newPointOffsets[0][p+1] = bSecDof; 6569 pointMatOffsets[0][p+1] = 0; 6570 } 6571 } 6572 newPointOffsets[0][0] = 0; 6573 pointMatOffsets[0][0] = 0; 6574 for (p = 0; p < numPoints; p++) { 6575 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 6576 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 6577 } 6578 ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 6579 } 6580 6581 /* output arrays */ 6582 ierr = DMGetWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 6583 6584 /* get the point-to-point matrices; construct newPoints */ 6585 ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr); 6586 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 6587 ierr = DMGetWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 6588 ierr = DMGetWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 6589 if (numFields) { 6590 for (p = 0, newP = 0; p < numPoints; p++) { 6591 PetscInt b = points[2*p]; 6592 PetscInt o = points[2*p+1]; 6593 PetscInt bDof = 0, bSecDof; 6594 6595 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 6596 if (!bSecDof) { 6597 continue; 6598 } 6599 if (b >= aStart && b < aEnd) { 6600 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 6601 } 6602 if (bDof) { 6603 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 6604 6605 fStart[0] = 0; 6606 fEnd[0] = 0; 6607 for (f = 0; f < numFields; f++) { 6608 PetscInt fDof; 6609 6610 ierr = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr); 6611 fStart[f+1] = fStart[f] + fDof; 6612 fEnd[f+1] = fStart[f+1]; 6613 } 6614 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 6615 ierr = DMPlexGetIndicesPointFields_Internal(cSec, PETSC_TRUE, b, bOff, fEnd, PETSC_TRUE, perms, p, NULL, indices);CHKERRQ(ierr); 6616 6617 fAnchorStart[0] = 0; 6618 fAnchorEnd[0] = 0; 6619 for (f = 0; f < numFields; f++) { 6620 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 6621 6622 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 6623 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 6624 } 6625 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 6626 for (q = 0; q < bDof; q++) { 6627 PetscInt a = anchors[bOff + q], aOff; 6628 6629 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6630 newPoints[2*(newP + q)] = a; 6631 newPoints[2*(newP + q) + 1] = 0; 6632 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 6633 ierr = DMPlexGetIndicesPointFields_Internal(section, PETSC_TRUE, a, aOff, fAnchorEnd, PETSC_TRUE, NULL, -1, NULL, newIndices);CHKERRQ(ierr); 6634 } 6635 newP += bDof; 6636 6637 if (outValues) { 6638 /* get the point-to-point submatrix */ 6639 for (f = 0; f < numFields; f++) { 6640 ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr); 6641 } 6642 } 6643 } 6644 else { 6645 newPoints[2 * newP] = b; 6646 newPoints[2 * newP + 1] = o; 6647 newP++; 6648 } 6649 } 6650 } else { 6651 for (p = 0; p < numPoints; p++) { 6652 PetscInt b = points[2*p]; 6653 PetscInt o = points[2*p+1]; 6654 PetscInt bDof = 0, bSecDof; 6655 6656 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 6657 if (!bSecDof) { 6658 continue; 6659 } 6660 if (b >= aStart && b < aEnd) { 6661 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 6662 } 6663 if (bDof) { 6664 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 6665 6666 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 6667 ierr = DMPlexGetIndicesPoint_Internal(cSec, PETSC_TRUE, b, bOff, &bEnd, PETSC_TRUE, (perms && perms[0]) ? perms[0][p] : NULL, NULL, indices);CHKERRQ(ierr); 6668 6669 ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr); 6670 for (q = 0; q < bDof; q++) { 6671 PetscInt a = anchors[bOff + q], aOff; 6672 6673 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 6674 6675 newPoints[2*(newP + q)] = a; 6676 newPoints[2*(newP + q) + 1] = 0; 6677 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 6678 ierr = DMPlexGetIndicesPoint_Internal(section, PETSC_TRUE, a, aOff, &bAnchorEnd, PETSC_TRUE, NULL, NULL, newIndices);CHKERRQ(ierr); 6679 } 6680 newP += bDof; 6681 6682 /* get the point-to-point submatrix */ 6683 if (outValues) { 6684 ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr); 6685 } 6686 } 6687 else { 6688 newPoints[2 * newP] = b; 6689 newPoints[2 * newP + 1] = o; 6690 newP++; 6691 } 6692 } 6693 } 6694 6695 if (outValues) { 6696 ierr = DMGetWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 6697 ierr = PetscArrayzero(tmpValues,newNumIndices*numIndices);CHKERRQ(ierr); 6698 /* multiply constraints on the right */ 6699 if (numFields) { 6700 for (f = 0; f < numFields; f++) { 6701 PetscInt oldOff = offsets[f]; 6702 6703 for (p = 0; p < numPoints; p++) { 6704 PetscInt cStart = newPointOffsets[f][p]; 6705 PetscInt b = points[2 * p]; 6706 PetscInt c, r, k; 6707 PetscInt dof; 6708 6709 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 6710 if (!dof) { 6711 continue; 6712 } 6713 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 6714 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 6715 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 6716 6717 for (r = 0; r < numIndices; r++) { 6718 for (c = 0; c < nCols; c++) { 6719 for (k = 0; k < dof; k++) { 6720 tmpValues[r * newNumIndices + cStart + c] += values[r * numIndices + oldOff + k] * mat[k * nCols + c]; 6721 } 6722 } 6723 } 6724 } 6725 else { 6726 /* copy this column as is */ 6727 for (r = 0; r < numIndices; r++) { 6728 for (c = 0; c < dof; c++) { 6729 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 6730 } 6731 } 6732 } 6733 oldOff += dof; 6734 } 6735 } 6736 } 6737 else { 6738 PetscInt oldOff = 0; 6739 for (p = 0; p < numPoints; p++) { 6740 PetscInt cStart = newPointOffsets[0][p]; 6741 PetscInt b = points[2 * p]; 6742 PetscInt c, r, k; 6743 PetscInt dof; 6744 6745 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 6746 if (!dof) { 6747 continue; 6748 } 6749 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 6750 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 6751 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 6752 6753 for (r = 0; r < numIndices; r++) { 6754 for (c = 0; c < nCols; c++) { 6755 for (k = 0; k < dof; k++) { 6756 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 6757 } 6758 } 6759 } 6760 } 6761 else { 6762 /* copy this column as is */ 6763 for (r = 0; r < numIndices; r++) { 6764 for (c = 0; c < dof; c++) { 6765 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 6766 } 6767 } 6768 } 6769 oldOff += dof; 6770 } 6771 } 6772 6773 if (multiplyLeft) { 6774 ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,MPIU_SCALAR,&newValues);CHKERRQ(ierr); 6775 ierr = PetscArrayzero(newValues,newNumIndices*newNumIndices);CHKERRQ(ierr); 6776 /* multiply constraints transpose on the left */ 6777 if (numFields) { 6778 for (f = 0; f < numFields; f++) { 6779 PetscInt oldOff = offsets[f]; 6780 6781 for (p = 0; p < numPoints; p++) { 6782 PetscInt rStart = newPointOffsets[f][p]; 6783 PetscInt b = points[2 * p]; 6784 PetscInt c, r, k; 6785 PetscInt dof; 6786 6787 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 6788 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 6789 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 6790 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 6791 6792 for (r = 0; r < nRows; r++) { 6793 for (c = 0; c < newNumIndices; c++) { 6794 for (k = 0; k < dof; k++) { 6795 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 6796 } 6797 } 6798 } 6799 } 6800 else { 6801 /* copy this row as is */ 6802 for (r = 0; r < dof; r++) { 6803 for (c = 0; c < newNumIndices; c++) { 6804 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 6805 } 6806 } 6807 } 6808 oldOff += dof; 6809 } 6810 } 6811 } 6812 else { 6813 PetscInt oldOff = 0; 6814 6815 for (p = 0; p < numPoints; p++) { 6816 PetscInt rStart = newPointOffsets[0][p]; 6817 PetscInt b = points[2 * p]; 6818 PetscInt c, r, k; 6819 PetscInt dof; 6820 6821 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 6822 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 6823 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 6824 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 6825 6826 for (r = 0; r < nRows; r++) { 6827 for (c = 0; c < newNumIndices; c++) { 6828 for (k = 0; k < dof; k++) { 6829 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 6830 } 6831 } 6832 } 6833 } 6834 else { 6835 /* copy this row as is */ 6836 for (r = 0; r < dof; r++) { 6837 for (c = 0; c < newNumIndices; c++) { 6838 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 6839 } 6840 } 6841 } 6842 oldOff += dof; 6843 } 6844 } 6845 6846 ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,MPIU_SCALAR,&tmpValues);CHKERRQ(ierr); 6847 } 6848 else { 6849 newValues = tmpValues; 6850 } 6851 } 6852 6853 /* clean up */ 6854 ierr = DMRestoreWorkArray(dm,maxDof,MPIU_INT,&indices);CHKERRQ(ierr); 6855 ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,MPIU_INT,&newIndices);CHKERRQ(ierr); 6856 6857 if (numFields) { 6858 for (f = 0; f < numFields; f++) { 6859 ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],MPIU_SCALAR,&pointMat[f]);CHKERRQ(ierr); 6860 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 6861 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[f]);CHKERRQ(ierr); 6862 } 6863 } 6864 else { 6865 ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],MPIU_SCALAR,&pointMat[0]);CHKERRQ(ierr); 6866 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 6867 ierr = DMRestoreWorkArray(dm,numPoints+1,MPIU_INT,&newPointOffsets[0]);CHKERRQ(ierr); 6868 } 6869 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 6870 6871 /* output */ 6872 if (outPoints) { 6873 *outPoints = newPoints; 6874 } 6875 else { 6876 ierr = DMRestoreWorkArray(dm,2*newNumPoints,MPIU_INT,&newPoints);CHKERRQ(ierr); 6877 } 6878 if (outValues) { 6879 *outValues = newValues; 6880 } 6881 for (f = 0; f <= numFields; f++) { 6882 offsets[f] = newOffsets[f]; 6883 } 6884 PetscFunctionReturn(0); 6885 } 6886 6887 /*@C 6888 DMPlexGetClosureIndices - Gets the global dof indices associated with the closure of the given point within the provided sections. 6889 6890 Not collective 6891 6892 Input Parameters: 6893 + dm - The DM 6894 . section - The PetscSection describing the points (a local section) 6895 . idxSection - The PetscSection from which to obtain indices (may be local or global) 6896 . point - The point defining the closure 6897 - useClPerm - Use the closure point permutation if available 6898 6899 Output Parameters: 6900 + numIndices - The number of dof indices in the closure of point with the input sections 6901 . indices - The dof indices 6902 . outOffsets - Array to write the field offsets into, or NULL 6903 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 6904 6905 Notes: 6906 Must call DMPlexRestoreClosureIndices() to free allocated memory 6907 6908 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 6909 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 6910 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 6911 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 6912 indices (with the above semantics) are implied. 6913 6914 Level: advanced 6915 6916 .seealso DMPlexRestoreClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 6917 @*/ 6918 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 6919 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 6920 { 6921 /* Closure ordering */ 6922 PetscSection clSection; 6923 IS clPoints; 6924 const PetscInt *clp; 6925 PetscInt *points; 6926 const PetscInt *clperm = NULL; 6927 /* Dof permutation and sign flips */ 6928 const PetscInt **perms[32] = {NULL}; 6929 const PetscScalar **flips[32] = {NULL}; 6930 PetscScalar *valCopy = NULL; 6931 /* Hanging node constraints */ 6932 PetscInt *pointsC = NULL; 6933 PetscScalar *valuesC = NULL; 6934 PetscInt NclC, NiC; 6935 6936 PetscInt *idx; 6937 PetscInt Nf, Ncl, Ni = 0, offsets[32], p, f; 6938 PetscBool isLocal = (section == idxSection) ? PETSC_TRUE : PETSC_FALSE; 6939 PetscErrorCode ierr; 6940 6941 PetscFunctionBeginHot; 6942 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6943 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 6944 PetscValidHeaderSpecific(idxSection, PETSC_SECTION_CLASSID, 3); 6945 if (numIndices) PetscValidPointer(numIndices, 6); 6946 if (indices) PetscValidPointer(indices, 7); 6947 if (outOffsets) PetscValidPointer(outOffsets, 8); 6948 if (values) PetscValidPointer(values, 9); 6949 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 6950 if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf); 6951 ierr = PetscArrayzero(offsets, 32);CHKERRQ(ierr); 6952 /* 1) Get points in closure */ 6953 ierr = DMPlexGetCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 6954 if (useClPerm) { 6955 PetscInt depth, clsize; 6956 ierr = DMPlexGetPointDepth(dm, point, &depth);CHKERRQ(ierr); 6957 for (clsize=0,p=0; p<Ncl; p++) { 6958 PetscInt dof; 6959 ierr = PetscSectionGetDof(section, points[2*p], &dof);CHKERRQ(ierr); 6960 clsize += dof; 6961 } 6962 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, depth, clsize, &clperm);CHKERRQ(ierr); 6963 } 6964 /* 2) Get number of indices on these points and field offsets from section */ 6965 for (p = 0; p < Ncl*2; p += 2) { 6966 PetscInt dof, fdof; 6967 6968 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 6969 for (f = 0; f < Nf; ++f) { 6970 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 6971 offsets[f+1] += fdof; 6972 } 6973 Ni += dof; 6974 } 6975 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 6976 if (Nf && offsets[Nf] != Ni) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", offsets[Nf], Ni); 6977 /* 3) Get symmetries and sign flips. Apply sign flips to values if passed in (only works for square values matrix) */ 6978 for (f = 0; f < PetscMax(1, Nf); ++f) { 6979 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 6980 else {ierr = PetscSectionGetPointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 6981 /* may need to apply sign changes to the element matrix */ 6982 if (values && flips[f]) { 6983 PetscInt foffset = offsets[f]; 6984 6985 for (p = 0; p < Ncl; ++p) { 6986 PetscInt pnt = points[2*p], fdof; 6987 const PetscScalar *flip = flips[f] ? flips[f][p] : NULL; 6988 6989 if (!Nf) {ierr = PetscSectionGetDof(section, pnt, &fdof);CHKERRQ(ierr);} 6990 else {ierr = PetscSectionGetFieldDof(section, pnt, f, &fdof);CHKERRQ(ierr);} 6991 if (flip) { 6992 PetscInt i, j, k; 6993 6994 if (!valCopy) { 6995 ierr = DMGetWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr); 6996 for (j = 0; j < Ni * Ni; ++j) valCopy[j] = (*values)[j]; 6997 *values = valCopy; 6998 } 6999 for (i = 0; i < fdof; ++i) { 7000 PetscScalar fval = flip[i]; 7001 7002 for (k = 0; k < Ni; ++k) { 7003 valCopy[Ni * (foffset + i) + k] *= fval; 7004 valCopy[Ni * k + (foffset + i)] *= fval; 7005 } 7006 } 7007 } 7008 foffset += fdof; 7009 } 7010 } 7011 } 7012 /* 4) Apply hanging node constraints. Get new symmetries and replace all storage with constrained storage */ 7013 ierr = DMPlexAnchorsModifyMat(dm, section, Ncl, Ni, points, perms, values ? *values : NULL, &NclC, &NiC, &pointsC, values ? &valuesC : NULL, offsets, PETSC_TRUE);CHKERRQ(ierr); 7014 if (NclC) { 7015 if (valCopy) {ierr = DMRestoreWorkArray(dm, Ni*Ni, MPIU_SCALAR, &valCopy);CHKERRQ(ierr);} 7016 for (f = 0; f < PetscMax(1, Nf); ++f) { 7017 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 7018 else {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 7019 } 7020 for (f = 0; f < PetscMax(1, Nf); ++f) { 7021 if (Nf) {ierr = PetscSectionGetFieldPointSyms(section, f, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);} 7022 else {ierr = PetscSectionGetPointSyms(section, NclC, pointsC, &perms[f], &flips[f]);CHKERRQ(ierr);} 7023 } 7024 ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 7025 Ncl = NclC; 7026 Ni = NiC; 7027 points = pointsC; 7028 if (values) *values = valuesC; 7029 } 7030 /* 5) Calculate indices */ 7031 ierr = DMGetWorkArray(dm, Ni, MPIU_INT, &idx);CHKERRQ(ierr); 7032 if (Nf) { 7033 PetscInt idxOff; 7034 PetscBool useFieldOffsets; 7035 7036 if (outOffsets) {for (f = 0; f <= Nf; f++) outOffsets[f] = offsets[f];} 7037 ierr = PetscSectionGetUseFieldOffsets(idxSection, &useFieldOffsets);CHKERRQ(ierr); 7038 if (useFieldOffsets) { 7039 for (p = 0; p < Ncl; ++p) { 7040 const PetscInt pnt = points[p*2]; 7041 7042 ierr = DMPlexGetIndicesPointFieldsSplit_Internal(section, idxSection, pnt, offsets, perms, p, clperm, idx);CHKERRQ(ierr); 7043 } 7044 } else { 7045 for (p = 0; p < Ncl; ++p) { 7046 const PetscInt pnt = points[p*2]; 7047 7048 ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr); 7049 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7050 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the 7051 * global section. */ 7052 ierr = DMPlexGetIndicesPointFields_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, offsets, PETSC_FALSE, perms, p, clperm, idx);CHKERRQ(ierr); 7053 } 7054 } 7055 } else { 7056 PetscInt off = 0, idxOff; 7057 7058 for (p = 0; p < Ncl; ++p) { 7059 const PetscInt pnt = points[p*2]; 7060 const PetscInt *perm = perms[0] ? perms[0][p] : NULL; 7061 7062 ierr = PetscSectionGetOffset(idxSection, pnt, &idxOff);CHKERRQ(ierr); 7063 /* Note that we pass a local section even though we're using global offsets. This is because global sections do 7064 * not (at the time of this writing) have fields set. They probably should, in which case we would pass the global section. */ 7065 ierr = DMPlexGetIndicesPoint_Internal(section, isLocal, pnt, idxOff < 0 ? -(idxOff+1) : idxOff, &off, PETSC_FALSE, perm, clperm, idx);CHKERRQ(ierr); 7066 } 7067 } 7068 /* 6) Cleanup */ 7069 for (f = 0; f < PetscMax(1, Nf); ++f) { 7070 if (Nf) {ierr = PetscSectionRestoreFieldPointSyms(section, f, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 7071 else {ierr = PetscSectionRestorePointSyms(section, Ncl, points, &perms[f], &flips[f]);CHKERRQ(ierr);} 7072 } 7073 if (NclC) { 7074 ierr = DMRestoreWorkArray(dm, NclC*2, MPIU_INT, &pointsC);CHKERRQ(ierr); 7075 } else { 7076 ierr = DMPlexRestoreCompressedClosure(dm, section, point, &Ncl, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 7077 } 7078 7079 if (numIndices) *numIndices = Ni; 7080 if (indices) *indices = idx; 7081 PetscFunctionReturn(0); 7082 } 7083 7084 /*@C 7085 DMPlexRestoreClosureIndices - Restores the global dof indices associated with the closure of the given point within the provided sections. 7086 7087 Not collective 7088 7089 Input Parameters: 7090 + dm - The DM 7091 . section - The PetscSection describing the points (a local section) 7092 . idxSection - The PetscSection from which to obtain indices (may be local or global) 7093 . point - The point defining the closure 7094 - useClPerm - Use the closure point permutation if available 7095 7096 Output Parameters: 7097 + numIndices - The number of dof indices in the closure of point with the input sections 7098 . indices - The dof indices 7099 . outOffsets - Array to write the field offsets into, or NULL 7100 - values - The input values, which may be modified if sign flips are induced by the point symmetries, or NULL 7101 7102 Notes: 7103 If values were modified, the user is responsible for calling DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values). 7104 7105 If idxSection is global, any constrained dofs (see DMAddBoundary(), for example) will get negative indices. The value 7106 of those indices is not significant. If idxSection is local, the constrained dofs will yield the involution -(idx+1) 7107 of their index in a local vector. A caller who does not wish to distinguish those points may recover the nonnegative 7108 indices via involution, -(-(idx+1)+1)==idx. Local indices are provided when idxSection == section, otherwise global 7109 indices (with the above semantics) are implied. 7110 7111 Level: advanced 7112 7113 .seealso DMPlexGetClosureIndices(), DMPlexVecGetClosure(), DMPlexMatSetClosure(), DMGetLocalSection(), DMGetGlobalSection() 7114 @*/ 7115 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection idxSection, PetscInt point, PetscBool useClPerm, 7116 PetscInt *numIndices, PetscInt *indices[], PetscInt outOffsets[], PetscScalar *values[]) 7117 { 7118 PetscErrorCode ierr; 7119 7120 PetscFunctionBegin; 7121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7122 PetscValidPointer(indices, 7); 7123 ierr = DMRestoreWorkArray(dm, 0, MPIU_INT, indices);CHKERRQ(ierr); 7124 PetscFunctionReturn(0); 7125 } 7126 7127 /*@C 7128 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 7129 7130 Not collective 7131 7132 Input Parameters: 7133 + dm - The DM 7134 . section - The section describing the layout in v, or NULL to use the default section 7135 . globalSection - The section describing the layout in v, or NULL to use the default global section 7136 . A - The matrix 7137 . point - The point in the DM 7138 . values - The array of values 7139 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7140 7141 Fortran Notes: 7142 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 7143 7144 Level: intermediate 7145 7146 .seealso DMPlexMatSetClosureGeneral(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7147 @*/ 7148 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7149 { 7150 DM_Plex *mesh = (DM_Plex*) dm->data; 7151 PetscInt *indices; 7152 PetscInt numIndices; 7153 const PetscScalar *valuesOrig = values; 7154 PetscErrorCode ierr; 7155 7156 PetscFunctionBegin; 7157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7158 if (!section) {ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr);} 7159 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 7160 if (!globalSection) {ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 7161 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 7162 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 7163 7164 ierr = DMPlexGetClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7165 7166 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);} 7167 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 7168 if (ierr) { 7169 PetscMPIInt rank; 7170 PetscErrorCode ierr2; 7171 7172 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2); 7173 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 7174 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2); 7175 ierr2 = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr2); 7176 if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);} 7177 CHKERRQ(ierr); 7178 } 7179 if (mesh->printFEM > 1) { 7180 PetscInt i; 7181 ierr = PetscPrintf(PETSC_COMM_SELF, " Indices:");CHKERRQ(ierr); 7182 for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %D", indices[i]);CHKERRQ(ierr);} 7183 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7184 } 7185 7186 ierr = DMPlexRestoreClosureIndices(dm, section, globalSection, point, PETSC_TRUE, &numIndices, &indices, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7187 if (values != valuesOrig) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);} 7188 PetscFunctionReturn(0); 7189 } 7190 7191 /*@C 7192 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' using a different row and column section 7193 7194 Not collective 7195 7196 Input Parameters: 7197 + dmRow - The DM for the row fields 7198 . sectionRow - The section describing the layout, or NULL to use the default section in dmRow 7199 . globalSectionRow - The section describing the layout, or NULL to use the default global section in dmRow 7200 . dmCol - The DM for the column fields 7201 . sectionCol - The section describing the layout, or NULL to use the default section in dmCol 7202 . globalSectionCol - The section describing the layout, or NULL to use the default global section in dmCol 7203 . A - The matrix 7204 . point - The point in the DMs 7205 . values - The array of values 7206 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 7207 7208 Level: intermediate 7209 7210 .seealso DMPlexMatSetClosure(), DMPlexVecGetClosure(), DMPlexVecSetClosure() 7211 @*/ 7212 PetscErrorCode DMPlexMatSetClosureGeneral(DM dmRow, PetscSection sectionRow, PetscSection globalSectionRow, DM dmCol, PetscSection sectionCol, PetscSection globalSectionCol, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7213 { 7214 DM_Plex *mesh = (DM_Plex*) dmRow->data; 7215 PetscInt *indicesRow, *indicesCol; 7216 PetscInt numIndicesRow, numIndicesCol; 7217 const PetscScalar *valuesOrig = values; 7218 PetscErrorCode ierr; 7219 7220 PetscFunctionBegin; 7221 PetscValidHeaderSpecific(dmRow, DM_CLASSID, 1); 7222 if (!sectionRow) {ierr = DMGetLocalSection(dmRow, §ionRow);CHKERRQ(ierr);} 7223 PetscValidHeaderSpecific(sectionRow, PETSC_SECTION_CLASSID, 2); 7224 if (!globalSectionRow) {ierr = DMGetGlobalSection(dmRow, &globalSectionRow);CHKERRQ(ierr);} 7225 PetscValidHeaderSpecific(globalSectionRow, PETSC_SECTION_CLASSID, 3); 7226 PetscValidHeaderSpecific(dmCol, DM_CLASSID, 4); 7227 if (!sectionCol) {ierr = DMGetLocalSection(dmCol, §ionCol);CHKERRQ(ierr);} 7228 PetscValidHeaderSpecific(sectionCol, PETSC_SECTION_CLASSID, 5); 7229 if (!globalSectionCol) {ierr = DMGetGlobalSection(dmCol, &globalSectionCol);CHKERRQ(ierr);} 7230 PetscValidHeaderSpecific(globalSectionCol, PETSC_SECTION_CLASSID, 6); 7231 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7232 7233 ierr = DMPlexGetClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7234 ierr = DMPlexGetClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7235 7236 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr);} 7237 ierr = MatSetValues(A, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values, mode); 7238 if (ierr) { 7239 PetscMPIInt rank; 7240 PetscErrorCode ierr2; 7241 7242 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2); 7243 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 7244 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndicesRow, indicesRow, numIndicesCol, indicesCol, values);CHKERRQ(ierr2); 7245 ierr2 = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2); 7246 ierr2 = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr2); 7247 if (values != valuesOrig) {ierr2 = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr2);} 7248 CHKERRQ(ierr); 7249 } 7250 7251 ierr = DMPlexRestoreClosureIndices(dmRow, sectionRow, globalSectionRow, point, PETSC_TRUE, &numIndicesRow, &indicesRow, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7252 ierr = DMPlexRestoreClosureIndices(dmCol, sectionCol, globalSectionCol, point, PETSC_TRUE, &numIndicesCol, &indicesCol, NULL, (PetscScalar **) &values);CHKERRQ(ierr); 7253 if (values != valuesOrig) {ierr = DMRestoreWorkArray(dmRow, 0, MPIU_SCALAR, &values);CHKERRQ(ierr);} 7254 PetscFunctionReturn(0); 7255 } 7256 7257 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 7258 { 7259 DM_Plex *mesh = (DM_Plex*) dmf->data; 7260 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7261 PetscInt *cpoints = NULL; 7262 PetscInt *findices, *cindices; 7263 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7264 PetscInt foffsets[32], coffsets[32]; 7265 DMPolytopeType ct; 7266 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7267 PetscErrorCode ierr; 7268 7269 PetscFunctionBegin; 7270 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7271 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7272 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 7273 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7274 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 7275 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7276 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 7277 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7278 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 7279 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7280 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 7281 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 7282 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7283 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 7284 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 7285 /* Column indices */ 7286 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 7287 maxFPoints = numCPoints; 7288 /* Compress out points not in the section */ 7289 /* TODO: Squeeze out points with 0 dof as well */ 7290 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 7291 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7292 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7293 cpoints[q*2] = cpoints[p]; 7294 cpoints[q*2+1] = cpoints[p+1]; 7295 ++q; 7296 } 7297 } 7298 numCPoints = q; 7299 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7300 PetscInt fdof; 7301 7302 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 7303 if (!dof) continue; 7304 for (f = 0; f < numFields; ++f) { 7305 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 7306 coffsets[f+1] += fdof; 7307 } 7308 numCIndices += dof; 7309 } 7310 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7311 /* Row indices */ 7312 ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr); 7313 { 7314 DMPlexCellRefiner cr; 7315 ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr); 7316 ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 7317 ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr); 7318 } 7319 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 7320 for (r = 0, q = 0; r < numSubcells; ++r) { 7321 /* TODO Map from coarse to fine cells */ 7322 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 7323 /* Compress out points not in the section */ 7324 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 7325 for (p = 0; p < numFPoints*2; p += 2) { 7326 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7327 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 7328 if (!dof) continue; 7329 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7330 if (s < q) continue; 7331 ftotpoints[q*2] = fpoints[p]; 7332 ftotpoints[q*2+1] = fpoints[p+1]; 7333 ++q; 7334 } 7335 } 7336 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 7337 } 7338 numFPoints = q; 7339 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7340 PetscInt fdof; 7341 7342 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 7343 if (!dof) continue; 7344 for (f = 0; f < numFields; ++f) { 7345 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 7346 foffsets[f+1] += fdof; 7347 } 7348 numFIndices += dof; 7349 } 7350 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7351 7352 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7353 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7354 ierr = DMGetWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 7355 ierr = DMGetWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 7356 if (numFields) { 7357 const PetscInt **permsF[32] = {NULL}; 7358 const PetscInt **permsC[32] = {NULL}; 7359 7360 for (f = 0; f < numFields; f++) { 7361 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 7362 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 7363 } 7364 for (p = 0; p < numFPoints; p++) { 7365 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 7366 ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr); 7367 } 7368 for (p = 0; p < numCPoints; p++) { 7369 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 7370 ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr); 7371 } 7372 for (f = 0; f < numFields; f++) { 7373 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 7374 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 7375 } 7376 } else { 7377 const PetscInt **permsF = NULL; 7378 const PetscInt **permsC = NULL; 7379 7380 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 7381 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 7382 for (p = 0, off = 0; p < numFPoints; p++) { 7383 const PetscInt *perm = permsF ? permsF[p] : NULL; 7384 7385 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 7386 ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr); 7387 } 7388 for (p = 0, off = 0; p < numCPoints; p++) { 7389 const PetscInt *perm = permsC ? permsC[p] : NULL; 7390 7391 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 7392 ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr); 7393 } 7394 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 7395 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 7396 } 7397 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);} 7398 /* TODO: flips */ 7399 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 7400 if (ierr) { 7401 PetscMPIInt rank; 7402 PetscErrorCode ierr2; 7403 7404 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRMPI(ierr2); 7405 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 7406 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2); 7407 ierr2 = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr2); 7408 ierr2 = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr2); 7409 CHKERRQ(ierr); 7410 } 7411 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 7412 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 7413 ierr = DMRestoreWorkArray(dmf, numFIndices, MPIU_INT, &findices);CHKERRQ(ierr); 7414 ierr = DMRestoreWorkArray(dmc, numCIndices, MPIU_INT, &cindices);CHKERRQ(ierr); 7415 PetscFunctionReturn(0); 7416 } 7417 7418 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 7419 { 7420 PetscInt *fpoints = NULL, *ftotpoints = NULL; 7421 PetscInt *cpoints = NULL; 7422 PetscInt foffsets[32], coffsets[32]; 7423 const PetscInt *fclperm = NULL, *cclperm = NULL; /* Closure permutations cannot work here */ 7424 DMPolytopeType ct; 7425 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 7426 PetscErrorCode ierr; 7427 7428 PetscFunctionBegin; 7429 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 7430 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 7431 if (!fsection) {ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr);} 7432 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 7433 if (!csection) {ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr);} 7434 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 7435 if (!globalFSection) {ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 7436 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 7437 if (!globalCSection) {ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 7438 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 7439 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 7440 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 7441 ierr = PetscArrayzero(foffsets, 32);CHKERRQ(ierr); 7442 ierr = PetscArrayzero(coffsets, 32);CHKERRQ(ierr); 7443 /* Column indices */ 7444 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 7445 maxFPoints = numCPoints; 7446 /* Compress out points not in the section */ 7447 /* TODO: Squeeze out points with 0 dof as well */ 7448 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 7449 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 7450 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 7451 cpoints[q*2] = cpoints[p]; 7452 cpoints[q*2+1] = cpoints[p+1]; 7453 ++q; 7454 } 7455 } 7456 numCPoints = q; 7457 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 7458 PetscInt fdof; 7459 7460 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 7461 if (!dof) continue; 7462 for (f = 0; f < numFields; ++f) { 7463 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 7464 coffsets[f+1] += fdof; 7465 } 7466 numCIndices += dof; 7467 } 7468 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 7469 /* Row indices */ 7470 ierr = DMPlexGetCellType(dmc, point, &ct);CHKERRQ(ierr); 7471 { 7472 DMPlexCellRefiner cr; 7473 ierr = DMPlexCellRefinerCreate(dmc, &cr);CHKERRQ(ierr); 7474 ierr = DMPlexCellRefinerGetAffineTransforms(cr, ct, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 7475 ierr = DMPlexCellRefinerDestroy(&cr);CHKERRQ(ierr); 7476 } 7477 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 7478 for (r = 0, q = 0; r < numSubcells; ++r) { 7479 /* TODO Map from coarse to fine cells */ 7480 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 7481 /* Compress out points not in the section */ 7482 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 7483 for (p = 0; p < numFPoints*2; p += 2) { 7484 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 7485 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 7486 if (!dof) continue; 7487 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 7488 if (s < q) continue; 7489 ftotpoints[q*2] = fpoints[p]; 7490 ftotpoints[q*2+1] = fpoints[p+1]; 7491 ++q; 7492 } 7493 } 7494 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 7495 } 7496 numFPoints = q; 7497 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 7498 PetscInt fdof; 7499 7500 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 7501 if (!dof) continue; 7502 for (f = 0; f < numFields; ++f) { 7503 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 7504 foffsets[f+1] += fdof; 7505 } 7506 numFIndices += dof; 7507 } 7508 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 7509 7510 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", foffsets[numFields], numFIndices); 7511 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", coffsets[numFields], numCIndices); 7512 if (numFields) { 7513 const PetscInt **permsF[32] = {NULL}; 7514 const PetscInt **permsC[32] = {NULL}; 7515 7516 for (f = 0; f < numFields; f++) { 7517 ierr = PetscSectionGetFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 7518 ierr = PetscSectionGetFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 7519 } 7520 for (p = 0; p < numFPoints; p++) { 7521 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 7522 ierr = DMPlexGetIndicesPointFields_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, permsF, p, fclperm, findices);CHKERRQ(ierr); 7523 } 7524 for (p = 0; p < numCPoints; p++) { 7525 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 7526 ierr = DMPlexGetIndicesPointFields_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, permsC, p, cclperm, cindices);CHKERRQ(ierr); 7527 } 7528 for (f = 0; f < numFields; f++) { 7529 ierr = PetscSectionRestoreFieldPointSyms(fsection,f,numFPoints,ftotpoints,&permsF[f],NULL);CHKERRQ(ierr); 7530 ierr = PetscSectionRestoreFieldPointSyms(csection,f,numCPoints,cpoints,&permsC[f],NULL);CHKERRQ(ierr); 7531 } 7532 } else { 7533 const PetscInt **permsF = NULL; 7534 const PetscInt **permsC = NULL; 7535 7536 ierr = PetscSectionGetPointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 7537 ierr = PetscSectionGetPointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 7538 for (p = 0, off = 0; p < numFPoints; p++) { 7539 const PetscInt *perm = permsF ? permsF[p] : NULL; 7540 7541 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[2*p], &globalOff);CHKERRQ(ierr); 7542 ierr = DMPlexGetIndicesPoint_Internal(fsection, PETSC_FALSE, ftotpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, fclperm, findices);CHKERRQ(ierr); 7543 } 7544 for (p = 0, off = 0; p < numCPoints; p++) { 7545 const PetscInt *perm = permsC ? permsC[p] : NULL; 7546 7547 ierr = PetscSectionGetOffset(globalCSection, cpoints[2*p], &globalOff);CHKERRQ(ierr); 7548 ierr = DMPlexGetIndicesPoint_Internal(csection, PETSC_FALSE, cpoints[2*p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, perm, cclperm, cindices);CHKERRQ(ierr); 7549 } 7550 ierr = PetscSectionRestorePointSyms(fsection,numFPoints,ftotpoints,&permsF,NULL);CHKERRQ(ierr); 7551 ierr = PetscSectionRestorePointSyms(csection,numCPoints,cpoints,&permsC,NULL);CHKERRQ(ierr); 7552 } 7553 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, MPIU_INT, &ftotpoints);CHKERRQ(ierr); 7554 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 7555 PetscFunctionReturn(0); 7556 } 7557 7558 /*@C 7559 DMPlexGetVTKCellHeight - Returns the height in the DAG used to determine which points are cells (normally 0) 7560 7561 Input Parameter: 7562 . dm - The DMPlex object 7563 7564 Output Parameter: 7565 . cellHeight - The height of a cell 7566 7567 Level: developer 7568 7569 .seealso DMPlexSetVTKCellHeight() 7570 @*/ 7571 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 7572 { 7573 DM_Plex *mesh = (DM_Plex*) dm->data; 7574 7575 PetscFunctionBegin; 7576 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7577 PetscValidPointer(cellHeight, 2); 7578 *cellHeight = mesh->vtkCellHeight; 7579 PetscFunctionReturn(0); 7580 } 7581 7582 /*@C 7583 DMPlexSetVTKCellHeight - Sets the height in the DAG used to determine which points are cells (normally 0) 7584 7585 Input Parameters: 7586 + dm - The DMPlex object 7587 - cellHeight - The height of a cell 7588 7589 Level: developer 7590 7591 .seealso DMPlexGetVTKCellHeight() 7592 @*/ 7593 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 7594 { 7595 DM_Plex *mesh = (DM_Plex*) dm->data; 7596 7597 PetscFunctionBegin; 7598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7599 mesh->vtkCellHeight = cellHeight; 7600 PetscFunctionReturn(0); 7601 } 7602 7603 /*@ 7604 DMPlexGetGhostCellStratum - Get the range of cells which are used to enforce FV boundary conditions 7605 7606 Input Parameter: 7607 . dm - The DMPlex object 7608 7609 Output Parameters: 7610 + gcStart - The first ghost cell, or NULL 7611 - gcEnd - The upper bound on ghost cells, or NULL 7612 7613 Level: advanced 7614 7615 .seealso DMPlexConstructGhostCells(), DMPlexGetGhostCellStratum() 7616 @*/ 7617 PetscErrorCode DMPlexGetGhostCellStratum(DM dm, PetscInt *gcStart, PetscInt *gcEnd) 7618 { 7619 DMLabel ctLabel; 7620 PetscErrorCode ierr; 7621 7622 PetscFunctionBegin; 7623 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7624 ierr = DMPlexGetCellTypeLabel(dm, &ctLabel);CHKERRQ(ierr); 7625 ierr = DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_FV_GHOST, gcStart, gcEnd);CHKERRQ(ierr); 7626 PetscFunctionReturn(0); 7627 } 7628 7629 /* We can easily have a form that takes an IS instead */ 7630 PetscErrorCode DMPlexCreateNumbering_Plex(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 7631 { 7632 PetscSection section, globalSection; 7633 PetscInt *numbers, p; 7634 PetscErrorCode ierr; 7635 7636 PetscFunctionBegin; 7637 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 7638 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 7639 for (p = pStart; p < pEnd; ++p) { 7640 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 7641 } 7642 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 7643 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 7644 ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr); 7645 for (p = pStart; p < pEnd; ++p) { 7646 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 7647 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 7648 else numbers[p-pStart] += shift; 7649 } 7650 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 7651 if (globalSize) { 7652 PetscLayout layout; 7653 ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr); 7654 ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr); 7655 ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr); 7656 } 7657 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 7658 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 7659 PetscFunctionReturn(0); 7660 } 7661 7662 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 7663 { 7664 PetscInt cellHeight, cStart, cEnd; 7665 PetscErrorCode ierr; 7666 7667 PetscFunctionBegin; 7668 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 7669 if (includeHybrid) {ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);} 7670 else {ierr = DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);} 7671 ierr = DMPlexCreateNumbering_Plex(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr); 7672 PetscFunctionReturn(0); 7673 } 7674 7675 /*@ 7676 DMPlexGetCellNumbering - Get a global cell numbering for all cells on this process 7677 7678 Input Parameter: 7679 . dm - The DMPlex object 7680 7681 Output Parameter: 7682 . globalCellNumbers - Global cell numbers for all cells on this process 7683 7684 Level: developer 7685 7686 .seealso DMPlexGetVertexNumbering() 7687 @*/ 7688 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 7689 { 7690 DM_Plex *mesh = (DM_Plex*) dm->data; 7691 PetscErrorCode ierr; 7692 7693 PetscFunctionBegin; 7694 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7695 if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);} 7696 *globalCellNumbers = mesh->globalCellNumbers; 7697 PetscFunctionReturn(0); 7698 } 7699 7700 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 7701 { 7702 PetscInt vStart, vEnd; 7703 PetscErrorCode ierr; 7704 7705 PetscFunctionBegin; 7706 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7707 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 7708 ierr = DMPlexCreateNumbering_Plex(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr); 7709 PetscFunctionReturn(0); 7710 } 7711 7712 /*@ 7713 DMPlexGetVertexNumbering - Get a global vertex numbering for all vertices on this process 7714 7715 Input Parameter: 7716 . dm - The DMPlex object 7717 7718 Output Parameter: 7719 . globalVertexNumbers - Global vertex numbers for all vertices on this process 7720 7721 Level: developer 7722 7723 .seealso DMPlexGetCellNumbering() 7724 @*/ 7725 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 7726 { 7727 DM_Plex *mesh = (DM_Plex*) dm->data; 7728 PetscErrorCode ierr; 7729 7730 PetscFunctionBegin; 7731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7732 if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);} 7733 *globalVertexNumbers = mesh->globalVertexNumbers; 7734 PetscFunctionReturn(0); 7735 } 7736 7737 /*@ 7738 DMPlexCreatePointNumbering - Create a global numbering for all points on this process 7739 7740 Input Parameter: 7741 . dm - The DMPlex object 7742 7743 Output Parameter: 7744 . globalPointNumbers - Global numbers for all points on this process 7745 7746 Level: developer 7747 7748 .seealso DMPlexGetCellNumbering() 7749 @*/ 7750 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 7751 { 7752 IS nums[4]; 7753 PetscInt depths[4], gdepths[4], starts[4]; 7754 PetscInt depth, d, shift = 0; 7755 PetscErrorCode ierr; 7756 7757 PetscFunctionBegin; 7758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7759 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 7760 /* For unstratified meshes use dim instead of depth */ 7761 if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);} 7762 for (d = 0; d <= depth; ++d) { 7763 PetscInt end; 7764 7765 depths[d] = depth-d; 7766 ierr = DMPlexGetDepthStratum(dm, depths[d], &starts[d], &end);CHKERRQ(ierr); 7767 if (!(starts[d]-end)) { starts[d] = depths[d] = -1; } 7768 } 7769 ierr = PetscSortIntWithArray(depth+1, starts, depths);CHKERRQ(ierr); 7770 ierr = MPIU_Allreduce(depths, gdepths, depth+1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr); 7771 for (d = 0; d <= depth; ++d) { 7772 if (starts[d] >= 0 && depths[d] != gdepths[d]) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected depth %D, found %D",depths[d],gdepths[d]); 7773 } 7774 for (d = 0; d <= depth; ++d) { 7775 PetscInt pStart, pEnd, gsize; 7776 7777 ierr = DMPlexGetDepthStratum(dm, gdepths[d], &pStart, &pEnd);CHKERRQ(ierr); 7778 ierr = DMPlexCreateNumbering_Plex(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr); 7779 shift += gsize; 7780 } 7781 ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr); 7782 for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);} 7783 PetscFunctionReturn(0); 7784 } 7785 7786 /*@ 7787 DMPlexCreateRankField - Create a cell field whose value is the rank of the owner 7788 7789 Input Parameter: 7790 . dm - The DMPlex object 7791 7792 Output Parameter: 7793 . ranks - The rank field 7794 7795 Options Database Keys: 7796 . -dm_partition_view - Adds the rank field into the DM output from -dm_view using the same viewer 7797 7798 Level: intermediate 7799 7800 .seealso: DMView() 7801 @*/ 7802 PetscErrorCode DMPlexCreateRankField(DM dm, Vec *ranks) 7803 { 7804 DM rdm; 7805 PetscFE fe; 7806 PetscScalar *r; 7807 PetscMPIInt rank; 7808 DMPolytopeType ct; 7809 PetscInt dim, cStart, cEnd, c; 7810 PetscBool simplex; 7811 PetscErrorCode ierr; 7812 7813 PetscFunctionBeginUser; 7814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7815 PetscValidPointer(ranks, 2); 7816 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRMPI(ierr); 7817 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7818 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7819 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7820 ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 7821 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 7822 ierr = PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "PETSc___rank_", -1, &fe);CHKERRQ(ierr); 7823 ierr = PetscObjectSetName((PetscObject) fe, "rank");CHKERRQ(ierr); 7824 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7825 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7826 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7827 ierr = DMCreateGlobalVector(rdm, ranks);CHKERRQ(ierr); 7828 ierr = PetscObjectSetName((PetscObject) *ranks, "partition");CHKERRQ(ierr); 7829 ierr = VecGetArray(*ranks, &r);CHKERRQ(ierr); 7830 for (c = cStart; c < cEnd; ++c) { 7831 PetscScalar *lr; 7832 7833 ierr = DMPlexPointGlobalRef(rdm, c, r, &lr);CHKERRQ(ierr); 7834 if (lr) *lr = rank; 7835 } 7836 ierr = VecRestoreArray(*ranks, &r);CHKERRQ(ierr); 7837 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7838 PetscFunctionReturn(0); 7839 } 7840 7841 /*@ 7842 DMPlexCreateLabelField - Create a cell field whose value is the label value for that cell 7843 7844 Input Parameters: 7845 + dm - The DMPlex 7846 - label - The DMLabel 7847 7848 Output Parameter: 7849 . val - The label value field 7850 7851 Options Database Keys: 7852 . -dm_label_view - Adds the label value field into the DM output from -dm_view using the same viewer 7853 7854 Level: intermediate 7855 7856 .seealso: DMView() 7857 @*/ 7858 PetscErrorCode DMPlexCreateLabelField(DM dm, DMLabel label, Vec *val) 7859 { 7860 DM rdm; 7861 PetscFE fe; 7862 PetscScalar *v; 7863 PetscInt dim, cStart, cEnd, c; 7864 PetscErrorCode ierr; 7865 7866 PetscFunctionBeginUser; 7867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7868 PetscValidPointer(label, 2); 7869 PetscValidPointer(val, 3); 7870 ierr = DMClone(dm, &rdm);CHKERRQ(ierr); 7871 ierr = DMGetDimension(rdm, &dim);CHKERRQ(ierr); 7872 ierr = PetscFECreateDefault(PetscObjectComm((PetscObject) rdm), dim, 1, PETSC_TRUE, "PETSc___label_value_", -1, &fe);CHKERRQ(ierr); 7873 ierr = PetscObjectSetName((PetscObject) fe, "label_value");CHKERRQ(ierr); 7874 ierr = DMSetField(rdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr); 7875 ierr = PetscFEDestroy(&fe);CHKERRQ(ierr); 7876 ierr = DMCreateDS(rdm);CHKERRQ(ierr); 7877 ierr = DMPlexGetHeightStratum(rdm, 0, &cStart, &cEnd);CHKERRQ(ierr); 7878 ierr = DMCreateGlobalVector(rdm, val);CHKERRQ(ierr); 7879 ierr = PetscObjectSetName((PetscObject) *val, "label_value");CHKERRQ(ierr); 7880 ierr = VecGetArray(*val, &v);CHKERRQ(ierr); 7881 for (c = cStart; c < cEnd; ++c) { 7882 PetscScalar *lv; 7883 PetscInt cval; 7884 7885 ierr = DMPlexPointGlobalRef(rdm, c, v, &lv);CHKERRQ(ierr); 7886 ierr = DMLabelGetValue(label, c, &cval);CHKERRQ(ierr); 7887 *lv = cval; 7888 } 7889 ierr = VecRestoreArray(*val, &v);CHKERRQ(ierr); 7890 ierr = DMDestroy(&rdm);CHKERRQ(ierr); 7891 PetscFunctionReturn(0); 7892 } 7893 7894 /*@ 7895 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 7896 7897 Input Parameter: 7898 . dm - The DMPlex object 7899 7900 Notes: 7901 This is a useful diagnostic when creating meshes programmatically. 7902 7903 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 7904 7905 Level: developer 7906 7907 .seealso: DMCreate(), DMSetFromOptions() 7908 @*/ 7909 PetscErrorCode DMPlexCheckSymmetry(DM dm) 7910 { 7911 PetscSection coneSection, supportSection; 7912 const PetscInt *cone, *support; 7913 PetscInt coneSize, c, supportSize, s; 7914 PetscInt pStart, pEnd, p, pp, csize, ssize; 7915 PetscBool storagecheck = PETSC_TRUE; 7916 PetscErrorCode ierr; 7917 7918 PetscFunctionBegin; 7919 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7920 ierr = DMViewFromOptions(dm, NULL, "-sym_dm_view");CHKERRQ(ierr); 7921 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 7922 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 7923 /* Check that point p is found in the support of its cone points, and vice versa */ 7924 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 7925 for (p = pStart; p < pEnd; ++p) { 7926 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 7927 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 7928 for (c = 0; c < coneSize; ++c) { 7929 PetscBool dup = PETSC_FALSE; 7930 PetscInt d; 7931 for (d = c-1; d >= 0; --d) { 7932 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 7933 } 7934 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 7935 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 7936 for (s = 0; s < supportSize; ++s) { 7937 if (support[s] == p) break; 7938 } 7939 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 7940 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", p);CHKERRQ(ierr); 7941 for (s = 0; s < coneSize; ++s) { 7942 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[s]);CHKERRQ(ierr); 7943 } 7944 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7945 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", cone[c]);CHKERRQ(ierr); 7946 for (s = 0; s < supportSize; ++s) { 7947 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[s]);CHKERRQ(ierr); 7948 } 7949 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7950 if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not repeatedly found in support of repeated cone point %D", p, cone[c]); 7951 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in support of cone point %D", p, cone[c]); 7952 } 7953 } 7954 ierr = DMPlexGetTreeParent(dm, p, &pp, NULL);CHKERRQ(ierr); 7955 if (p != pp) { storagecheck = PETSC_FALSE; continue; } 7956 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 7957 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 7958 for (s = 0; s < supportSize; ++s) { 7959 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 7960 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 7961 for (c = 0; c < coneSize; ++c) { 7962 ierr = DMPlexGetTreeParent(dm, cone[c], &pp, NULL);CHKERRQ(ierr); 7963 if (cone[c] != pp) { c = 0; break; } 7964 if (cone[c] == p) break; 7965 } 7966 if (c >= coneSize) { 7967 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D support: ", p);CHKERRQ(ierr); 7968 for (c = 0; c < supportSize; ++c) { 7969 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", support[c]);CHKERRQ(ierr); 7970 } 7971 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7972 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %D cone: ", support[s]);CHKERRQ(ierr); 7973 for (c = 0; c < coneSize; ++c) { 7974 ierr = PetscPrintf(PETSC_COMM_SELF, "%D, ", cone[c]);CHKERRQ(ierr); 7975 } 7976 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 7977 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D not found in cone of support point %D", p, support[s]); 7978 } 7979 } 7980 } 7981 if (storagecheck) { 7982 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 7983 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 7984 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %D != Total support size %D", csize, ssize); 7985 } 7986 PetscFunctionReturn(0); 7987 } 7988 7989 /* 7990 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. 7991 */ 7992 static PetscErrorCode DMPlexCellUnsplitVertices_Private(DM dm, PetscInt c, DMPolytopeType ct, PetscInt *unsplit) 7993 { 7994 DMPolytopeType cct; 7995 PetscInt ptpoints[4]; 7996 const PetscInt *cone, *ccone, *ptcone; 7997 PetscInt coneSize, cp, cconeSize, ccp, npt = 0, pt; 7998 PetscErrorCode ierr; 7999 8000 PetscFunctionBegin; 8001 *unsplit = 0; 8002 switch (ct) { 8003 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8004 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 8005 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 8006 for (cp = 0; cp < coneSize; ++cp) { 8007 ierr = DMPlexGetCellType(dm, cone[cp], &cct);CHKERRQ(ierr); 8008 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) ptpoints[npt++] = cone[cp]; 8009 } 8010 break; 8011 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8012 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8013 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 8014 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 8015 for (cp = 0; cp < coneSize; ++cp) { 8016 ierr = DMPlexGetCone(dm, cone[cp], &ccone);CHKERRQ(ierr); 8017 ierr = DMPlexGetConeSize(dm, cone[cp], &cconeSize);CHKERRQ(ierr); 8018 for (ccp = 0; ccp < cconeSize; ++ccp) { 8019 ierr = DMPlexGetCellType(dm, ccone[ccp], &cct);CHKERRQ(ierr); 8020 if (cct == DM_POLYTOPE_POINT_PRISM_TENSOR) { 8021 PetscInt p; 8022 for (p = 0; p < npt; ++p) if (ptpoints[p] == ccone[ccp]) break; 8023 if (p == npt) ptpoints[npt++] = ccone[ccp]; 8024 } 8025 } 8026 } 8027 break; 8028 default: break; 8029 } 8030 for (pt = 0; pt < npt; ++pt) { 8031 ierr = DMPlexGetCone(dm, ptpoints[pt], &ptcone);CHKERRQ(ierr); 8032 if (ptcone[0] == ptcone[1]) ++(*unsplit); 8033 } 8034 PetscFunctionReturn(0); 8035 } 8036 8037 /*@ 8038 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 8039 8040 Input Parameters: 8041 + dm - The DMPlex object 8042 - cellHeight - Normally 0 8043 8044 Notes: 8045 This is a useful diagnostic when creating meshes programmatically. 8046 Currently applicable only to homogeneous simplex or tensor meshes. 8047 8048 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8049 8050 Level: developer 8051 8052 .seealso: DMCreate(), DMSetFromOptions() 8053 @*/ 8054 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscInt cellHeight) 8055 { 8056 DMPlexInterpolatedFlag interp; 8057 DMPolytopeType ct; 8058 PetscInt vStart, vEnd, cStart, cEnd, c; 8059 PetscErrorCode ierr; 8060 8061 PetscFunctionBegin; 8062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8063 ierr = DMPlexIsInterpolated(dm, &interp);CHKERRQ(ierr); 8064 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 8065 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 8066 for (c = cStart; c < cEnd; ++c) { 8067 PetscInt *closure = NULL; 8068 PetscInt coneSize, closureSize, cl, Nv = 0; 8069 8070 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 8071 if ((PetscInt) ct < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %D has no cell type", c); 8072 if (ct == DM_POLYTOPE_UNKNOWN) continue; 8073 if (interp == DMPLEX_INTERPOLATED_FULL) { 8074 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 8075 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)); 8076 } 8077 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 8078 for (cl = 0; cl < closureSize*2; cl += 2) { 8079 const PetscInt p = closure[cl]; 8080 if ((p >= vStart) && (p < vEnd)) ++Nv; 8081 } 8082 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 8083 /* Special Case: Tensor faces with identified vertices */ 8084 if (Nv < DMPolytopeTypeGetNumVertices(ct)) { 8085 PetscInt unsplit; 8086 8087 ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr); 8088 if (Nv + unsplit == DMPolytopeTypeGetNumVertices(ct)) continue; 8089 } 8090 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)); 8091 } 8092 PetscFunctionReturn(0); 8093 } 8094 8095 /*@ 8096 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 8097 8098 Not Collective 8099 8100 Input Parameters: 8101 + dm - The DMPlex object 8102 - cellHeight - Normally 0 8103 8104 Notes: 8105 This is a useful diagnostic when creating meshes programmatically. 8106 This routine is only relevant for meshes that are fully interpolated across all ranks. 8107 It will error out if a partially interpolated mesh is given on some rank. 8108 It will do nothing for locally uninterpolated mesh (as there is nothing to check). 8109 8110 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8111 8112 Level: developer 8113 8114 .seealso: DMCreate(), DMPlexGetVTKCellHeight(), DMSetFromOptions() 8115 @*/ 8116 PetscErrorCode DMPlexCheckFaces(DM dm, PetscInt cellHeight) 8117 { 8118 PetscInt dim, depth, vStart, vEnd, cStart, cEnd, c, h; 8119 PetscErrorCode ierr; 8120 DMPlexInterpolatedFlag interpEnum; 8121 8122 PetscFunctionBegin; 8123 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8124 ierr = DMPlexIsInterpolated(dm, &interpEnum);CHKERRQ(ierr); 8125 if (interpEnum == DMPLEX_INTERPOLATED_NONE) PetscFunctionReturn(0); 8126 if (interpEnum == DMPLEX_INTERPOLATED_PARTIAL) { 8127 PetscMPIInt rank; 8128 MPI_Comm comm; 8129 8130 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 8131 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 8132 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Mesh is only partially interpolated on rank %d, this is currently not supported", rank); 8133 } 8134 8135 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 8136 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 8137 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 8138 for (h = cellHeight; h < PetscMin(depth, dim); ++h) { 8139 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 8140 for (c = cStart; c < cEnd; ++c) { 8141 const PetscInt *cone, *ornt, *faceSizes, *faces; 8142 const DMPolytopeType *faceTypes; 8143 DMPolytopeType ct; 8144 PetscInt numFaces, coneSize, f; 8145 PetscInt *closure = NULL, closureSize, cl, numCorners = 0, fOff = 0, unsplit; 8146 8147 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 8148 ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr); 8149 if (unsplit) continue; 8150 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 8151 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 8152 ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr); 8153 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 8154 for (cl = 0; cl < closureSize*2; cl += 2) { 8155 const PetscInt p = closure[cl]; 8156 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 8157 } 8158 ierr = DMPlexGetRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr); 8159 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); 8160 for (f = 0; f < numFaces; ++f) { 8161 DMPolytopeType fct; 8162 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 8163 8164 ierr = DMPlexGetCellType(dm, cone[f], &fct);CHKERRQ(ierr); 8165 ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 8166 for (cl = 0; cl < fclosureSize*2; cl += 2) { 8167 const PetscInt p = fclosure[cl]; 8168 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 8169 } 8170 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]); 8171 for (v = 0; v < fnumCorners; ++v) { 8172 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]); 8173 } 8174 ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 8175 fOff += faceSizes[f]; 8176 } 8177 ierr = DMPlexRestoreRawFaces_Internal(dm, ct, closure, &numFaces, &faceTypes, &faceSizes, &faces);CHKERRQ(ierr); 8178 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 8179 } 8180 } 8181 PetscFunctionReturn(0); 8182 } 8183 8184 /*@ 8185 DMPlexCheckGeometry - Check the geometry of mesh cells 8186 8187 Input Parameter: 8188 . dm - The DMPlex object 8189 8190 Notes: 8191 This is a useful diagnostic when creating meshes programmatically. 8192 8193 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8194 8195 Level: developer 8196 8197 .seealso: DMCreate(), DMSetFromOptions() 8198 @*/ 8199 PetscErrorCode DMPlexCheckGeometry(DM dm) 8200 { 8201 Vec coordinates; 8202 PetscReal detJ, J[9], refVol = 1.0; 8203 PetscReal vol; 8204 PetscBool periodic; 8205 PetscInt dim, depth, dE, d, cStart, cEnd, c; 8206 PetscErrorCode ierr; 8207 8208 PetscFunctionBegin; 8209 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 8210 ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr); 8211 if (dim != dE) PetscFunctionReturn(0); 8212 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 8213 ierr = DMGetPeriodicity(dm, &periodic, NULL, NULL, NULL);CHKERRQ(ierr); 8214 for (d = 0; d < dim; ++d) refVol *= 2.0; 8215 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 8216 /* Make sure local coordinates are created, because that step is collective */ 8217 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 8218 for (c = cStart; c < cEnd; ++c) { 8219 DMPolytopeType ct; 8220 PetscInt unsplit; 8221 PetscBool ignoreZeroVol = PETSC_FALSE; 8222 8223 ierr = DMPlexGetCellType(dm, c, &ct);CHKERRQ(ierr); 8224 switch (ct) { 8225 case DM_POLYTOPE_SEG_PRISM_TENSOR: 8226 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8227 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8228 ignoreZeroVol = PETSC_TRUE; break; 8229 default: break; 8230 } 8231 switch (ct) { 8232 case DM_POLYTOPE_TRI_PRISM: 8233 case DM_POLYTOPE_TRI_PRISM_TENSOR: 8234 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 8235 case DM_POLYTOPE_PYRAMID: 8236 continue; 8237 default: break; 8238 } 8239 ierr = DMPlexCellUnsplitVertices_Private(dm, c, ct, &unsplit);CHKERRQ(ierr); 8240 if (unsplit) continue; 8241 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, NULL, J, NULL, &detJ);CHKERRQ(ierr); 8242 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); 8243 ierr = PetscInfo2(dm, "Cell %D FEM Volume %g\n", c, (double) detJ*refVol);CHKERRQ(ierr); 8244 if (depth > 1 && !periodic) { 8245 ierr = DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL);CHKERRQ(ierr); 8246 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); 8247 ierr = PetscInfo2(dm, "Cell %D FVM Volume %g\n", c, (double) vol);CHKERRQ(ierr); 8248 } 8249 } 8250 PetscFunctionReturn(0); 8251 } 8252 8253 /*@ 8254 DMPlexCheckPointSF - Check that several necessary conditions are met for the point SF of this plex. 8255 8256 Input Parameters: 8257 . dm - The DMPlex object 8258 8259 Notes: 8260 This is mainly intended for debugging/testing purposes. 8261 It currently checks only meshes with no partition overlapping. 8262 8263 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8264 8265 Level: developer 8266 8267 .seealso: DMGetPointSF(), DMSetFromOptions() 8268 @*/ 8269 PetscErrorCode DMPlexCheckPointSF(DM dm) 8270 { 8271 PetscSF pointSF; 8272 PetscInt cellHeight, cStart, cEnd, l, nleaves, nroots, overlap; 8273 const PetscInt *locals, *rootdegree; 8274 PetscBool distributed; 8275 PetscErrorCode ierr; 8276 8277 PetscFunctionBegin; 8278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8279 ierr = DMGetPointSF(dm, &pointSF);CHKERRQ(ierr); 8280 ierr = DMPlexIsDistributed(dm, &distributed);CHKERRQ(ierr); 8281 if (!distributed) PetscFunctionReturn(0); 8282 ierr = DMPlexGetOverlap(dm, &overlap);CHKERRQ(ierr); 8283 if (overlap) { 8284 ierr = PetscPrintf(PetscObjectComm((PetscObject)dm), "Warning: DMPlexCheckPointSF() is currently not implemented for meshes with partition overlapping"); 8285 PetscFunctionReturn(0); 8286 } 8287 if (!pointSF) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but does not have PointSF attached"); 8288 ierr = PetscSFGetGraph(pointSF, &nroots, &nleaves, &locals, NULL);CHKERRQ(ierr); 8289 if (nroots < 0) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "This DMPlex is distributed but its PointSF has no graph set"); 8290 ierr = PetscSFComputeDegreeBegin(pointSF, &rootdegree);CHKERRQ(ierr); 8291 ierr = PetscSFComputeDegreeEnd(pointSF, &rootdegree);CHKERRQ(ierr); 8292 8293 /* 1) check there are no faces in 2D, cells in 3D, in interface */ 8294 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 8295 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 8296 for (l = 0; l < nleaves; ++l) { 8297 const PetscInt point = locals[l]; 8298 8299 if (point >= cStart && point < cEnd) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D which is a cell", point); 8300 } 8301 8302 /* 2) if some point is in interface, then all its cone points must be also in interface (either as leaves or roots) */ 8303 for (l = 0; l < nleaves; ++l) { 8304 const PetscInt point = locals[l]; 8305 const PetscInt *cone; 8306 PetscInt coneSize, c, idx; 8307 8308 ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr); 8309 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 8310 for (c = 0; c < coneSize; ++c) { 8311 if (!rootdegree[cone[c]]) { 8312 ierr = PetscFindInt(cone[c], nleaves, locals, &idx);CHKERRQ(ierr); 8313 if (idx < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point SF contains %D but not %D from its cone", point, cone[c]); 8314 } 8315 } 8316 } 8317 PetscFunctionReturn(0); 8318 } 8319 8320 typedef struct cell_stats 8321 { 8322 PetscReal min, max, sum, squaresum; 8323 PetscInt count; 8324 } cell_stats_t; 8325 8326 static void MPIAPI cell_stats_reduce(void *a, void *b, int * len, MPI_Datatype *datatype) 8327 { 8328 PetscInt i, N = *len; 8329 8330 for (i = 0; i < N; i++) { 8331 cell_stats_t *A = (cell_stats_t *) a; 8332 cell_stats_t *B = (cell_stats_t *) b; 8333 8334 B->min = PetscMin(A->min,B->min); 8335 B->max = PetscMax(A->max,B->max); 8336 B->sum += A->sum; 8337 B->squaresum += A->squaresum; 8338 B->count += A->count; 8339 } 8340 } 8341 8342 /*@ 8343 DMPlexCheckCellShape - Checks the Jacobian of the mapping from reference to real cells and computes some minimal statistics. 8344 8345 Collective on dm 8346 8347 Input Parameters: 8348 + dm - The DMPlex object 8349 . output - If true, statistics will be displayed on stdout 8350 - condLimit - Display all cells above this condition number, or PETSC_DETERMINE for no cell output 8351 8352 Notes: 8353 This is mainly intended for debugging/testing purposes. 8354 8355 For the complete list of DMPlexCheck* functions, see DMSetFromOptions(). 8356 8357 Level: developer 8358 8359 .seealso: DMSetFromOptions(), DMPlexComputeOrthogonalQuality() 8360 @*/ 8361 PetscErrorCode DMPlexCheckCellShape(DM dm, PetscBool output, PetscReal condLimit) 8362 { 8363 DM dmCoarse; 8364 cell_stats_t stats, globalStats; 8365 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 8366 PetscReal *J, *invJ, min = 0, max = 0, mean = 0, stdev = 0; 8367 PetscReal limit = condLimit > 0 ? condLimit : PETSC_MAX_REAL; 8368 PetscInt cdim, cStart, cEnd, c, eStart, eEnd, count = 0; 8369 PetscMPIInt rank,size; 8370 PetscErrorCode ierr; 8371 8372 PetscFunctionBegin; 8373 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8374 stats.min = PETSC_MAX_REAL; 8375 stats.max = PETSC_MIN_REAL; 8376 stats.sum = stats.squaresum = 0.; 8377 stats.count = 0; 8378 8379 ierr = MPI_Comm_size(comm, &size);CHKERRMPI(ierr); 8380 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 8381 ierr = DMGetCoordinateDim(dm,&cdim);CHKERRQ(ierr); 8382 ierr = PetscMalloc2(PetscSqr(cdim), &J, PetscSqr(cdim), &invJ);CHKERRQ(ierr); 8383 ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr); 8384 ierr = DMPlexGetDepthStratum(dm,1,&eStart,&eEnd);CHKERRQ(ierr); 8385 for (c = cStart; c < cEnd; c++) { 8386 PetscInt i; 8387 PetscReal frobJ = 0., frobInvJ = 0., cond2, cond, detJ; 8388 8389 ierr = DMPlexComputeCellGeometryAffineFEM(dm,c,NULL,J,invJ,&detJ);CHKERRQ(ierr); 8390 if (detJ < 0.0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Mesh cell %D is inverted", c); 8391 for (i = 0; i < PetscSqr(cdim); ++i) { 8392 frobJ += J[i] * J[i]; 8393 frobInvJ += invJ[i] * invJ[i]; 8394 } 8395 cond2 = frobJ * frobInvJ; 8396 cond = PetscSqrtReal(cond2); 8397 8398 stats.min = PetscMin(stats.min,cond); 8399 stats.max = PetscMax(stats.max,cond); 8400 stats.sum += cond; 8401 stats.squaresum += cond2; 8402 stats.count++; 8403 if (output && cond > limit) { 8404 PetscSection coordSection; 8405 Vec coordsLocal; 8406 PetscScalar *coords = NULL; 8407 PetscInt Nv, d, clSize, cl, *closure = NULL; 8408 8409 ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr); 8410 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 8411 ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 8412 ierr = PetscSynchronizedPrintf(comm, "[%d] Cell %D cond %g\n", rank, c, (double) cond);CHKERRQ(ierr); 8413 for (i = 0; i < Nv/cdim; ++i) { 8414 ierr = PetscSynchronizedPrintf(comm, " Vertex %D: (", i);CHKERRQ(ierr); 8415 for (d = 0; d < cdim; ++d) { 8416 if (d > 0) {ierr = PetscSynchronizedPrintf(comm, ", ");CHKERRQ(ierr);} 8417 ierr = PetscSynchronizedPrintf(comm, "%g", (double) PetscRealPart(coords[i*cdim+d]));CHKERRQ(ierr); 8418 } 8419 ierr = PetscSynchronizedPrintf(comm, ")\n");CHKERRQ(ierr); 8420 } 8421 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 8422 for (cl = 0; cl < clSize*2; cl += 2) { 8423 const PetscInt edge = closure[cl]; 8424 8425 if ((edge >= eStart) && (edge < eEnd)) { 8426 PetscReal len; 8427 8428 ierr = DMPlexComputeCellGeometryFVM(dm, edge, &len, NULL, NULL);CHKERRQ(ierr); 8429 ierr = PetscSynchronizedPrintf(comm, " Edge %D: length %g\n", edge, (double) len);CHKERRQ(ierr); 8430 } 8431 } 8432 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure);CHKERRQ(ierr); 8433 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, &Nv, &coords);CHKERRQ(ierr); 8434 } 8435 } 8436 if (output) {ierr = PetscSynchronizedFlush(comm, NULL);CHKERRQ(ierr);} 8437 8438 if (size > 1) { 8439 PetscMPIInt blockLengths[2] = {4,1}; 8440 MPI_Aint blockOffsets[2] = {offsetof(cell_stats_t,min),offsetof(cell_stats_t,count)}; 8441 MPI_Datatype blockTypes[2] = {MPIU_REAL,MPIU_INT}, statType; 8442 MPI_Op statReduce; 8443 8444 ierr = MPI_Type_create_struct(2,blockLengths,blockOffsets,blockTypes,&statType);CHKERRMPI(ierr); 8445 ierr = MPI_Type_commit(&statType);CHKERRMPI(ierr); 8446 ierr = MPI_Op_create(cell_stats_reduce, PETSC_TRUE, &statReduce);CHKERRMPI(ierr); 8447 ierr = MPI_Reduce(&stats,&globalStats,1,statType,statReduce,0,comm);CHKERRMPI(ierr); 8448 ierr = MPI_Op_free(&statReduce);CHKERRMPI(ierr); 8449 ierr = MPI_Type_free(&statType);CHKERRMPI(ierr); 8450 } else { 8451 ierr = PetscArraycpy(&globalStats,&stats,1);CHKERRQ(ierr); 8452 } 8453 if (!rank) { 8454 count = globalStats.count; 8455 min = globalStats.min; 8456 max = globalStats.max; 8457 mean = globalStats.sum / globalStats.count; 8458 stdev = globalStats.count > 1 ? PetscSqrtReal(PetscMax((globalStats.squaresum - globalStats.count * mean * mean) / (globalStats.count - 1),0)) : 0.0; 8459 } 8460 8461 if (output) { 8462 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); 8463 } 8464 ierr = PetscFree2(J,invJ);CHKERRQ(ierr); 8465 8466 ierr = DMGetCoarseDM(dm,&dmCoarse);CHKERRQ(ierr); 8467 if (dmCoarse) { 8468 PetscBool isplex; 8469 8470 ierr = PetscObjectTypeCompare((PetscObject)dmCoarse,DMPLEX,&isplex);CHKERRQ(ierr); 8471 if (isplex) { 8472 ierr = DMPlexCheckCellShape(dmCoarse,output,condLimit);CHKERRQ(ierr); 8473 } 8474 } 8475 PetscFunctionReturn(0); 8476 } 8477 8478 /*@ 8479 DMPlexComputeOrthogonalQuality - Compute cell-wise orthogonal quality mesh statistic. Optionally tags all cells with 8480 orthogonal quality below given tolerance. 8481 8482 Collective on dm 8483 8484 Input Parameters: 8485 + dm - The DMPlex object 8486 . fv - Optional PetscFV object for pre-computed cell/face centroid information 8487 - atol - [0, 1] Absolute tolerance for tagging cells. 8488 8489 Output Parameters: 8490 + OrthQual - Vec containing orthogonal quality per cell 8491 - OrthQualLabel - DMLabel tagging cells below atol with DM_ADAPT_REFINE 8492 8493 Options Database Keys: 8494 + -dm_plex_orthogonal_quality_label_view - view OrthQualLabel if label is requested. Currently only PETSCVIEWERASCII is 8495 supported. 8496 - -dm_plex_orthogonal_quality_vec_view - view OrthQual vector. 8497 8498 Notes: 8499 Orthogonal quality is given by the following formula: 8500 8501 \min \left[ \frac{A_i \cdot f_i}{\|A_i\| \|f_i\|} , \frac{A_i \cdot c_i}{\|A_i\| \|c_i\|} \right] 8502 8503 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 8504 is the vector from the current cells centroid to the centroid of its i'th neighbor (which shares a face with the 8505 current cell). This computes the vector similarity between each cell face and its corresponding neighbor centroid by 8506 calculating the cosine of the angle between these vectors. 8507 8508 Orthogonal quality ranges from 1 (best) to 0 (worst). 8509 8510 This routine is mainly useful for FVM, however is not restricted to only FVM. The PetscFV object is optionally used to check for 8511 pre-computed FVM cell data, but if it is not passed in then this data will be computed. 8512 8513 Cells are tagged if they have an orthogonal quality less than or equal to the absolute tolerance. 8514 8515 Level: intermediate 8516 8517 .seealso: DMPlexCheckCellShape(), DMCreateLabel() 8518 @*/ 8519 PetscErrorCode DMPlexComputeOrthogonalQuality(DM dm, PetscFV fv, PetscReal atol, Vec *OrthQual, DMLabel *OrthQualLabel) 8520 { 8521 PetscInt nc, cellHeight, cStart, cEnd, cell, cellIter = 0; 8522 PetscInt *idx; 8523 PetscScalar *oqVals; 8524 const PetscScalar *cellGeomArr, *faceGeomArr; 8525 PetscReal *ci, *fi, *Ai; 8526 MPI_Comm comm; 8527 Vec cellgeom, facegeom; 8528 DM dmFace, dmCell; 8529 IS glob; 8530 ISLocalToGlobalMapping ltog; 8531 PetscViewer vwr; 8532 PetscErrorCode ierr; 8533 8534 PetscFunctionBegin; 8535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8536 if (fv) {PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);} 8537 PetscValidPointer(OrthQual, 4); 8538 if (PetscUnlikelyDebug(atol < 0.0 || atol > 1.0)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Absolute tolerance %g not in [0,1]",(double)atol); 8539 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 8540 ierr = DMGetDimension(dm, &nc);CHKERRQ(ierr); 8541 if (nc < 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must have dimension >= 2 (current %D)", nc); 8542 { 8543 DMPlexInterpolatedFlag interpFlag; 8544 8545 ierr = DMPlexIsInterpolated(dm, &interpFlag);CHKERRQ(ierr); 8546 if (interpFlag != DMPLEX_INTERPOLATED_FULL) { 8547 PetscMPIInt rank; 8548 8549 ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr); 8550 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM must be fully interpolated, DM on rank %d is not fully interpolated", rank); 8551 } 8552 } 8553 if (OrthQualLabel) { 8554 PetscValidPointer(OrthQualLabel, 5); 8555 ierr = DMCreateLabel(dm, "Orthogonal_Quality");CHKERRQ(ierr); 8556 ierr = DMGetLabel(dm, "Orthogonal_Quality", OrthQualLabel);CHKERRQ(ierr); 8557 } else {*OrthQualLabel = NULL;} 8558 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 8559 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 8560 ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &glob);CHKERRQ(ierr); 8561 ierr = ISLocalToGlobalMappingCreateIS(glob, <og);CHKERRQ(ierr); 8562 ierr = ISLocalToGlobalMappingSetType(ltog, ISLOCALTOGLOBALMAPPINGHASH);CHKERRQ(ierr); 8563 ierr = VecCreate(comm, OrthQual);CHKERRQ(ierr); 8564 ierr = VecSetType(*OrthQual, VECSTANDARD);CHKERRQ(ierr); 8565 ierr = VecSetSizes(*OrthQual, cEnd-cStart, PETSC_DETERMINE);CHKERRQ(ierr); 8566 ierr = VecSetLocalToGlobalMapping(*OrthQual, ltog);CHKERRQ(ierr); 8567 ierr = VecSetUp(*OrthQual);CHKERRQ(ierr); 8568 ierr = ISDestroy(&glob);CHKERRQ(ierr); 8569 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 8570 ierr = DMPlexGetDataFVM(dm, fv, &cellgeom, &facegeom, NULL);CHKERRQ(ierr); 8571 ierr = VecGetArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr); 8572 ierr = VecGetArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr); 8573 ierr = VecGetDM(cellgeom, &dmCell);CHKERRQ(ierr); 8574 ierr = VecGetDM(facegeom, &dmFace);CHKERRQ(ierr); 8575 ierr = PetscMalloc5(cEnd-cStart, &idx, cEnd-cStart, &oqVals, nc, &ci, nc, &fi, nc, &Ai);CHKERRQ(ierr); 8576 for (cell = cStart; cell < cEnd; cellIter++,cell++) { 8577 PetscInt cellneigh, cellneighiter = 0, adjSize = PETSC_DETERMINE; 8578 PetscInt cellarr[2], *adj = NULL; 8579 PetscScalar *cArr, *fArr; 8580 PetscReal minvalc = 1.0, minvalf = 1.0; 8581 PetscFVCellGeom *cg; 8582 8583 idx[cellIter] = cell-cStart; 8584 cellarr[0] = cell; 8585 /* Make indexing into cellGeom easier */ 8586 ierr = DMPlexPointLocalRead(dmCell, cell, cellGeomArr, &cg);CHKERRQ(ierr); 8587 ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &adjSize, &adj);CHKERRQ(ierr); 8588 /* Technically 1 too big, but easier than fiddling with empty adjacency array */ 8589 ierr = PetscCalloc2(adjSize, &cArr, adjSize, &fArr);CHKERRQ(ierr); 8590 for (cellneigh = 0; cellneigh < adjSize; cellneighiter++,cellneigh++) { 8591 PetscInt i; 8592 const PetscInt neigh = adj[cellneigh]; 8593 PetscReal normci = 0, normfi = 0, normai = 0; 8594 PetscFVCellGeom *cgneigh; 8595 PetscFVFaceGeom *fg; 8596 8597 /* Don't count ourselves in the neighbor list */ 8598 if (neigh == cell) continue; 8599 ierr = DMPlexPointLocalRead(dmCell, neigh, cellGeomArr, &cgneigh);CHKERRQ(ierr); 8600 cellarr[1] = neigh; 8601 { 8602 PetscInt numcovpts; 8603 const PetscInt *covpts; 8604 8605 ierr = DMPlexGetMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr); 8606 ierr = DMPlexPointLocalRead(dmFace, covpts[0], faceGeomArr, &fg);CHKERRQ(ierr); 8607 ierr = DMPlexRestoreMeet(dm, 2, cellarr, &numcovpts, &covpts);CHKERRQ(ierr); 8608 } 8609 8610 /* Compute c_i, f_i and their norms */ 8611 for (i = 0; i < nc; i++) { 8612 ci[i] = cgneigh->centroid[i] - cg->centroid[i]; 8613 fi[i] = fg->centroid[i] - cg->centroid[i]; 8614 Ai[i] = fg->normal[i]; 8615 normci += PetscPowReal(ci[i], 2); 8616 normfi += PetscPowReal(fi[i], 2); 8617 normai += PetscPowReal(Ai[i], 2); 8618 } 8619 normci = PetscSqrtReal(normci); 8620 normfi = PetscSqrtReal(normfi); 8621 normai = PetscSqrtReal(normai); 8622 8623 /* Normalize and compute for each face-cell-normal pair */ 8624 for (i = 0; i < nc; i++) { 8625 ci[i] = ci[i]/normci; 8626 fi[i] = fi[i]/normfi; 8627 Ai[i] = Ai[i]/normai; 8628 /* PetscAbs because I don't know if normals are guaranteed to point out */ 8629 cArr[cellneighiter] += PetscAbs(Ai[i]*ci[i]); 8630 fArr[cellneighiter] += PetscAbs(Ai[i]*fi[i]); 8631 } 8632 if (PetscRealPart(cArr[cellneighiter]) < minvalc) { 8633 minvalc = PetscRealPart(cArr[cellneighiter]); 8634 } 8635 if (PetscRealPart(fArr[cellneighiter]) < minvalf) { 8636 minvalf = PetscRealPart(fArr[cellneighiter]); 8637 } 8638 } 8639 ierr = PetscFree(adj);CHKERRQ(ierr); 8640 ierr = PetscFree2(cArr, fArr);CHKERRQ(ierr); 8641 /* Defer to cell if they're equal */ 8642 oqVals[cellIter] = PetscMin(minvalf, minvalc); 8643 if (OrthQualLabel) { 8644 if (PetscRealPart(oqVals[cellIter]) <= atol) {ierr = DMLabelSetValue(*OrthQualLabel, cell, DM_ADAPT_REFINE);CHKERRQ(ierr);} 8645 } 8646 } 8647 ierr = VecSetValuesLocal(*OrthQual, cEnd-cStart, idx, oqVals, INSERT_VALUES);CHKERRQ(ierr); 8648 ierr = VecAssemblyBegin(*OrthQual);CHKERRQ(ierr); 8649 ierr = VecAssemblyEnd(*OrthQual);CHKERRQ(ierr); 8650 ierr = VecRestoreArrayRead(cellgeom, &cellGeomArr);CHKERRQ(ierr); 8651 ierr = VecRestoreArrayRead(facegeom, &faceGeomArr);CHKERRQ(ierr); 8652 ierr = PetscOptionsGetViewer(comm, NULL, NULL, "-dm_plex_orthogonal_quality_label_view", &vwr, NULL, NULL);CHKERRQ(ierr); 8653 if (OrthQualLabel) { 8654 if (vwr) {ierr = DMLabelView(*OrthQualLabel, vwr);CHKERRQ(ierr);} 8655 } 8656 ierr = PetscFree5(idx, oqVals, ci, fi, Ai);CHKERRQ(ierr); 8657 ierr = PetscViewerDestroy(&vwr);CHKERRQ(ierr); 8658 ierr = VecViewFromOptions(*OrthQual, NULL, "-dm_plex_orthogonal_quality_vec_view");CHKERRQ(ierr); 8659 PetscFunctionReturn(0); 8660 } 8661 8662 /* this is here insead of DMGetOutputDM because output DM still has constraints in the local indices that affect 8663 * interpolator construction */ 8664 static PetscErrorCode DMGetFullDM(DM dm, DM *odm) 8665 { 8666 PetscSection section, newSection, gsection; 8667 PetscSF sf; 8668 PetscBool hasConstraints, ghasConstraints; 8669 PetscErrorCode ierr; 8670 8671 PetscFunctionBegin; 8672 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 8673 PetscValidPointer(odm,2); 8674 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 8675 ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr); 8676 ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRMPI(ierr); 8677 if (!ghasConstraints) { 8678 ierr = PetscObjectReference((PetscObject)dm);CHKERRQ(ierr); 8679 *odm = dm; 8680 PetscFunctionReturn(0); 8681 } 8682 ierr = DMClone(dm, odm);CHKERRQ(ierr); 8683 ierr = DMCopyFields(dm, *odm);CHKERRQ(ierr); 8684 ierr = DMGetLocalSection(*odm, &newSection);CHKERRQ(ierr); 8685 ierr = DMGetPointSF(*odm, &sf);CHKERRQ(ierr); 8686 ierr = PetscSectionCreateGlobalSection(newSection, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr); 8687 ierr = DMSetGlobalSection(*odm, gsection);CHKERRQ(ierr); 8688 ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr); 8689 PetscFunctionReturn(0); 8690 } 8691 8692 static PetscErrorCode DMCreateAffineInterpolationCorrection_Plex(DM dmc, DM dmf, Vec *shift) 8693 { 8694 DM dmco, dmfo; 8695 Mat interpo; 8696 Vec rscale; 8697 Vec cglobalo, clocal; 8698 Vec fglobal, fglobalo, flocal; 8699 PetscBool regular; 8700 PetscErrorCode ierr; 8701 8702 PetscFunctionBegin; 8703 ierr = DMGetFullDM(dmc, &dmco);CHKERRQ(ierr); 8704 ierr = DMGetFullDM(dmf, &dmfo);CHKERRQ(ierr); 8705 ierr = DMSetCoarseDM(dmfo, dmco);CHKERRQ(ierr); 8706 ierr = DMPlexGetRegularRefinement(dmf, ®ular);CHKERRQ(ierr); 8707 ierr = DMPlexSetRegularRefinement(dmfo, regular);CHKERRQ(ierr); 8708 ierr = DMCreateInterpolation(dmco, dmfo, &interpo, &rscale);CHKERRQ(ierr); 8709 ierr = DMCreateGlobalVector(dmco, &cglobalo);CHKERRQ(ierr); 8710 ierr = DMCreateLocalVector(dmc, &clocal);CHKERRQ(ierr); 8711 ierr = VecSet(cglobalo, 0.);CHKERRQ(ierr); 8712 ierr = VecSet(clocal, 0.);CHKERRQ(ierr); 8713 ierr = DMCreateGlobalVector(dmf, &fglobal);CHKERRQ(ierr); 8714 ierr = DMCreateGlobalVector(dmfo, &fglobalo);CHKERRQ(ierr); 8715 ierr = DMCreateLocalVector(dmf, &flocal);CHKERRQ(ierr); 8716 ierr = VecSet(fglobal, 0.);CHKERRQ(ierr); 8717 ierr = VecSet(fglobalo, 0.);CHKERRQ(ierr); 8718 ierr = VecSet(flocal, 0.);CHKERRQ(ierr); 8719 ierr = DMPlexInsertBoundaryValues(dmc, PETSC_TRUE, clocal, 0., NULL, NULL, NULL);CHKERRQ(ierr); 8720 ierr = DMLocalToGlobalBegin(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr); 8721 ierr = DMLocalToGlobalEnd(dmco, clocal, INSERT_VALUES, cglobalo);CHKERRQ(ierr); 8722 ierr = MatMult(interpo, cglobalo, fglobalo);CHKERRQ(ierr); 8723 ierr = DMGlobalToLocalBegin(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr); 8724 ierr = DMGlobalToLocalEnd(dmfo, fglobalo, INSERT_VALUES, flocal);CHKERRQ(ierr); 8725 ierr = DMLocalToGlobalBegin(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr); 8726 ierr = DMLocalToGlobalEnd(dmf, flocal, INSERT_VALUES, fglobal);CHKERRQ(ierr); 8727 *shift = fglobal; 8728 ierr = VecDestroy(&flocal);CHKERRQ(ierr); 8729 ierr = VecDestroy(&fglobalo);CHKERRQ(ierr); 8730 ierr = VecDestroy(&clocal);CHKERRQ(ierr); 8731 ierr = VecDestroy(&cglobalo);CHKERRQ(ierr); 8732 ierr = VecDestroy(&rscale);CHKERRQ(ierr); 8733 ierr = MatDestroy(&interpo);CHKERRQ(ierr); 8734 ierr = DMDestroy(&dmfo);CHKERRQ(ierr); 8735 ierr = DMDestroy(&dmco);CHKERRQ(ierr); 8736 PetscFunctionReturn(0); 8737 } 8738 8739 PETSC_INTERN PetscErrorCode DMInterpolateSolution_Plex(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 8740 { 8741 PetscObject shifto; 8742 Vec shift; 8743 8744 PetscErrorCode ierr; 8745 8746 PetscFunctionBegin; 8747 if (!interp) { 8748 Vec rscale; 8749 8750 ierr = DMCreateInterpolation(coarse, fine, &interp, &rscale);CHKERRQ(ierr); 8751 ierr = VecDestroy(&rscale);CHKERRQ(ierr); 8752 } else { 8753 ierr = PetscObjectReference((PetscObject)interp);CHKERRQ(ierr); 8754 } 8755 ierr = PetscObjectQuery((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", &shifto);CHKERRQ(ierr); 8756 if (!shifto) { 8757 ierr = DMCreateAffineInterpolationCorrection_Plex(coarse, fine, &shift);CHKERRQ(ierr); 8758 ierr = PetscObjectCompose((PetscObject)interp, "_DMInterpolateSolution_Plex_Vec", (PetscObject) shift);CHKERRQ(ierr); 8759 shifto = (PetscObject) shift; 8760 ierr = VecDestroy(&shift);CHKERRQ(ierr); 8761 } 8762 shift = (Vec) shifto; 8763 ierr = MatInterpolate(interp, coarseSol, fineSol);CHKERRQ(ierr); 8764 ierr = VecAXPY(fineSol, 1.0, shift);CHKERRQ(ierr); 8765 ierr = MatDestroy(&interp);CHKERRQ(ierr); 8766 PetscFunctionReturn(0); 8767 } 8768 8769 /* Pointwise interpolation 8770 Just code FEM for now 8771 u^f = I u^c 8772 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 8773 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 8774 I_{ij} = psi^f_i phi^c_j 8775 */ 8776 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 8777 { 8778 PetscSection gsc, gsf; 8779 PetscInt m, n; 8780 void *ctx; 8781 DM cdm; 8782 PetscBool regular, ismatis, isRefined = dmCoarse->data == dmFine->data ? PETSC_FALSE : PETSC_TRUE; 8783 PetscErrorCode ierr; 8784 8785 PetscFunctionBegin; 8786 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 8787 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 8788 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 8789 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 8790 8791 ierr = PetscStrcmp(dmCoarse->mattype, MATIS, &ismatis);CHKERRQ(ierr); 8792 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr); 8793 ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 8794 ierr = MatSetType(*interpolation, ismatis ? MATAIJ : dmCoarse->mattype);CHKERRQ(ierr); 8795 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 8796 8797 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 8798 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 8799 if (!isRefined || (regular && cdm == dmCoarse)) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, isRefined, *interpolation, ctx);CHKERRQ(ierr);} 8800 else {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 8801 ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr); 8802 if (scaling) { 8803 /* Use naive scaling */ 8804 ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr); 8805 } 8806 PetscFunctionReturn(0); 8807 } 8808 8809 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 8810 { 8811 PetscErrorCode ierr; 8812 VecScatter ctx; 8813 8814 PetscFunctionBegin; 8815 ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr); 8816 ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr); 8817 ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr); 8818 PetscFunctionReturn(0); 8819 } 8820 8821 static void g0_identity_private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8822 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8823 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8824 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 8825 { 8826 g0[0] = 1.0; 8827 } 8828 8829 PetscErrorCode DMCreateMassMatrix_Plex(DM dmCoarse, DM dmFine, Mat *mass) 8830 { 8831 PetscSection gsc, gsf; 8832 PetscInt m, n; 8833 void *ctx; 8834 DM cdm; 8835 PetscBool regular; 8836 PetscErrorCode ierr; 8837 8838 PetscFunctionBegin; 8839 if (dmFine == dmCoarse) { 8840 DM dmc; 8841 PetscDS ds; 8842 Vec u; 8843 IS cellIS; 8844 PetscFormKey key; 8845 PetscInt depth; 8846 8847 ierr = DMClone(dmFine, &dmc);CHKERRQ(ierr); 8848 ierr = DMCopyDisc(dmFine, dmc);CHKERRQ(ierr); 8849 ierr = DMGetDS(dmc, &ds);CHKERRQ(ierr); 8850 ierr = PetscDSSetJacobian(ds, 0, 0, g0_identity_private, NULL, NULL, NULL);CHKERRQ(ierr); 8851 ierr = DMCreateMatrix(dmc, mass);CHKERRQ(ierr); 8852 ierr = DMGetGlobalVector(dmc, &u);CHKERRQ(ierr); 8853 ierr = DMPlexGetDepth(dmc, &depth);CHKERRQ(ierr); 8854 ierr = DMGetStratumIS(dmc, "depth", depth, &cellIS);CHKERRQ(ierr); 8855 ierr = MatZeroEntries(*mass);CHKERRQ(ierr); 8856 key.label = NULL; 8857 key.value = 0; 8858 key.field = 0; 8859 key.part = 0; 8860 ierr = DMPlexComputeJacobian_Internal(dmc, key, cellIS, 0.0, 0.0, u, NULL, *mass, *mass, NULL);CHKERRQ(ierr); 8861 ierr = ISDestroy(&cellIS);CHKERRQ(ierr); 8862 ierr = DMRestoreGlobalVector(dmc, &u);CHKERRQ(ierr); 8863 ierr = DMDestroy(&dmc);CHKERRQ(ierr); 8864 } else { 8865 ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 8866 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 8867 ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 8868 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 8869 8870 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), mass);CHKERRQ(ierr); 8871 ierr = MatSetSizes(*mass, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 8872 ierr = MatSetType(*mass, dmCoarse->mattype);CHKERRQ(ierr); 8873 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 8874 8875 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 8876 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 8877 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeMassMatrixNested(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 8878 else {ierr = DMPlexComputeMassMatrixGeneral(dmCoarse, dmFine, *mass, ctx);CHKERRQ(ierr);} 8879 } 8880 ierr = MatViewFromOptions(*mass, NULL, "-mass_mat_view");CHKERRQ(ierr); 8881 PetscFunctionReturn(0); 8882 } 8883 8884 /*@ 8885 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 8886 8887 Input Parameter: 8888 . dm - The DMPlex object 8889 8890 Output Parameter: 8891 . regular - The flag 8892 8893 Level: intermediate 8894 8895 .seealso: DMPlexSetRegularRefinement() 8896 @*/ 8897 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 8898 { 8899 PetscFunctionBegin; 8900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8901 PetscValidPointer(regular, 2); 8902 *regular = ((DM_Plex *) dm->data)->regularRefinement; 8903 PetscFunctionReturn(0); 8904 } 8905 8906 /*@ 8907 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 8908 8909 Input Parameters: 8910 + dm - The DMPlex object 8911 - regular - The flag 8912 8913 Level: intermediate 8914 8915 .seealso: DMPlexGetRegularRefinement() 8916 @*/ 8917 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 8918 { 8919 PetscFunctionBegin; 8920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8921 ((DM_Plex *) dm->data)->regularRefinement = regular; 8922 PetscFunctionReturn(0); 8923 } 8924 8925 /*@ 8926 DMPlexGetCellRefinerType - Get the strategy for refining a cell 8927 8928 Input Parameter: 8929 . dm - The DMPlex object 8930 8931 Output Parameter: 8932 . cr - The strategy number 8933 8934 Level: intermediate 8935 8936 .seealso: DMPlexSetCellRefinerType(), DMPlexSetRegularRefinement() 8937 @*/ 8938 PetscErrorCode DMPlexGetCellRefinerType(DM dm, DMPlexCellRefinerType *cr) 8939 { 8940 PetscFunctionBegin; 8941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8942 PetscValidPointer(cr, 2); 8943 *cr = ((DM_Plex *) dm->data)->cellRefiner; 8944 PetscFunctionReturn(0); 8945 } 8946 8947 /*@ 8948 DMPlexSetCellRefinerType - Set the strategy for refining a cell 8949 8950 Input Parameters: 8951 + dm - The DMPlex object 8952 - cr - The strategy number 8953 8954 Level: intermediate 8955 8956 .seealso: DMPlexGetCellRefinerType(), DMPlexGetRegularRefinement() 8957 @*/ 8958 PetscErrorCode DMPlexSetCellRefinerType(DM dm, DMPlexCellRefinerType cr) 8959 { 8960 PetscFunctionBegin; 8961 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8962 ((DM_Plex *) dm->data)->cellRefiner = cr; 8963 PetscFunctionReturn(0); 8964 } 8965 8966 /* anchors */ 8967 /*@ 8968 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 8969 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints(). 8970 8971 not collective 8972 8973 Input Parameters: 8974 . dm - The DMPlex object 8975 8976 Output Parameters: 8977 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 8978 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 8979 8980 Level: intermediate 8981 8982 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints() 8983 @*/ 8984 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 8985 { 8986 DM_Plex *plex = (DM_Plex *)dm->data; 8987 PetscErrorCode ierr; 8988 8989 PetscFunctionBegin; 8990 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8991 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);} 8992 if (anchorSection) *anchorSection = plex->anchorSection; 8993 if (anchorIS) *anchorIS = plex->anchorIS; 8994 PetscFunctionReturn(0); 8995 } 8996 8997 /*@ 8998 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 8999 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 9000 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 9001 9002 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 9003 DMGetConstraints() and filling in the entries in the constraint matrix. 9004 9005 collective on dm 9006 9007 Input Parameters: 9008 + dm - The DMPlex object 9009 . 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). 9010 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 9011 9012 The reference counts of anchorSection and anchorIS are incremented. 9013 9014 Level: intermediate 9015 9016 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints() 9017 @*/ 9018 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 9019 { 9020 DM_Plex *plex = (DM_Plex *)dm->data; 9021 PetscMPIInt result; 9022 PetscErrorCode ierr; 9023 9024 PetscFunctionBegin; 9025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9026 if (anchorSection) { 9027 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 9028 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRMPI(ierr); 9029 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 9030 } 9031 if (anchorIS) { 9032 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 9033 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRMPI(ierr); 9034 if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 9035 } 9036 9037 ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr); 9038 ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr); 9039 plex->anchorSection = anchorSection; 9040 9041 ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr); 9042 ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr); 9043 plex->anchorIS = anchorIS; 9044 9045 if (PetscUnlikelyDebug(anchorIS && anchorSection)) { 9046 PetscInt size, a, pStart, pEnd; 9047 const PetscInt *anchors; 9048 9049 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 9050 ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr); 9051 ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr); 9052 for (a = 0; a < size; a++) { 9053 PetscInt p; 9054 9055 p = anchors[a]; 9056 if (p >= pStart && p < pEnd) { 9057 PetscInt dof; 9058 9059 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 9060 if (dof) { 9061 PetscErrorCode ierr2; 9062 9063 ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2); 9064 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %D cannot be constrained and an anchor",p); 9065 } 9066 } 9067 } 9068 ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr); 9069 } 9070 /* reset the generic constraints */ 9071 ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr); 9072 PetscFunctionReturn(0); 9073 } 9074 9075 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 9076 { 9077 PetscSection anchorSection; 9078 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 9079 PetscErrorCode ierr; 9080 9081 PetscFunctionBegin; 9082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9083 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 9084 ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr); 9085 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 9086 if (numFields) { 9087 PetscInt f; 9088 ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr); 9089 9090 for (f = 0; f < numFields; f++) { 9091 PetscInt numComp; 9092 9093 ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr); 9094 ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr); 9095 } 9096 } 9097 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 9098 ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr); 9099 pStart = PetscMax(pStart,sStart); 9100 pEnd = PetscMin(pEnd,sEnd); 9101 pEnd = PetscMax(pStart,pEnd); 9102 ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr); 9103 for (p = pStart; p < pEnd; p++) { 9104 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 9105 if (dof) { 9106 ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); 9107 ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr); 9108 for (f = 0; f < numFields; f++) { 9109 ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); 9110 ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr); 9111 } 9112 } 9113 } 9114 ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr); 9115 ierr = PetscObjectSetName((PetscObject) *cSec, "Constraint Section");CHKERRQ(ierr); 9116 PetscFunctionReturn(0); 9117 } 9118 9119 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 9120 { 9121 PetscSection aSec; 9122 PetscInt pStart, pEnd, p, sStart, sEnd, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 9123 const PetscInt *anchors; 9124 PetscInt numFields, f; 9125 IS aIS; 9126 PetscErrorCode ierr; 9127 MatType mtype; 9128 PetscBool iscuda,iskokkos; 9129 9130 PetscFunctionBegin; 9131 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9132 ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr); 9133 ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr); 9134 ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr); 9135 ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr); 9136 ierr = PetscStrcmp(dm->mattype,MATSEQAIJCUSPARSE,&iscuda);CHKERRQ(ierr); 9137 if (!iscuda) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJCUSPARSE,&iscuda);CHKERRQ(ierr); } 9138 ierr = PetscStrcmp(dm->mattype,MATSEQAIJKOKKOS,&iskokkos);CHKERRQ(ierr); 9139 if (!iskokkos) { ierr = PetscStrcmp(dm->mattype,MATMPIAIJKOKKOS,&iskokkos);CHKERRQ(ierr); } 9140 if (iscuda) mtype = MATSEQAIJCUSPARSE; 9141 else if (iskokkos) mtype = MATSEQAIJKOKKOS; 9142 else mtype = MATSEQAIJ; 9143 ierr = MatSetType(*cMat,mtype);CHKERRQ(ierr); 9144 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 9145 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 9146 /* cSec will be a subset of aSec and section */ 9147 ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr); 9148 ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr); 9149 ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr); 9150 i[0] = 0; 9151 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 9152 for (p = pStart; p < pEnd; p++) { 9153 PetscInt rDof, rOff, r; 9154 9155 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 9156 if (!rDof) continue; 9157 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 9158 if (numFields) { 9159 for (f = 0; f < numFields; f++) { 9160 annz = 0; 9161 for (r = 0; r < rDof; r++) { 9162 a = anchors[rOff + r]; 9163 if (a < sStart || a >= sEnd) continue; 9164 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 9165 annz += aDof; 9166 } 9167 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 9168 ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr); 9169 for (q = 0; q < dof; q++) { 9170 i[off + q + 1] = i[off + q] + annz; 9171 } 9172 } 9173 } 9174 else { 9175 annz = 0; 9176 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 9177 for (q = 0; q < dof; q++) { 9178 a = anchors[rOff + q]; 9179 if (a < sStart || a >= sEnd) continue; 9180 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 9181 annz += aDof; 9182 } 9183 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 9184 ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr); 9185 for (q = 0; q < dof; q++) { 9186 i[off + q + 1] = i[off + q] + annz; 9187 } 9188 } 9189 } 9190 nnz = i[m]; 9191 ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr); 9192 offset = 0; 9193 for (p = pStart; p < pEnd; p++) { 9194 if (numFields) { 9195 for (f = 0; f < numFields; f++) { 9196 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 9197 for (q = 0; q < dof; q++) { 9198 PetscInt rDof, rOff, r; 9199 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 9200 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 9201 for (r = 0; r < rDof; r++) { 9202 PetscInt s; 9203 9204 a = anchors[rOff + r]; 9205 if (a < sStart || a >= sEnd) continue; 9206 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 9207 ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr); 9208 for (s = 0; s < aDof; s++) { 9209 j[offset++] = aOff + s; 9210 } 9211 } 9212 } 9213 } 9214 } 9215 else { 9216 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 9217 for (q = 0; q < dof; q++) { 9218 PetscInt rDof, rOff, r; 9219 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 9220 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 9221 for (r = 0; r < rDof; r++) { 9222 PetscInt s; 9223 9224 a = anchors[rOff + r]; 9225 if (a < sStart || a >= sEnd) continue; 9226 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 9227 ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr); 9228 for (s = 0; s < aDof; s++) { 9229 j[offset++] = aOff + s; 9230 } 9231 } 9232 } 9233 } 9234 } 9235 ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr); 9236 ierr = PetscFree(i);CHKERRQ(ierr); 9237 ierr = PetscFree(j);CHKERRQ(ierr); 9238 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 9239 PetscFunctionReturn(0); 9240 } 9241 9242 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 9243 { 9244 DM_Plex *plex = (DM_Plex *)dm->data; 9245 PetscSection anchorSection, section, cSec; 9246 Mat cMat; 9247 PetscErrorCode ierr; 9248 9249 PetscFunctionBegin; 9250 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9251 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 9252 if (anchorSection) { 9253 PetscInt Nf; 9254 9255 ierr = DMGetLocalSection(dm,§ion);CHKERRQ(ierr); 9256 ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr); 9257 ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr); 9258 ierr = DMGetNumFields(dm,&Nf);CHKERRQ(ierr); 9259 if (Nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);} 9260 ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr); 9261 ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr); 9262 ierr = MatDestroy(&cMat);CHKERRQ(ierr); 9263 } 9264 PetscFunctionReturn(0); 9265 } 9266 9267 PetscErrorCode DMCreateSubDomainDM_Plex(DM dm, DMLabel label, PetscInt value, IS *is, DM *subdm) 9268 { 9269 IS subis; 9270 PetscSection section, subsection; 9271 PetscErrorCode ierr; 9272 9273 PetscFunctionBegin; 9274 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 9275 if (!section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set default section for DM before splitting subdomain"); 9276 if (!subdm) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Must set output subDM for splitting subdomain"); 9277 /* Create subdomain */ 9278 ierr = DMPlexFilter(dm, label, value, subdm);CHKERRQ(ierr); 9279 /* Create submodel */ 9280 ierr = DMPlexGetSubpointIS(*subdm, &subis);CHKERRQ(ierr); 9281 ierr = PetscSectionCreateSubmeshSection(section, subis, &subsection);CHKERRQ(ierr); 9282 ierr = DMSetLocalSection(*subdm, subsection);CHKERRQ(ierr); 9283 ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr); 9284 ierr = DMCopyDisc(dm, *subdm);CHKERRQ(ierr); 9285 /* Create map from submodel to global model */ 9286 if (is) { 9287 PetscSection sectionGlobal, subsectionGlobal; 9288 IS spIS; 9289 const PetscInt *spmap; 9290 PetscInt *subIndices; 9291 PetscInt subSize = 0, subOff = 0, pStart, pEnd, p; 9292 PetscInt Nf, f, bs = -1, bsLocal[2], bsMinMax[2]; 9293 9294 ierr = DMPlexGetSubpointIS(*subdm, &spIS);CHKERRQ(ierr); 9295 ierr = ISGetIndices(spIS, &spmap);CHKERRQ(ierr); 9296 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 9297 ierr = DMGetGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 9298 ierr = DMGetGlobalSection(*subdm, &subsectionGlobal);CHKERRQ(ierr); 9299 ierr = PetscSectionGetChart(subsection, &pStart, &pEnd);CHKERRQ(ierr); 9300 for (p = pStart; p < pEnd; ++p) { 9301 PetscInt gdof, pSubSize = 0; 9302 9303 ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr); 9304 if (gdof > 0) { 9305 for (f = 0; f < Nf; ++f) { 9306 PetscInt fdof, fcdof; 9307 9308 ierr = PetscSectionGetFieldDof(subsection, p, f, &fdof);CHKERRQ(ierr); 9309 ierr = PetscSectionGetFieldConstraintDof(subsection, p, f, &fcdof);CHKERRQ(ierr); 9310 pSubSize += fdof-fcdof; 9311 } 9312 subSize += pSubSize; 9313 if (pSubSize) { 9314 if (bs < 0) { 9315 bs = pSubSize; 9316 } else if (bs != pSubSize) { 9317 /* Layout does not admit a pointwise block size */ 9318 bs = 1; 9319 } 9320 } 9321 } 9322 } 9323 /* Must have same blocksize on all procs (some might have no points) */ 9324 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs; 9325 ierr = PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);CHKERRQ(ierr); 9326 if (bsMinMax[0] != bsMinMax[1]) {bs = 1;} 9327 else {bs = bsMinMax[0];} 9328 ierr = PetscMalloc1(subSize, &subIndices);CHKERRQ(ierr); 9329 for (p = pStart; p < pEnd; ++p) { 9330 PetscInt gdof, goff; 9331 9332 ierr = PetscSectionGetDof(subsectionGlobal, p, &gdof);CHKERRQ(ierr); 9333 if (gdof > 0) { 9334 const PetscInt point = spmap[p]; 9335 9336 ierr = PetscSectionGetOffset(sectionGlobal, point, &goff);CHKERRQ(ierr); 9337 for (f = 0; f < Nf; ++f) { 9338 PetscInt fdof, fcdof, fc, f2, poff = 0; 9339 9340 /* Can get rid of this loop by storing field information in the global section */ 9341 for (f2 = 0; f2 < f; ++f2) { 9342 ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr); 9343 ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr); 9344 poff += fdof-fcdof; 9345 } 9346 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 9347 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 9348 for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) { 9349 subIndices[subOff] = goff+poff+fc; 9350 } 9351 } 9352 } 9353 } 9354 ierr = ISRestoreIndices(spIS, &spmap);CHKERRQ(ierr); 9355 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr); 9356 if (bs > 1) { 9357 /* We need to check that the block size does not come from non-contiguous fields */ 9358 PetscInt i, j, set = 1; 9359 for (i = 0; i < subSize; i += bs) { 9360 for (j = 0; j < bs; ++j) { 9361 if (subIndices[i+j] != subIndices[i]+j) {set = 0; break;} 9362 } 9363 } 9364 if (set) {ierr = ISSetBlockSize(*is, bs);CHKERRQ(ierr);} 9365 } 9366 /* Attach nullspace */ 9367 for (f = 0; f < Nf; ++f) { 9368 (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[f]; 9369 if ((*subdm)->nullspaceConstructors[f]) break; 9370 } 9371 if (f < Nf) { 9372 MatNullSpace nullSpace; 9373 ierr = (*(*subdm)->nullspaceConstructors[f])(*subdm, f, f, &nullSpace);CHKERRQ(ierr); 9374 9375 ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr); 9376 ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr); 9377 } 9378 } 9379 PetscFunctionReturn(0); 9380 } 9381 9382 /*@ 9383 DMPlexMonitorThroughput - Report the cell throughput of FE integration 9384 9385 Input Parameter: 9386 - dm - The DM 9387 9388 Level: developer 9389 9390 Options Database Keys: 9391 . -dm_plex_monitor_throughput - Activate the monitor 9392 9393 .seealso: DMSetFromOptions(), DMPlexCreate() 9394 @*/ 9395 PetscErrorCode DMPlexMonitorThroughput(DM dm, void *dummy) 9396 { 9397 #if defined(PETSC_USE_LOG) 9398 PetscStageLog stageLog; 9399 PetscLogEvent event; 9400 PetscLogStage stage; 9401 PetscEventPerfInfo eventInfo; 9402 PetscReal cellRate, flopRate; 9403 PetscInt cStart, cEnd, Nf, N; 9404 const char *name; 9405 PetscErrorCode ierr; 9406 #endif 9407 9408 PetscFunctionBegin; 9409 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9410 #if defined(PETSC_USE_LOG) 9411 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 9412 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 9413 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 9414 ierr = PetscLogGetStageLog(&stageLog);CHKERRQ(ierr); 9415 ierr = PetscStageLogGetCurrent(stageLog, &stage);CHKERRQ(ierr); 9416 ierr = PetscLogEventGetId("DMPlexResidualFE", &event);CHKERRQ(ierr); 9417 ierr = PetscLogEventGetPerfInfo(stage, event, &eventInfo);CHKERRQ(ierr); 9418 N = (cEnd - cStart)*Nf*eventInfo.count; 9419 flopRate = eventInfo.flops/eventInfo.time; 9420 cellRate = N/eventInfo.time; 9421 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); 9422 #else 9423 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Plex Throughput Monitor is not supported if logging is turned off. Reconfigure using --with-log."); 9424 #endif 9425 PetscFunctionReturn(0); 9426 } 9427