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