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