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