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