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