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