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