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