1 #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <../src/sys/utils/hash.h> 3 #include <petsc-private/isimpl.h> 4 #include <petscsf.h> 5 6 /* Logging support */ 7 PetscLogEvent DMPLEX_Interpolate, DMPLEX_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM; 8 9 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer); 10 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 11 PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer); 12 13 #undef __FUNCT__ 14 #define __FUNCT__ "DMPlexGetFieldType_Internal" 15 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 16 { 17 PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, vdof = 0, cdof = 0; 18 PetscErrorCode ierr; 19 20 PetscFunctionBegin; 21 *ft = PETSC_VTK_POINT_FIELD; 22 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 23 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 24 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 25 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 26 if (field >= 0) { 27 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vdof);CHKERRQ(ierr);} 28 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &cdof);CHKERRQ(ierr);} 29 } else { 30 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);} 31 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);} 32 } 33 if (vdof) { 34 *sStart = vStart; 35 *sEnd = vEnd; 36 if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 37 else *ft = PETSC_VTK_POINT_FIELD; 38 } else if (cdof) { 39 *sStart = cStart; 40 *sEnd = cEnd; 41 if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 42 else *ft = PETSC_VTK_CELL_FIELD; 43 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK"); 44 PetscFunctionReturn(0); 45 } 46 47 #undef __FUNCT__ 48 #define __FUNCT__ "VecView_Plex_Local" 49 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 50 { 51 DM dm; 52 PetscBool isvtk, ishdf5, isseq; 53 PetscErrorCode ierr; 54 55 PetscFunctionBegin; 56 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 57 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 58 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 59 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 60 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 61 if (isvtk || ishdf5) { 62 PetscInt numFields; 63 PetscBool fem = PETSC_FALSE; 64 65 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 66 if (numFields) { 67 PetscObject fe; 68 69 ierr = DMGetField(dm, 0, &fe);CHKERRQ(ierr); 70 if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE; 71 } 72 if (fem) { 73 ierr = DMPlexInsertBoundaryValuesFEM(dm, v);CHKERRQ(ierr); 74 } else { 75 PetscObject faceGeometry; 76 77 /* TODO Fix the time, and add FVM objects */ 78 ierr = PetscObjectQuery((PetscObject) dm, "FaceGeometry", &faceGeometry);CHKERRQ(ierr); 79 if (faceGeometry) {ierr = DMPlexInsertBoundaryValuesFVM(dm, 0.0, v);CHKERRQ(ierr);} 80 } 81 } 82 if (isvtk) { 83 PetscSection section; 84 PetscViewerVTKFieldType ft; 85 PetscInt pStart, pEnd; 86 87 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 88 ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr); 89 ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */ 90 ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr); /* viewer drops reference */ 91 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr); 92 } else if (ishdf5) { 93 #if defined(PETSC_HAVE_HDF5) 94 ierr = VecView_Plex_Local_HDF5(v, viewer);CHKERRQ(ierr); 95 #else 96 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 97 #endif 98 } else { 99 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 100 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 101 } 102 PetscFunctionReturn(0); 103 } 104 105 #undef __FUNCT__ 106 #define __FUNCT__ "VecView_Plex" 107 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 108 { 109 DM dm; 110 PetscBool isvtk, ishdf5, isseq; 111 PetscErrorCode ierr; 112 113 PetscFunctionBegin; 114 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 115 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 116 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 117 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 118 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 119 if (isvtk) { 120 Vec locv; 121 const char *name; 122 123 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 124 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 125 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 126 ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 127 ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 128 ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr); 129 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 130 } else if (ishdf5) { 131 #if defined(PETSC_HAVE_HDF5) 132 ierr = VecView_Plex_HDF5(v, viewer);CHKERRQ(ierr); 133 #else 134 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 135 #endif 136 } else { 137 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 138 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 139 } 140 PetscFunctionReturn(0); 141 } 142 143 #undef __FUNCT__ 144 #define __FUNCT__ "VecLoad_Plex_Local" 145 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 146 { 147 DM dm; 148 PetscBool ishdf5; 149 PetscErrorCode ierr; 150 151 PetscFunctionBegin; 152 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 153 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 154 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 155 if (ishdf5) { 156 DM dmBC; 157 Vec gv; 158 const char *name; 159 160 ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr); 161 ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr); 162 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 163 ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr); 164 ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr); 165 ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 166 ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 167 ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr); 168 } else { 169 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 170 } 171 PetscFunctionReturn(0); 172 } 173 174 #undef __FUNCT__ 175 #define __FUNCT__ "VecLoad_Plex" 176 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 177 { 178 DM dm; 179 PetscBool ishdf5; 180 PetscErrorCode ierr; 181 182 PetscFunctionBegin; 183 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 184 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 185 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 186 if (ishdf5) { 187 #if defined(PETSC_HAVE_HDF5) 188 ierr = VecLoad_Plex_HDF5(v, viewer);CHKERRQ(ierr); 189 #else 190 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 191 #endif 192 } else { 193 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 194 } 195 PetscFunctionReturn(0); 196 } 197 198 #undef __FUNCT__ 199 #define __FUNCT__ "DMPlexView_Ascii" 200 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 201 { 202 DM_Plex *mesh = (DM_Plex*) dm->data; 203 DM cdm; 204 DMLabel markers; 205 PetscSection coordSection; 206 Vec coordinates; 207 PetscViewerFormat format; 208 PetscErrorCode ierr; 209 210 PetscFunctionBegin; 211 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 212 ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr); 213 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 214 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 215 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 216 const char *name; 217 PetscInt maxConeSize, maxSupportSize; 218 PetscInt pStart, pEnd, p; 219 PetscMPIInt rank, size; 220 221 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 222 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 223 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 224 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 225 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 226 ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr); 227 ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr); 228 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr); 229 ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr); 230 ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr); 231 for (p = pStart; p < pEnd; ++p) { 232 PetscInt dof, off, s; 233 234 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 235 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 236 for (s = off; s < off+dof; ++s) { 237 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr); 238 } 239 } 240 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 241 ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr); 242 for (p = pStart; p < pEnd; ++p) { 243 PetscInt dof, off, c; 244 245 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 246 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 247 for (c = off; c < off+dof; ++c) { 248 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr); 249 } 250 } 251 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 252 ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr); 253 if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);} 254 ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr); 255 ierr = DMLabelView(markers,viewer);CHKERRQ(ierr); 256 if (size > 1) { 257 PetscSF sf; 258 259 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 260 ierr = PetscSFView(sf, viewer);CHKERRQ(ierr); 261 } 262 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 263 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 264 const char *name; 265 const char *colors[3] = {"red", "blue", "green"}; 266 const int numColors = 3; 267 PetscReal scale = 2.0; 268 PetscScalar *coords; 269 PetscInt depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p; 270 PetscMPIInt rank, size; 271 272 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 273 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 274 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 275 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 276 ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr); 277 ierr = PetscViewerASCIIPrintf(viewer, "\ 278 \\documentclass[crop,multi=false]{standalone}\n\n\ 279 \\usepackage{tikz}\n\ 280 \\usepackage{pgflibraryshapes}\n\ 281 \\usetikzlibrary{backgrounds}\n\ 282 \\usetikzlibrary{arrows}\n\ 283 \\begin{document}\n\ 284 \\section{%s}\n\ 285 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr); 286 ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr); 287 for (p = 0; p < size; ++p) { 288 if (p > 0 && p == size-1) { 289 ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr); 290 } else if (p > 0) { 291 ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr); 292 } 293 ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr); 294 } 295 ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\ 296 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr); 297 /* Plot vertices */ 298 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 299 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 300 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 301 for (v = vStart; v < vEnd; ++v) { 302 PetscInt off, dof, d; 303 304 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 305 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 306 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 307 for (d = 0; d < dof; ++d) { 308 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 309 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*PetscRealPart(coords[off+d])));CHKERRQ(ierr); 310 } 311 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr); 312 } 313 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 314 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 315 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 316 /* Plot edges */ 317 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 318 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 319 if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);} 320 for (e = eStart; e < eEnd; ++e) { 321 const PetscInt *cone; 322 PetscInt coneSize, offA, offB, dof, d; 323 324 ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr); 325 if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize); 326 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 327 ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr); 328 ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr); 329 ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr); 330 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 331 for (d = 0; d < dof; ++d) { 332 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 333 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d])));CHKERRQ(ierr); 334 } 335 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr); 336 } 337 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 338 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 339 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 340 /* Plot cells */ 341 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 342 for (c = cStart; c < cEnd; ++c) { 343 PetscInt *closure = NULL; 344 PetscInt closureSize, firstPoint = -1; 345 346 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 347 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr); 348 for (p = 0; p < closureSize*2; p += 2) { 349 const PetscInt point = closure[p]; 350 351 if ((point < vStart) || (point >= vEnd)) continue; 352 if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);} 353 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr); 354 if (firstPoint < 0) firstPoint = point; 355 } 356 /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */ 357 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr); 358 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 359 } 360 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 361 ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr); 362 ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr); 363 } else { 364 MPI_Comm comm; 365 PetscInt *sizes, *hybsizes; 366 PetscInt locDepth, depth, dim, d, pMax[4]; 367 PetscInt pStart, pEnd, p; 368 PetscInt numLabels, l; 369 const char *name; 370 PetscMPIInt size; 371 372 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 373 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 374 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 375 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 376 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);CHKERRQ(ierr);} 377 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);} 378 ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr); 379 ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 380 ierr = DMPlexGetHybridBounds(dm, &pMax[depth], &pMax[depth-1], &pMax[1], &pMax[0]);CHKERRQ(ierr); 381 ierr = PetscMalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr); 382 if (depth == 1) { 383 ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 384 pEnd = pEnd - pStart; 385 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 386 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", 0);CHKERRQ(ierr); 387 for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 388 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 389 ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 390 pEnd = pEnd - pStart; 391 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 392 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);CHKERRQ(ierr); 393 for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 394 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 395 } else { 396 for (d = 0; d <= dim; d++) { 397 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 398 pEnd -= pStart; 399 pMax[d] -= pStart; 400 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 401 ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 402 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", d);CHKERRQ(ierr); 403 for (p = 0; p < size; ++p) { 404 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 405 else {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 406 } 407 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 408 } 409 } 410 ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr); 411 ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 412 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 413 for (l = 0; l < numLabels; ++l) { 414 DMLabel label; 415 const char *name; 416 IS valueIS; 417 const PetscInt *values; 418 PetscInt numValues, v; 419 420 ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr); 421 ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr); 422 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 423 ierr = PetscViewerASCIIPrintf(viewer, " %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr); 424 ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr); 425 ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr); 426 for (v = 0; v < numValues; ++v) { 427 PetscInt size; 428 429 ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr); 430 if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 431 ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr); 432 } 433 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 434 ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr); 435 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 436 } 437 } 438 PetscFunctionReturn(0); 439 } 440 441 #undef __FUNCT__ 442 #define __FUNCT__ "DMView_Plex" 443 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 444 { 445 PetscBool iascii, ishdf5; 446 PetscErrorCode ierr; 447 448 PetscFunctionBegin; 449 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 450 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 451 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 452 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 453 if (iascii) { 454 ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr); 455 } else if (ishdf5) { 456 #if defined(PETSC_HAVE_HDF5) 457 ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);CHKERRQ(ierr); 458 ierr = DMPlexView_HDF5(dm, viewer);CHKERRQ(ierr); 459 ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); 460 #else 461 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 462 #endif 463 } 464 PetscFunctionReturn(0); 465 } 466 467 #undef __FUNCT__ 468 #define __FUNCT__ "DMLoad_Plex" 469 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 470 { 471 PetscBool isbinary, ishdf5; 472 PetscErrorCode ierr; 473 474 PetscFunctionBegin; 475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 476 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 477 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr); 478 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 479 if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");} 480 else if (ishdf5) { 481 #if defined(PETSC_HAVE_HDF5) 482 DM odm; 483 ierr = DMCreate(PetscObjectComm((PetscObject) dm), &odm);CHKERRQ(ierr); 484 ierr = DMSetType(odm, DMPLEX);CHKERRQ(ierr); 485 ierr = DMPlexLoad_HDF5(odm, viewer);CHKERRQ(ierr); 486 ierr = DMPlexInterpolate(odm, &dm);CHKERRQ(ierr); 487 ierr = DMPlexCopyCoordinates(odm, dm);CHKERRQ(ierr); 488 ierr = DMPlexCopyLabels(odm, dm);CHKERRQ(ierr); 489 ierr = DMDestroy(&odm);CHKERRQ(ierr); 490 #else 491 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 492 #endif 493 } 494 PetscFunctionReturn(0); 495 } 496 497 #undef __FUNCT__ 498 #define __FUNCT__ "BoundaryDestroy" 499 static PetscErrorCode BoundaryDestroy(DMBoundary *boundary) 500 { 501 DMBoundary b, next; 502 PetscErrorCode ierr; 503 504 PetscFunctionBeginUser; 505 if (!boundary) PetscFunctionReturn(0); 506 b = *boundary; 507 *boundary = NULL; 508 for (; b; b = next) { 509 next = b->next; 510 ierr = PetscFree(b->ids);CHKERRQ(ierr); 511 ierr = PetscFree(b->name);CHKERRQ(ierr); 512 ierr = PetscFree(b);CHKERRQ(ierr); 513 } 514 PetscFunctionReturn(0); 515 } 516 517 #undef __FUNCT__ 518 #define __FUNCT__ "DMDestroy_Plex" 519 PetscErrorCode DMDestroy_Plex(DM dm) 520 { 521 DM_Plex *mesh = (DM_Plex*) dm->data; 522 DMLabel next = mesh->labels; 523 PetscErrorCode ierr; 524 525 PetscFunctionBegin; 526 if (--mesh->refct > 0) PetscFunctionReturn(0); 527 ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr); 528 ierr = PetscFree(mesh->cones);CHKERRQ(ierr); 529 ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr); 530 ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); 531 ierr = PetscFree(mesh->supports);CHKERRQ(ierr); 532 ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr); 533 while (next) { 534 DMLabel tmp = next->next; 535 536 ierr = DMLabelDestroy(&next);CHKERRQ(ierr); 537 next = tmp; 538 } 539 ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr); 540 ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr); 541 ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr); 542 ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr); 543 ierr = BoundaryDestroy(&mesh->boundary);CHKERRQ(ierr); 544 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 545 ierr = PetscFree(mesh);CHKERRQ(ierr); 546 PetscFunctionReturn(0); 547 } 548 549 #undef __FUNCT__ 550 #define __FUNCT__ "DMCreateMatrix_Plex" 551 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 552 { 553 PetscSection section, sectionGlobal; 554 PetscInt bs = -1; 555 PetscInt localSize; 556 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock; 557 PetscErrorCode ierr; 558 MatType mtype; 559 560 PetscFunctionBegin; 561 ierr = MatInitializePackage();CHKERRQ(ierr); 562 mtype = dm->mattype; 563 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 564 ierr = DMGetDefaultGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 565 /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */ 566 ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); 567 ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr); 568 ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 569 ierr = MatSetType(*J, mtype);CHKERRQ(ierr); 570 ierr = MatSetFromOptions(*J);CHKERRQ(ierr); 571 ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr); 572 ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr); 573 ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr); 574 ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr); 575 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 576 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 577 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 578 if (!isShell) { 579 PetscBool fillMatrix = (PetscBool) !dm->prealloc_only; 580 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin; 581 582 if (bs < 0) { 583 if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) { 584 PetscInt pStart, pEnd, p, dof, cdof; 585 586 ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr); 587 for (p = pStart; p < pEnd; ++p) { 588 ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr); 589 ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr); 590 if (dof-cdof) { 591 if (bs < 0) { 592 bs = dof-cdof; 593 } else if (bs != dof-cdof) { 594 /* Layout does not admit a pointwise block size */ 595 bs = 1; 596 break; 597 } 598 } 599 } 600 /* Must have same blocksize on all procs (some might have no points) */ 601 bsLocal = bs; 602 ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 603 bsLocal = bs < 0 ? bsMax : bs; 604 ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 605 if (bsMin != bsMax) { 606 bs = 1; 607 } else { 608 bs = bsMax; 609 } 610 } else { 611 bs = 1; 612 } 613 } 614 ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr); 615 ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr); 616 ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr); 617 } 618 PetscFunctionReturn(0); 619 } 620 621 #undef __FUNCT__ 622 #define __FUNCT__ "DMPlexGetDimension" 623 /*@ 624 DMPlexGetDimension - Return the topological mesh dimension 625 626 Not collective 627 628 Input Parameter: 629 . mesh - The DMPlex 630 631 Output Parameter: 632 . dim - The topological mesh dimension 633 634 Level: beginner 635 636 .seealso: DMPlexCreate() 637 @*/ 638 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim) 639 { 640 DM_Plex *mesh = (DM_Plex*) dm->data; 641 642 PetscFunctionBegin; 643 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 644 PetscValidPointer(dim, 2); 645 *dim = mesh->dim; 646 PetscFunctionReturn(0); 647 } 648 649 #undef __FUNCT__ 650 #define __FUNCT__ "DMPlexSetDimension" 651 /*@ 652 DMPlexSetDimension - Set the topological mesh dimension 653 654 Collective on mesh 655 656 Input Parameters: 657 + mesh - The DMPlex 658 - dim - The topological mesh dimension 659 660 Level: beginner 661 662 .seealso: DMPlexCreate() 663 @*/ 664 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim) 665 { 666 DM_Plex *mesh = (DM_Plex*) dm->data; 667 668 PetscFunctionBegin; 669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 670 PetscValidLogicalCollectiveInt(dm, dim, 2); 671 mesh->dim = dim; 672 PetscFunctionReturn(0); 673 } 674 675 #undef __FUNCT__ 676 #define __FUNCT__ "DMPlexGetChart" 677 /*@ 678 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 679 680 Not collective 681 682 Input Parameter: 683 . mesh - The DMPlex 684 685 Output Parameters: 686 + pStart - The first mesh point 687 - pEnd - The upper bound for mesh points 688 689 Level: beginner 690 691 .seealso: DMPlexCreate(), DMPlexSetChart() 692 @*/ 693 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 694 { 695 DM_Plex *mesh = (DM_Plex*) dm->data; 696 PetscErrorCode ierr; 697 698 PetscFunctionBegin; 699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 700 ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 701 PetscFunctionReturn(0); 702 } 703 704 #undef __FUNCT__ 705 #define __FUNCT__ "DMPlexSetChart" 706 /*@ 707 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 708 709 Not collective 710 711 Input Parameters: 712 + mesh - The DMPlex 713 . pStart - The first mesh point 714 - pEnd - The upper bound for mesh points 715 716 Output Parameters: 717 718 Level: beginner 719 720 .seealso: DMPlexCreate(), DMPlexGetChart() 721 @*/ 722 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 723 { 724 DM_Plex *mesh = (DM_Plex*) dm->data; 725 PetscErrorCode ierr; 726 727 PetscFunctionBegin; 728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 729 ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 730 ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 731 PetscFunctionReturn(0); 732 } 733 734 #undef __FUNCT__ 735 #define __FUNCT__ "DMPlexGetConeSize" 736 /*@ 737 DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG 738 739 Not collective 740 741 Input Parameters: 742 + mesh - The DMPlex 743 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 744 745 Output Parameter: 746 . size - The cone size for point p 747 748 Level: beginner 749 750 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 751 @*/ 752 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 753 { 754 DM_Plex *mesh = (DM_Plex*) dm->data; 755 PetscErrorCode ierr; 756 757 PetscFunctionBegin; 758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 759 PetscValidPointer(size, 3); 760 ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 761 PetscFunctionReturn(0); 762 } 763 764 #undef __FUNCT__ 765 #define __FUNCT__ "DMPlexSetConeSize" 766 /*@ 767 DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG 768 769 Not collective 770 771 Input Parameters: 772 + mesh - The DMPlex 773 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 774 - size - The cone size for point p 775 776 Output Parameter: 777 778 Note: 779 This should be called after DMPlexSetChart(). 780 781 Level: beginner 782 783 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 784 @*/ 785 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 786 { 787 DM_Plex *mesh = (DM_Plex*) dm->data; 788 PetscErrorCode ierr; 789 790 PetscFunctionBegin; 791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 792 ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 793 794 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 795 PetscFunctionReturn(0); 796 } 797 798 #undef __FUNCT__ 799 #define __FUNCT__ "DMPlexGetCone" 800 /*@C 801 DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG 802 803 Not collective 804 805 Input Parameters: 806 + mesh - The DMPlex 807 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 808 809 Output Parameter: 810 . cone - An array of points which are on the in-edges for point p 811 812 Level: beginner 813 814 Fortran Notes: 815 Since it returns an array, this routine is only available in Fortran 90, and you must 816 include petsc.h90 in your code. 817 818 You must also call DMPlexRestoreCone() after you finish using the returned array. 819 820 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart() 821 @*/ 822 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 823 { 824 DM_Plex *mesh = (DM_Plex*) dm->data; 825 PetscInt off; 826 PetscErrorCode ierr; 827 828 PetscFunctionBegin; 829 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 830 PetscValidPointer(cone, 3); 831 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 832 *cone = &mesh->cones[off]; 833 PetscFunctionReturn(0); 834 } 835 836 #undef __FUNCT__ 837 #define __FUNCT__ "DMPlexSetCone" 838 /*@ 839 DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG 840 841 Not collective 842 843 Input Parameters: 844 + mesh - The DMPlex 845 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 846 - cone - An array of points which are on the in-edges for point p 847 848 Output Parameter: 849 850 Note: 851 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 852 853 Level: beginner 854 855 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 856 @*/ 857 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 858 { 859 DM_Plex *mesh = (DM_Plex*) dm->data; 860 PetscInt pStart, pEnd; 861 PetscInt dof, off, c; 862 PetscErrorCode ierr; 863 864 PetscFunctionBegin; 865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 866 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 867 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 868 if (dof) PetscValidPointer(cone, 3); 869 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 870 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); 871 for (c = 0; c < dof; ++c) { 872 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); 873 mesh->cones[off+c] = cone[c]; 874 } 875 PetscFunctionReturn(0); 876 } 877 878 #undef __FUNCT__ 879 #define __FUNCT__ "DMPlexGetConeOrientation" 880 /*@C 881 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG 882 883 Not collective 884 885 Input Parameters: 886 + mesh - The DMPlex 887 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 888 889 Output Parameter: 890 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 891 integer giving the prescription for cone traversal. If it is negative, the cone is 892 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 893 the index of the cone point on which to start. 894 895 Level: beginner 896 897 Fortran Notes: 898 Since it returns an array, this routine is only available in Fortran 90, and you must 899 include petsc.h90 in your code. 900 901 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 902 903 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 904 @*/ 905 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 906 { 907 DM_Plex *mesh = (DM_Plex*) dm->data; 908 PetscInt off; 909 PetscErrorCode ierr; 910 911 PetscFunctionBegin; 912 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 913 #if defined(PETSC_USE_DEBUG) 914 { 915 PetscInt dof; 916 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 917 if (dof) PetscValidPointer(coneOrientation, 3); 918 } 919 #endif 920 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 921 922 *coneOrientation = &mesh->coneOrientations[off]; 923 PetscFunctionReturn(0); 924 } 925 926 #undef __FUNCT__ 927 #define __FUNCT__ "DMPlexSetConeOrientation" 928 /*@ 929 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG 930 931 Not collective 932 933 Input Parameters: 934 + mesh - The DMPlex 935 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 936 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 937 integer giving the prescription for cone traversal. If it is negative, the cone is 938 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 939 the index of the cone point on which to start. 940 941 Output Parameter: 942 943 Note: 944 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 945 946 Level: beginner 947 948 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 949 @*/ 950 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 951 { 952 DM_Plex *mesh = (DM_Plex*) dm->data; 953 PetscInt pStart, pEnd; 954 PetscInt dof, off, c; 955 PetscErrorCode ierr; 956 957 PetscFunctionBegin; 958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 959 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 960 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 961 if (dof) PetscValidPointer(coneOrientation, 3); 962 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 963 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); 964 for (c = 0; c < dof; ++c) { 965 PetscInt cdof, o = coneOrientation[c]; 966 967 ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr); 968 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); 969 mesh->coneOrientations[off+c] = o; 970 } 971 PetscFunctionReturn(0); 972 } 973 974 #undef __FUNCT__ 975 #define __FUNCT__ "DMPlexInsertCone" 976 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 977 { 978 DM_Plex *mesh = (DM_Plex*) dm->data; 979 PetscInt pStart, pEnd; 980 PetscInt dof, off; 981 PetscErrorCode ierr; 982 983 PetscFunctionBegin; 984 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 985 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 986 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); 987 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); 988 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 989 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 990 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); 991 mesh->cones[off+conePos] = conePoint; 992 PetscFunctionReturn(0); 993 } 994 995 #undef __FUNCT__ 996 #define __FUNCT__ "DMPlexInsertConeOrientation" 997 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 998 { 999 DM_Plex *mesh = (DM_Plex*) dm->data; 1000 PetscInt pStart, pEnd; 1001 PetscInt dof, off; 1002 PetscErrorCode ierr; 1003 1004 PetscFunctionBegin; 1005 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1006 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1007 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); 1008 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1009 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1010 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); 1011 mesh->coneOrientations[off+conePos] = coneOrientation; 1012 PetscFunctionReturn(0); 1013 } 1014 1015 #undef __FUNCT__ 1016 #define __FUNCT__ "DMPlexGetSupportSize" 1017 /*@ 1018 DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG 1019 1020 Not collective 1021 1022 Input Parameters: 1023 + mesh - The DMPlex 1024 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1025 1026 Output Parameter: 1027 . size - The support size for point p 1028 1029 Level: beginner 1030 1031 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 1032 @*/ 1033 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 1034 { 1035 DM_Plex *mesh = (DM_Plex*) dm->data; 1036 PetscErrorCode ierr; 1037 1038 PetscFunctionBegin; 1039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1040 PetscValidPointer(size, 3); 1041 ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 1042 PetscFunctionReturn(0); 1043 } 1044 1045 #undef __FUNCT__ 1046 #define __FUNCT__ "DMPlexSetSupportSize" 1047 /*@ 1048 DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG 1049 1050 Not collective 1051 1052 Input Parameters: 1053 + mesh - The DMPlex 1054 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1055 - size - The support size for point p 1056 1057 Output Parameter: 1058 1059 Note: 1060 This should be called after DMPlexSetChart(). 1061 1062 Level: beginner 1063 1064 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 1065 @*/ 1066 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 1067 { 1068 DM_Plex *mesh = (DM_Plex*) dm->data; 1069 PetscErrorCode ierr; 1070 1071 PetscFunctionBegin; 1072 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1073 ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 1074 1075 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 1076 PetscFunctionReturn(0); 1077 } 1078 1079 #undef __FUNCT__ 1080 #define __FUNCT__ "DMPlexGetSupport" 1081 /*@C 1082 DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG 1083 1084 Not collective 1085 1086 Input Parameters: 1087 + mesh - The DMPlex 1088 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1089 1090 Output Parameter: 1091 . support - An array of points which are on the out-edges for point p 1092 1093 Level: beginner 1094 1095 Fortran Notes: 1096 Since it returns an array, this routine is only available in Fortran 90, and you must 1097 include petsc.h90 in your code. 1098 1099 You must also call DMPlexRestoreSupport() after you finish using the returned array. 1100 1101 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1102 @*/ 1103 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 1104 { 1105 DM_Plex *mesh = (DM_Plex*) dm->data; 1106 PetscInt off; 1107 PetscErrorCode ierr; 1108 1109 PetscFunctionBegin; 1110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1111 PetscValidPointer(support, 3); 1112 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1113 *support = &mesh->supports[off]; 1114 PetscFunctionReturn(0); 1115 } 1116 1117 #undef __FUNCT__ 1118 #define __FUNCT__ "DMPlexSetSupport" 1119 /*@ 1120 DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG 1121 1122 Not collective 1123 1124 Input Parameters: 1125 + mesh - The DMPlex 1126 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1127 - support - An array of points which are on the in-edges for point p 1128 1129 Output Parameter: 1130 1131 Note: 1132 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 1133 1134 Level: beginner 1135 1136 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 1137 @*/ 1138 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 1139 { 1140 DM_Plex *mesh = (DM_Plex*) dm->data; 1141 PetscInt pStart, pEnd; 1142 PetscInt dof, off, c; 1143 PetscErrorCode ierr; 1144 1145 PetscFunctionBegin; 1146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1147 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 1148 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 1149 if (dof) PetscValidPointer(support, 3); 1150 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1151 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); 1152 for (c = 0; c < dof; ++c) { 1153 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); 1154 mesh->supports[off+c] = support[c]; 1155 } 1156 PetscFunctionReturn(0); 1157 } 1158 1159 #undef __FUNCT__ 1160 #define __FUNCT__ "DMPlexInsertSupport" 1161 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 1162 { 1163 DM_Plex *mesh = (DM_Plex*) dm->data; 1164 PetscInt pStart, pEnd; 1165 PetscInt dof, off; 1166 PetscErrorCode ierr; 1167 1168 PetscFunctionBegin; 1169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1170 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 1171 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 1172 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1173 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); 1174 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); 1175 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); 1176 mesh->supports[off+supportPos] = supportPoint; 1177 PetscFunctionReturn(0); 1178 } 1179 1180 #undef __FUNCT__ 1181 #define __FUNCT__ "DMPlexGetTransitiveClosure" 1182 /*@C 1183 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG 1184 1185 Not collective 1186 1187 Input Parameters: 1188 + mesh - The DMPlex 1189 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1190 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1191 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 1192 1193 Output Parameters: 1194 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 1195 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 1196 1197 Note: 1198 If using internal storage (points is NULL on input), each call overwrites the last output. 1199 1200 Fortran Notes: 1201 Since it returns an array, this routine is only available in Fortran 90, and you must 1202 include petsc.h90 in your code. 1203 1204 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1205 1206 Level: beginner 1207 1208 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1209 @*/ 1210 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1211 { 1212 DM_Plex *mesh = (DM_Plex*) dm->data; 1213 PetscInt *closure, *fifo; 1214 const PetscInt *tmp = NULL, *tmpO = NULL; 1215 PetscInt tmpSize, t; 1216 PetscInt depth = 0, maxSize; 1217 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 1218 PetscErrorCode ierr; 1219 1220 PetscFunctionBegin; 1221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1222 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1223 /* This is only 1-level */ 1224 if (useCone) { 1225 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 1226 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 1227 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 1228 } else { 1229 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 1230 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 1231 } 1232 if (depth == 1) { 1233 if (*points) { 1234 closure = *points; 1235 } else { 1236 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 1237 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1238 } 1239 closure[0] = p; closure[1] = 0; 1240 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 1241 closure[closureSize] = tmp[t]; 1242 closure[closureSize+1] = tmpO ? tmpO[t] : 0; 1243 } 1244 if (numPoints) *numPoints = closureSize/2; 1245 if (points) *points = closure; 1246 PetscFunctionReturn(0); 1247 } 1248 maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1); 1249 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1250 if (*points) { 1251 closure = *points; 1252 } else { 1253 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1254 } 1255 closure[0] = p; closure[1] = 0; 1256 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 1257 const PetscInt cp = tmp[t]; 1258 const PetscInt co = tmpO ? tmpO[t] : 0; 1259 1260 closure[closureSize] = cp; 1261 closure[closureSize+1] = co; 1262 fifo[fifoSize] = cp; 1263 fifo[fifoSize+1] = co; 1264 } 1265 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 1266 while (fifoSize - fifoStart) { 1267 const PetscInt q = fifo[fifoStart]; 1268 const PetscInt o = fifo[fifoStart+1]; 1269 const PetscInt rev = o >= 0 ? 0 : 1; 1270 const PetscInt off = rev ? -(o+1) : o; 1271 1272 if (useCone) { 1273 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 1274 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 1275 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 1276 } else { 1277 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 1278 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 1279 tmpO = NULL; 1280 } 1281 for (t = 0; t < tmpSize; ++t) { 1282 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 1283 const PetscInt cp = tmp[i]; 1284 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 1285 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 1286 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 1287 PetscInt co = tmpO ? tmpO[i] : 0; 1288 PetscInt c; 1289 1290 if (rev) { 1291 PetscInt childSize, coff; 1292 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1293 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 1294 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1295 } 1296 /* Check for duplicate */ 1297 for (c = 0; c < closureSize; c += 2) { 1298 if (closure[c] == cp) break; 1299 } 1300 if (c == closureSize) { 1301 closure[closureSize] = cp; 1302 closure[closureSize+1] = co; 1303 fifo[fifoSize] = cp; 1304 fifo[fifoSize+1] = co; 1305 closureSize += 2; 1306 fifoSize += 2; 1307 } 1308 } 1309 fifoStart += 2; 1310 } 1311 if (numPoints) *numPoints = closureSize/2; 1312 if (points) *points = closure; 1313 ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1314 PetscFunctionReturn(0); 1315 } 1316 1317 #undef __FUNCT__ 1318 #define __FUNCT__ "DMPlexGetTransitiveClosure_Internal" 1319 /*@C 1320 DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation 1321 1322 Not collective 1323 1324 Input Parameters: 1325 + mesh - The DMPlex 1326 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1327 . orientation - The orientation of the point 1328 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1329 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 1330 1331 Output Parameters: 1332 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 1333 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 1334 1335 Note: 1336 If using internal storage (points is NULL on input), each call overwrites the last output. 1337 1338 Fortran Notes: 1339 Since it returns an array, this routine is only available in Fortran 90, and you must 1340 include petsc.h90 in your code. 1341 1342 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1343 1344 Level: beginner 1345 1346 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1347 @*/ 1348 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1349 { 1350 DM_Plex *mesh = (DM_Plex*) dm->data; 1351 PetscInt *closure, *fifo; 1352 const PetscInt *tmp = NULL, *tmpO = NULL; 1353 PetscInt tmpSize, t; 1354 PetscInt depth = 0, maxSize; 1355 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 1356 PetscErrorCode ierr; 1357 1358 PetscFunctionBegin; 1359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1360 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1361 /* This is only 1-level */ 1362 if (useCone) { 1363 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 1364 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 1365 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 1366 } else { 1367 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 1368 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 1369 } 1370 if (depth == 1) { 1371 if (*points) { 1372 closure = *points; 1373 } else { 1374 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 1375 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1376 } 1377 closure[0] = p; closure[1] = ornt; 1378 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 1379 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 1380 closure[closureSize] = tmp[i]; 1381 closure[closureSize+1] = tmpO ? tmpO[i] : 0; 1382 } 1383 if (numPoints) *numPoints = closureSize/2; 1384 if (points) *points = closure; 1385 PetscFunctionReturn(0); 1386 } 1387 maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1); 1388 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1389 if (*points) { 1390 closure = *points; 1391 } else { 1392 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1393 } 1394 closure[0] = p; closure[1] = ornt; 1395 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 1396 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 1397 const PetscInt cp = tmp[i]; 1398 PetscInt co = tmpO ? tmpO[i] : 0; 1399 1400 if (ornt < 0) { 1401 PetscInt childSize, coff; 1402 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1403 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 1404 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1405 } 1406 closure[closureSize] = cp; 1407 closure[closureSize+1] = co; 1408 fifo[fifoSize] = cp; 1409 fifo[fifoSize+1] = co; 1410 } 1411 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 1412 while (fifoSize - fifoStart) { 1413 const PetscInt q = fifo[fifoStart]; 1414 const PetscInt o = fifo[fifoStart+1]; 1415 const PetscInt rev = o >= 0 ? 0 : 1; 1416 const PetscInt off = rev ? -(o+1) : o; 1417 1418 if (useCone) { 1419 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 1420 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 1421 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 1422 } else { 1423 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 1424 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 1425 tmpO = NULL; 1426 } 1427 for (t = 0; t < tmpSize; ++t) { 1428 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 1429 const PetscInt cp = tmp[i]; 1430 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 1431 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 1432 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 1433 PetscInt co = tmpO ? tmpO[i] : 0; 1434 PetscInt c; 1435 1436 if (rev) { 1437 PetscInt childSize, coff; 1438 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1439 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 1440 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1441 } 1442 /* Check for duplicate */ 1443 for (c = 0; c < closureSize; c += 2) { 1444 if (closure[c] == cp) break; 1445 } 1446 if (c == closureSize) { 1447 closure[closureSize] = cp; 1448 closure[closureSize+1] = co; 1449 fifo[fifoSize] = cp; 1450 fifo[fifoSize+1] = co; 1451 closureSize += 2; 1452 fifoSize += 2; 1453 } 1454 } 1455 fifoStart += 2; 1456 } 1457 if (numPoints) *numPoints = closureSize/2; 1458 if (points) *points = closure; 1459 ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1460 PetscFunctionReturn(0); 1461 } 1462 1463 #undef __FUNCT__ 1464 #define __FUNCT__ "DMPlexRestoreTransitiveClosure" 1465 /*@C 1466 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG 1467 1468 Not collective 1469 1470 Input Parameters: 1471 + mesh - The DMPlex 1472 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1473 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1474 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit 1475 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit 1476 1477 Note: 1478 If not using internal storage (points is not NULL on input), this call is unnecessary 1479 1480 Fortran Notes: 1481 Since it returns an array, this routine is only available in Fortran 90, and you must 1482 include petsc.h90 in your code. 1483 1484 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1485 1486 Level: beginner 1487 1488 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1489 @*/ 1490 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1491 { 1492 PetscErrorCode ierr; 1493 1494 PetscFunctionBegin; 1495 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1496 if (numPoints) PetscValidIntPointer(numPoints,4); 1497 if (points) PetscValidPointer(points,5); 1498 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr); 1499 if (numPoints) *numPoints = 0; 1500 PetscFunctionReturn(0); 1501 } 1502 1503 #undef __FUNCT__ 1504 #define __FUNCT__ "DMPlexGetMaxSizes" 1505 /*@ 1506 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG 1507 1508 Not collective 1509 1510 Input Parameter: 1511 . mesh - The DMPlex 1512 1513 Output Parameters: 1514 + maxConeSize - The maximum number of in-edges 1515 - maxSupportSize - The maximum number of out-edges 1516 1517 Level: beginner 1518 1519 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 1520 @*/ 1521 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 1522 { 1523 DM_Plex *mesh = (DM_Plex*) dm->data; 1524 1525 PetscFunctionBegin; 1526 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1527 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 1528 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 1529 PetscFunctionReturn(0); 1530 } 1531 1532 #undef __FUNCT__ 1533 #define __FUNCT__ "DMSetUp_Plex" 1534 PetscErrorCode DMSetUp_Plex(DM dm) 1535 { 1536 DM_Plex *mesh = (DM_Plex*) dm->data; 1537 PetscInt size; 1538 PetscErrorCode ierr; 1539 1540 PetscFunctionBegin; 1541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1542 ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr); 1543 ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr); 1544 ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr); 1545 ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr); 1546 if (mesh->maxSupportSize) { 1547 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 1548 ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr); 1549 ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr); 1550 } 1551 PetscFunctionReturn(0); 1552 } 1553 1554 #undef __FUNCT__ 1555 #define __FUNCT__ "DMCreateSubDM_Plex" 1556 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm) 1557 { 1558 PetscErrorCode ierr; 1559 1560 PetscFunctionBegin; 1561 if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);} 1562 ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr); 1563 PetscFunctionReturn(0); 1564 } 1565 1566 #undef __FUNCT__ 1567 #define __FUNCT__ "DMPlexSymmetrize" 1568 /*@ 1569 DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation 1570 1571 Not collective 1572 1573 Input Parameter: 1574 . mesh - The DMPlex 1575 1576 Output Parameter: 1577 1578 Note: 1579 This should be called after all calls to DMPlexSetCone() 1580 1581 Level: beginner 1582 1583 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 1584 @*/ 1585 PetscErrorCode DMPlexSymmetrize(DM dm) 1586 { 1587 DM_Plex *mesh = (DM_Plex*) dm->data; 1588 PetscInt *offsets; 1589 PetscInt supportSize; 1590 PetscInt pStart, pEnd, p; 1591 PetscErrorCode ierr; 1592 1593 PetscFunctionBegin; 1594 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1595 if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 1596 /* Calculate support sizes */ 1597 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 1598 for (p = pStart; p < pEnd; ++p) { 1599 PetscInt dof, off, c; 1600 1601 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1602 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1603 for (c = off; c < off+dof; ++c) { 1604 ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr); 1605 } 1606 } 1607 for (p = pStart; p < pEnd; ++p) { 1608 PetscInt dof; 1609 1610 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 1611 1612 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 1613 } 1614 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 1615 /* Calculate supports */ 1616 ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr); 1617 ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr); 1618 ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr); 1619 for (p = pStart; p < pEnd; ++p) { 1620 PetscInt dof, off, c; 1621 1622 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1623 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1624 for (c = off; c < off+dof; ++c) { 1625 const PetscInt q = mesh->cones[c]; 1626 PetscInt offS; 1627 1628 ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr); 1629 1630 mesh->supports[offS+offsets[q]] = p; 1631 ++offsets[q]; 1632 } 1633 } 1634 ierr = PetscFree(offsets);CHKERRQ(ierr); 1635 PetscFunctionReturn(0); 1636 } 1637 1638 #undef __FUNCT__ 1639 #define __FUNCT__ "DMPlexStratify" 1640 /*@ 1641 DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and 1642 can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 1643 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 1644 the DAG. 1645 1646 Not collective 1647 1648 Input Parameter: 1649 . mesh - The DMPlex 1650 1651 Output Parameter: 1652 1653 Notes: 1654 The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would 1655 have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1. 1656 1657 This should be called after all calls to DMPlexSymmetrize() 1658 1659 Level: beginner 1660 1661 .seealso: DMPlexCreate(), DMPlexSymmetrize() 1662 @*/ 1663 PetscErrorCode DMPlexStratify(DM dm) 1664 { 1665 DMLabel label; 1666 PetscInt pStart, pEnd, p; 1667 PetscInt numRoots = 0, numLeaves = 0; 1668 PetscErrorCode ierr; 1669 1670 PetscFunctionBegin; 1671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1672 ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 1673 /* Calculate depth */ 1674 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 1675 ierr = DMPlexCreateLabel(dm, "depth");CHKERRQ(ierr); 1676 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 1677 /* Initialize roots and count leaves */ 1678 for (p = pStart; p < pEnd; ++p) { 1679 PetscInt coneSize, supportSize; 1680 1681 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 1682 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 1683 if (!coneSize && supportSize) { 1684 ++numRoots; 1685 ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr); 1686 } else if (!supportSize && coneSize) { 1687 ++numLeaves; 1688 } else if (!supportSize && !coneSize) { 1689 /* Isolated points */ 1690 ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr); 1691 } 1692 } 1693 if (numRoots + numLeaves == (pEnd - pStart)) { 1694 for (p = pStart; p < pEnd; ++p) { 1695 PetscInt coneSize, supportSize; 1696 1697 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 1698 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 1699 if (!supportSize && coneSize) { 1700 ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr); 1701 } 1702 } 1703 } else { 1704 IS pointIS; 1705 PetscInt numPoints = 0, level = 0; 1706 1707 ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr); 1708 if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);} 1709 while (numPoints) { 1710 const PetscInt *points; 1711 const PetscInt newLevel = level+1; 1712 1713 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 1714 for (p = 0; p < numPoints; ++p) { 1715 const PetscInt point = points[p]; 1716 const PetscInt *support; 1717 PetscInt supportSize, s; 1718 1719 ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr); 1720 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 1721 for (s = 0; s < supportSize; ++s) { 1722 ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr); 1723 } 1724 } 1725 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 1726 ++level; 1727 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1728 ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr); 1729 if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);} 1730 else {numPoints = 0;} 1731 } 1732 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1733 } 1734 ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 1735 PetscFunctionReturn(0); 1736 } 1737 1738 #undef __FUNCT__ 1739 #define __FUNCT__ "DMPlexGetJoin" 1740 /*@C 1741 DMPlexGetJoin - Get an array for the join of the set of points 1742 1743 Not Collective 1744 1745 Input Parameters: 1746 + dm - The DMPlex object 1747 . numPoints - The number of input points for the join 1748 - points - The input points 1749 1750 Output Parameters: 1751 + numCoveredPoints - The number of points in the join 1752 - coveredPoints - The points in the join 1753 1754 Level: intermediate 1755 1756 Note: Currently, this is restricted to a single level join 1757 1758 Fortran Notes: 1759 Since it returns an array, this routine is only available in Fortran 90, and you must 1760 include petsc.h90 in your code. 1761 1762 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1763 1764 .keywords: mesh 1765 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 1766 @*/ 1767 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 1768 { 1769 DM_Plex *mesh = (DM_Plex*) dm->data; 1770 PetscInt *join[2]; 1771 PetscInt joinSize, i = 0; 1772 PetscInt dof, off, p, c, m; 1773 PetscErrorCode ierr; 1774 1775 PetscFunctionBegin; 1776 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1777 PetscValidPointer(points, 2); 1778 PetscValidPointer(numCoveredPoints, 3); 1779 PetscValidPointer(coveredPoints, 4); 1780 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr); 1781 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr); 1782 /* Copy in support of first point */ 1783 ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr); 1784 ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr); 1785 for (joinSize = 0; joinSize < dof; ++joinSize) { 1786 join[i][joinSize] = mesh->supports[off+joinSize]; 1787 } 1788 /* Check each successive support */ 1789 for (p = 1; p < numPoints; ++p) { 1790 PetscInt newJoinSize = 0; 1791 1792 ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr); 1793 ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr); 1794 for (c = 0; c < dof; ++c) { 1795 const PetscInt point = mesh->supports[off+c]; 1796 1797 for (m = 0; m < joinSize; ++m) { 1798 if (point == join[i][m]) { 1799 join[1-i][newJoinSize++] = point; 1800 break; 1801 } 1802 } 1803 } 1804 joinSize = newJoinSize; 1805 i = 1-i; 1806 } 1807 *numCoveredPoints = joinSize; 1808 *coveredPoints = join[i]; 1809 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr); 1810 PetscFunctionReturn(0); 1811 } 1812 1813 #undef __FUNCT__ 1814 #define __FUNCT__ "DMPlexRestoreJoin" 1815 /*@C 1816 DMPlexRestoreJoin - Restore an array for the join of the set of points 1817 1818 Not Collective 1819 1820 Input Parameters: 1821 + dm - The DMPlex object 1822 . numPoints - The number of input points for the join 1823 - points - The input points 1824 1825 Output Parameters: 1826 + numCoveredPoints - The number of points in the join 1827 - coveredPoints - The points in the join 1828 1829 Fortran Notes: 1830 Since it returns an array, this routine is only available in Fortran 90, and you must 1831 include petsc.h90 in your code. 1832 1833 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1834 1835 Level: intermediate 1836 1837 .keywords: mesh 1838 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 1839 @*/ 1840 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 1841 { 1842 PetscErrorCode ierr; 1843 1844 PetscFunctionBegin; 1845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1846 if (points) PetscValidIntPointer(points,3); 1847 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 1848 PetscValidPointer(coveredPoints, 5); 1849 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr); 1850 if (numCoveredPoints) *numCoveredPoints = 0; 1851 PetscFunctionReturn(0); 1852 } 1853 1854 #undef __FUNCT__ 1855 #define __FUNCT__ "DMPlexGetFullJoin" 1856 /*@C 1857 DMPlexGetFullJoin - Get an array for the join of the set of points 1858 1859 Not Collective 1860 1861 Input Parameters: 1862 + dm - The DMPlex object 1863 . numPoints - The number of input points for the join 1864 - points - The input points 1865 1866 Output Parameters: 1867 + numCoveredPoints - The number of points in the join 1868 - coveredPoints - The points in the join 1869 1870 Fortran Notes: 1871 Since it returns an array, this routine is only available in Fortran 90, and you must 1872 include petsc.h90 in your code. 1873 1874 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1875 1876 Level: intermediate 1877 1878 .keywords: mesh 1879 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 1880 @*/ 1881 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 1882 { 1883 DM_Plex *mesh = (DM_Plex*) dm->data; 1884 PetscInt *offsets, **closures; 1885 PetscInt *join[2]; 1886 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 1887 PetscInt p, d, c, m; 1888 PetscErrorCode ierr; 1889 1890 PetscFunctionBegin; 1891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1892 PetscValidPointer(points, 2); 1893 PetscValidPointer(numCoveredPoints, 3); 1894 PetscValidPointer(coveredPoints, 4); 1895 1896 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1897 ierr = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr); 1898 ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr); 1899 maxSize = PetscPowInt(mesh->maxSupportSize,depth+1); 1900 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr); 1901 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr); 1902 1903 for (p = 0; p < numPoints; ++p) { 1904 PetscInt closureSize; 1905 1906 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr); 1907 1908 offsets[p*(depth+2)+0] = 0; 1909 for (d = 0; d < depth+1; ++d) { 1910 PetscInt pStart, pEnd, i; 1911 1912 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 1913 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 1914 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 1915 offsets[p*(depth+2)+d+1] = i; 1916 break; 1917 } 1918 } 1919 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 1920 } 1921 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); 1922 } 1923 for (d = 0; d < depth+1; ++d) { 1924 PetscInt dof; 1925 1926 /* Copy in support of first point */ 1927 dof = offsets[d+1] - offsets[d]; 1928 for (joinSize = 0; joinSize < dof; ++joinSize) { 1929 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 1930 } 1931 /* Check each successive cone */ 1932 for (p = 1; p < numPoints && joinSize; ++p) { 1933 PetscInt newJoinSize = 0; 1934 1935 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 1936 for (c = 0; c < dof; ++c) { 1937 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 1938 1939 for (m = 0; m < joinSize; ++m) { 1940 if (point == join[i][m]) { 1941 join[1-i][newJoinSize++] = point; 1942 break; 1943 } 1944 } 1945 } 1946 joinSize = newJoinSize; 1947 i = 1-i; 1948 } 1949 if (joinSize) break; 1950 } 1951 *numCoveredPoints = joinSize; 1952 *coveredPoints = join[i]; 1953 for (p = 0; p < numPoints; ++p) { 1954 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr); 1955 } 1956 ierr = PetscFree(closures);CHKERRQ(ierr); 1957 ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr); 1958 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr); 1959 PetscFunctionReturn(0); 1960 } 1961 1962 #undef __FUNCT__ 1963 #define __FUNCT__ "DMPlexGetMeet" 1964 /*@C 1965 DMPlexGetMeet - Get an array for the meet of the set of points 1966 1967 Not Collective 1968 1969 Input Parameters: 1970 + dm - The DMPlex object 1971 . numPoints - The number of input points for the meet 1972 - points - The input points 1973 1974 Output Parameters: 1975 + numCoveredPoints - The number of points in the meet 1976 - coveredPoints - The points in the meet 1977 1978 Level: intermediate 1979 1980 Note: Currently, this is restricted to a single level meet 1981 1982 Fortran Notes: 1983 Since it returns an array, this routine is only available in Fortran 90, and you must 1984 include petsc.h90 in your code. 1985 1986 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1987 1988 .keywords: mesh 1989 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 1990 @*/ 1991 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 1992 { 1993 DM_Plex *mesh = (DM_Plex*) dm->data; 1994 PetscInt *meet[2]; 1995 PetscInt meetSize, i = 0; 1996 PetscInt dof, off, p, c, m; 1997 PetscErrorCode ierr; 1998 1999 PetscFunctionBegin; 2000 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2001 PetscValidPointer(points, 2); 2002 PetscValidPointer(numCoveringPoints, 3); 2003 PetscValidPointer(coveringPoints, 4); 2004 ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr); 2005 ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr); 2006 /* Copy in cone of first point */ 2007 ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr); 2008 ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr); 2009 for (meetSize = 0; meetSize < dof; ++meetSize) { 2010 meet[i][meetSize] = mesh->cones[off+meetSize]; 2011 } 2012 /* Check each successive cone */ 2013 for (p = 1; p < numPoints; ++p) { 2014 PetscInt newMeetSize = 0; 2015 2016 ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr); 2017 ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr); 2018 for (c = 0; c < dof; ++c) { 2019 const PetscInt point = mesh->cones[off+c]; 2020 2021 for (m = 0; m < meetSize; ++m) { 2022 if (point == meet[i][m]) { 2023 meet[1-i][newMeetSize++] = point; 2024 break; 2025 } 2026 } 2027 } 2028 meetSize = newMeetSize; 2029 i = 1-i; 2030 } 2031 *numCoveringPoints = meetSize; 2032 *coveringPoints = meet[i]; 2033 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr); 2034 PetscFunctionReturn(0); 2035 } 2036 2037 #undef __FUNCT__ 2038 #define __FUNCT__ "DMPlexRestoreMeet" 2039 /*@C 2040 DMPlexRestoreMeet - Restore an array for the meet of the set of points 2041 2042 Not Collective 2043 2044 Input Parameters: 2045 + dm - The DMPlex object 2046 . numPoints - The number of input points for the meet 2047 - points - The input points 2048 2049 Output Parameters: 2050 + numCoveredPoints - The number of points in the meet 2051 - coveredPoints - The points in the meet 2052 2053 Level: intermediate 2054 2055 Fortran Notes: 2056 Since it returns an array, this routine is only available in Fortran 90, and you must 2057 include petsc.h90 in your code. 2058 2059 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2060 2061 .keywords: mesh 2062 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 2063 @*/ 2064 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2065 { 2066 PetscErrorCode ierr; 2067 2068 PetscFunctionBegin; 2069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2070 if (points) PetscValidIntPointer(points,3); 2071 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 2072 PetscValidPointer(coveredPoints,5); 2073 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr); 2074 if (numCoveredPoints) *numCoveredPoints = 0; 2075 PetscFunctionReturn(0); 2076 } 2077 2078 #undef __FUNCT__ 2079 #define __FUNCT__ "DMPlexGetFullMeet" 2080 /*@C 2081 DMPlexGetFullMeet - Get an array for the meet of the set of points 2082 2083 Not Collective 2084 2085 Input Parameters: 2086 + dm - The DMPlex object 2087 . numPoints - The number of input points for the meet 2088 - points - The input points 2089 2090 Output Parameters: 2091 + numCoveredPoints - The number of points in the meet 2092 - coveredPoints - The points in the meet 2093 2094 Level: intermediate 2095 2096 Fortran Notes: 2097 Since it returns an array, this routine is only available in Fortran 90, and you must 2098 include petsc.h90 in your code. 2099 2100 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2101 2102 .keywords: mesh 2103 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 2104 @*/ 2105 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2106 { 2107 DM_Plex *mesh = (DM_Plex*) dm->data; 2108 PetscInt *offsets, **closures; 2109 PetscInt *meet[2]; 2110 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 2111 PetscInt p, h, c, m; 2112 PetscErrorCode ierr; 2113 2114 PetscFunctionBegin; 2115 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2116 PetscValidPointer(points, 2); 2117 PetscValidPointer(numCoveredPoints, 3); 2118 PetscValidPointer(coveredPoints, 4); 2119 2120 ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr); 2121 ierr = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr); 2122 ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2123 maxSize = PetscPowInt(mesh->maxConeSize,height+1); 2124 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr); 2125 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr); 2126 2127 for (p = 0; p < numPoints; ++p) { 2128 PetscInt closureSize; 2129 2130 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr); 2131 2132 offsets[p*(height+2)+0] = 0; 2133 for (h = 0; h < height+1; ++h) { 2134 PetscInt pStart, pEnd, i; 2135 2136 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 2137 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 2138 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 2139 offsets[p*(height+2)+h+1] = i; 2140 break; 2141 } 2142 } 2143 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 2144 } 2145 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); 2146 } 2147 for (h = 0; h < height+1; ++h) { 2148 PetscInt dof; 2149 2150 /* Copy in cone of first point */ 2151 dof = offsets[h+1] - offsets[h]; 2152 for (meetSize = 0; meetSize < dof; ++meetSize) { 2153 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 2154 } 2155 /* Check each successive cone */ 2156 for (p = 1; p < numPoints && meetSize; ++p) { 2157 PetscInt newMeetSize = 0; 2158 2159 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 2160 for (c = 0; c < dof; ++c) { 2161 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 2162 2163 for (m = 0; m < meetSize; ++m) { 2164 if (point == meet[i][m]) { 2165 meet[1-i][newMeetSize++] = point; 2166 break; 2167 } 2168 } 2169 } 2170 meetSize = newMeetSize; 2171 i = 1-i; 2172 } 2173 if (meetSize) break; 2174 } 2175 *numCoveredPoints = meetSize; 2176 *coveredPoints = meet[i]; 2177 for (p = 0; p < numPoints; ++p) { 2178 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr); 2179 } 2180 ierr = PetscFree(closures);CHKERRQ(ierr); 2181 ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2182 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr); 2183 PetscFunctionReturn(0); 2184 } 2185 2186 #undef __FUNCT__ 2187 #define __FUNCT__ "DMPlexEqual" 2188 /*@C 2189 DMPlexEqual - Determine if two DMs have the same topology 2190 2191 Not Collective 2192 2193 Input Parameters: 2194 + dmA - A DMPlex object 2195 - dmB - A DMPlex object 2196 2197 Output Parameters: 2198 . equal - PETSC_TRUE if the topologies are identical 2199 2200 Level: intermediate 2201 2202 Notes: 2203 We are not solving graph isomorphism, so we do not permutation. 2204 2205 .keywords: mesh 2206 .seealso: DMPlexGetCone() 2207 @*/ 2208 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 2209 { 2210 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 2211 PetscErrorCode ierr; 2212 2213 PetscFunctionBegin; 2214 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 2215 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 2216 PetscValidPointer(equal, 3); 2217 2218 *equal = PETSC_FALSE; 2219 ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr); 2220 ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr); 2221 if (depth != depthB) PetscFunctionReturn(0); 2222 ierr = DMPlexGetChart(dmA, &pStart, &pEnd);CHKERRQ(ierr); 2223 ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr); 2224 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 2225 for (p = pStart; p < pEnd; ++p) { 2226 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 2227 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 2228 2229 ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr); 2230 ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr); 2231 ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr); 2232 ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr); 2233 ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr); 2234 ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr); 2235 if (coneSize != coneSizeB) PetscFunctionReturn(0); 2236 for (c = 0; c < coneSize; ++c) { 2237 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 2238 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 2239 } 2240 ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr); 2241 ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr); 2242 ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr); 2243 ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr); 2244 if (supportSize != supportSizeB) PetscFunctionReturn(0); 2245 for (s = 0; s < supportSize; ++s) { 2246 if (support[s] != supportB[s]) PetscFunctionReturn(0); 2247 } 2248 } 2249 *equal = PETSC_TRUE; 2250 PetscFunctionReturn(0); 2251 } 2252 2253 #undef __FUNCT__ 2254 #define __FUNCT__ "DMPlexGetNumFaceVertices" 2255 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 2256 { 2257 MPI_Comm comm; 2258 PetscErrorCode ierr; 2259 2260 PetscFunctionBegin; 2261 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 2262 PetscValidPointer(numFaceVertices,3); 2263 switch (cellDim) { 2264 case 0: 2265 *numFaceVertices = 0; 2266 break; 2267 case 1: 2268 *numFaceVertices = 1; 2269 break; 2270 case 2: 2271 switch (numCorners) { 2272 case 3: /* triangle */ 2273 *numFaceVertices = 2; /* Edge has 2 vertices */ 2274 break; 2275 case 4: /* quadrilateral */ 2276 *numFaceVertices = 2; /* Edge has 2 vertices */ 2277 break; 2278 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 2279 *numFaceVertices = 3; /* Edge has 3 vertices */ 2280 break; 2281 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 2282 *numFaceVertices = 3; /* Edge has 3 vertices */ 2283 break; 2284 default: 2285 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim); 2286 } 2287 break; 2288 case 3: 2289 switch (numCorners) { 2290 case 4: /* tetradehdron */ 2291 *numFaceVertices = 3; /* Face has 3 vertices */ 2292 break; 2293 case 6: /* tet cohesive cells */ 2294 *numFaceVertices = 4; /* Face has 4 vertices */ 2295 break; 2296 case 8: /* hexahedron */ 2297 *numFaceVertices = 4; /* Face has 4 vertices */ 2298 break; 2299 case 9: /* tet cohesive Lagrange cells */ 2300 *numFaceVertices = 6; /* Face has 6 vertices */ 2301 break; 2302 case 10: /* quadratic tetrahedron */ 2303 *numFaceVertices = 6; /* Face has 6 vertices */ 2304 break; 2305 case 12: /* hex cohesive Lagrange cells */ 2306 *numFaceVertices = 6; /* Face has 6 vertices */ 2307 break; 2308 case 18: /* quadratic tet cohesive Lagrange cells */ 2309 *numFaceVertices = 6; /* Face has 6 vertices */ 2310 break; 2311 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 2312 *numFaceVertices = 9; /* Face has 9 vertices */ 2313 break; 2314 default: 2315 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim); 2316 } 2317 break; 2318 default: 2319 SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim); 2320 } 2321 PetscFunctionReturn(0); 2322 } 2323 2324 #undef __FUNCT__ 2325 #define __FUNCT__ "DMPlexOrient" 2326 /* Trys to give the mesh a consistent orientation */ 2327 PetscErrorCode DMPlexOrient(DM dm) 2328 { 2329 PetscBT seenCells, flippedCells, seenFaces; 2330 PetscInt *faceFIFO, fTop, fBottom; 2331 PetscInt dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO; 2332 PetscErrorCode ierr; 2333 2334 PetscFunctionBegin; 2335 /* Truth Table 2336 mismatch flips do action mismatch flipA ^ flipB action 2337 F 0 flips no F F F 2338 F 1 flip yes F T T 2339 F 2 flips no T F T 2340 T 0 flips yes T T F 2341 T 1 flip no 2342 T 2 flips yes 2343 */ 2344 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 2345 ierr = DMPlexGetVTKCellHeight(dm, &h);CHKERRQ(ierr); 2346 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 2347 ierr = DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);CHKERRQ(ierr); 2348 ierr = PetscBTCreate(cEnd - cStart, &seenCells);CHKERRQ(ierr); 2349 ierr = PetscBTMemzero(cEnd - cStart, seenCells);CHKERRQ(ierr); 2350 ierr = PetscBTCreate(cEnd - cStart, &flippedCells);CHKERRQ(ierr); 2351 ierr = PetscBTMemzero(cEnd - cStart, flippedCells);CHKERRQ(ierr); 2352 ierr = PetscBTCreate(fEnd - fStart, &seenFaces);CHKERRQ(ierr); 2353 ierr = PetscBTMemzero(fEnd - fStart, seenFaces);CHKERRQ(ierr); 2354 ierr = PetscMalloc1((fEnd - fStart), &faceFIFO);CHKERRQ(ierr); 2355 fTop = fBottom = 0; 2356 /* Initialize FIFO with first cell */ 2357 if (cEnd > cStart) { 2358 const PetscInt *cone; 2359 PetscInt coneSize; 2360 2361 ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr); 2362 ierr = DMPlexGetCone(dm, cStart, &cone);CHKERRQ(ierr); 2363 for (c = 0; c < coneSize; ++c) { 2364 faceFIFO[fBottom++] = cone[c]; 2365 ierr = PetscBTSet(seenFaces, cone[c]-fStart);CHKERRQ(ierr); 2366 } 2367 } 2368 /* Consider each face in FIFO */ 2369 while (fTop < fBottom) { 2370 const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB; 2371 PetscInt supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1; 2372 PetscInt seenA, flippedA, seenB, flippedB, mismatch; 2373 2374 face = faceFIFO[fTop++]; 2375 ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); 2376 ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr); 2377 if (supportSize < 2) continue; 2378 if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize); 2379 seenA = PetscBTLookup(seenCells, support[0]-cStart); 2380 flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0; 2381 seenB = PetscBTLookup(seenCells, support[1]-cStart); 2382 flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0; 2383 2384 ierr = DMPlexGetConeSize(dm, support[0], &coneSizeA);CHKERRQ(ierr); 2385 ierr = DMPlexGetConeSize(dm, support[1], &coneSizeB);CHKERRQ(ierr); 2386 ierr = DMPlexGetCone(dm, support[0], &coneA);CHKERRQ(ierr); 2387 ierr = DMPlexGetCone(dm, support[1], &coneB);CHKERRQ(ierr); 2388 ierr = DMPlexGetConeOrientation(dm, support[0], &coneOA);CHKERRQ(ierr); 2389 ierr = DMPlexGetConeOrientation(dm, support[1], &coneOB);CHKERRQ(ierr); 2390 for (c = 0; c < coneSizeA; ++c) { 2391 if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) { 2392 faceFIFO[fBottom++] = coneA[c]; 2393 ierr = PetscBTSet(seenFaces, coneA[c]-fStart);CHKERRQ(ierr); 2394 } 2395 if (coneA[c] == face) posA = c; 2396 if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart); 2397 } 2398 if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]); 2399 for (c = 0; c < coneSizeB; ++c) { 2400 if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) { 2401 faceFIFO[fBottom++] = coneB[c]; 2402 ierr = PetscBTSet(seenFaces, coneB[c]-fStart);CHKERRQ(ierr); 2403 } 2404 if (coneB[c] == face) posB = c; 2405 if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart); 2406 } 2407 if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]); 2408 2409 if (dim == 1) { 2410 mismatch = posA == posB; 2411 } else { 2412 mismatch = coneOA[posA] == coneOB[posB]; 2413 } 2414 2415 if (mismatch ^ (flippedA ^ flippedB)) { 2416 if (seenA && seenB) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen cells %d and %d do not match: Fault mesh is non-orientable", support[0], support[1]); 2417 if (!seenA && !flippedA) { 2418 ierr = PetscBTSet(flippedCells, support[0]-cStart);CHKERRQ(ierr); 2419 } else if (!seenB && !flippedB) { 2420 ierr = PetscBTSet(flippedCells, support[1]-cStart);CHKERRQ(ierr); 2421 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable"); 2422 } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable"); 2423 ierr = PetscBTSet(seenCells, support[0]-cStart);CHKERRQ(ierr); 2424 ierr = PetscBTSet(seenCells, support[1]-cStart);CHKERRQ(ierr); 2425 } 2426 /* Now all subdomains are oriented, but we need a consistent parallel orientation */ 2427 { 2428 /* Find a representative face (edge) separating pairs of procs */ 2429 PetscSF sf; 2430 const PetscInt *lpoints; 2431 const PetscSFNode *rpoints; 2432 PetscInt *neighbors, *nranks; 2433 PetscInt numLeaves, numRoots, numNeighbors = 0, l, n; 2434 2435 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 2436 ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &lpoints, &rpoints);CHKERRQ(ierr); 2437 if (numLeaves >= 0) { 2438 const PetscInt *cone, *ornt, *support; 2439 PetscInt coneSize, supportSize; 2440 int *rornt, *lornt; /* PetscSF cannot handle smaller than int */ 2441 PetscBool *match, flipped = PETSC_FALSE; 2442 2443 ierr = PetscMalloc1(numLeaves,&neighbors);CHKERRQ(ierr); 2444 /* I know this is p^2 time in general, but for bounded degree its alright */ 2445 for (l = 0; l < numLeaves; ++l) { 2446 const PetscInt face = lpoints[l]; 2447 if ((face >= fStart) && (face < fEnd)) { 2448 const PetscInt rank = rpoints[l].rank; 2449 for (n = 0; n < numNeighbors; ++n) if (rank == rpoints[neighbors[n]].rank) break; 2450 if (n >= numNeighbors) { 2451 PetscInt supportSize; 2452 ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); 2453 if (supportSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Boundary faces should see one cell, not %d", supportSize); 2454 neighbors[numNeighbors++] = l; 2455 } 2456 } 2457 } 2458 ierr = PetscCalloc4(numNeighbors,&match,numNeighbors,&nranks,numRoots,&rornt,numRoots,&lornt);CHKERRQ(ierr); 2459 for (face = fStart; face < fEnd; ++face) { 2460 ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr); 2461 if (supportSize != 1) continue; 2462 ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr); 2463 2464 ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); 2465 ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); 2466 ierr = DMPlexGetConeOrientation(dm, support[0], &ornt);CHKERRQ(ierr); 2467 for (c = 0; c < coneSize; ++c) if (cone[c] == face) break; 2468 if (dim == 1) { 2469 /* Use cone position instead, shifted to -1 or 1 */ 2470 rornt[face] = c*2-1; 2471 } else { 2472 if (PetscBTLookup(flippedCells, support[0]-cStart)) rornt[face] = ornt[c] < 0 ? -1 : 1; 2473 else rornt[face] = ornt[c] < 0 ? 1 : -1; 2474 } 2475 } 2476 /* Mark each edge with match or nomatch */ 2477 ierr = PetscSFBcastBegin(sf, MPI_INT, rornt, lornt);CHKERRQ(ierr); 2478 ierr = PetscSFBcastEnd(sf, MPI_INT, rornt, lornt);CHKERRQ(ierr); 2479 for (n = 0; n < numNeighbors; ++n) { 2480 const PetscInt face = lpoints[neighbors[n]]; 2481 2482 if (rornt[face]*lornt[face] < 0) match[n] = PETSC_TRUE; 2483 else match[n] = PETSC_FALSE; 2484 nranks[n] = rpoints[neighbors[n]].rank; 2485 } 2486 /* Collect the graph on 0 */ 2487 { 2488 MPI_Comm comm = PetscObjectComm((PetscObject) sf); 2489 PetscBT seenProcs, flippedProcs; 2490 PetscInt *procFIFO, pTop, pBottom; 2491 PetscInt *adj = NULL; 2492 PetscBool *val = NULL; 2493 PetscMPIInt *recvcounts = NULL, *displs = NULL, p; 2494 PetscMPIInt N = numNeighbors, numProcs = 0, rank; 2495 PetscInt debug = 0; 2496 2497 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 2498 if (!rank) {ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);} 2499 ierr = PetscCalloc2(numProcs,&recvcounts,numProcs+1,&displs);CHKERRQ(ierr); 2500 ierr = MPI_Gather(&N, 1, MPI_INT, recvcounts, 1, MPI_INT, 0, comm);CHKERRQ(ierr); 2501 for (p = 0; p < numProcs; ++p) { 2502 displs[p+1] = displs[p] + recvcounts[p]; 2503 } 2504 if (!rank) {ierr = PetscMalloc2(displs[numProcs],&adj,displs[numProcs],&val);CHKERRQ(ierr);} 2505 ierr = MPI_Gatherv(nranks, numNeighbors, MPIU_INT, adj, recvcounts, displs, MPIU_INT, 0, comm);CHKERRQ(ierr); 2506 ierr = MPI_Gatherv(match, numNeighbors, MPIU_BOOL, val, recvcounts, displs, MPIU_BOOL, 0, comm);CHKERRQ(ierr); 2507 if (debug) { 2508 for (p = 0; p < numProcs; ++p) { 2509 ierr = PetscPrintf(comm, "Proc %d:\n", p); 2510 for (n = 0; n < recvcounts[p]; ++n) { 2511 ierr = PetscPrintf(comm, " edge %d (%d):\n", adj[displs[p]+n], val[displs[p]+n]); 2512 } 2513 } 2514 } 2515 ierr = PetscBTCreate(numProcs, &seenProcs);CHKERRQ(ierr); 2516 ierr = PetscBTMemzero(numProcs, seenProcs);CHKERRQ(ierr); 2517 ierr = PetscBTCreate(numProcs, &flippedProcs);CHKERRQ(ierr); 2518 ierr = PetscBTMemzero(numProcs, flippedProcs);CHKERRQ(ierr); 2519 ierr = PetscMalloc1(numProcs,&procFIFO);CHKERRQ(ierr); 2520 pTop = pBottom = 0; 2521 for (p = 0; p < numProcs; ++p) { 2522 if (PetscBTLookup(seenProcs, p)) continue; 2523 /* Initialize FIFO with next proc */ 2524 procFIFO[pBottom++] = p; 2525 ierr = PetscBTSet(seenProcs, p);CHKERRQ(ierr); 2526 /* Consider each proc in FIFO */ 2527 while (pTop < pBottom) { 2528 PetscInt proc, nproc, seen, flippedA, flippedB, mismatch; 2529 2530 proc = procFIFO[pTop++]; 2531 flippedA = PetscBTLookup(flippedProcs, proc) ? 1 : 0; 2532 /* Loop over neighboring procs */ 2533 for (n = 0; n < recvcounts[proc]; ++n) { 2534 nproc = adj[displs[proc]+n]; 2535 mismatch = val[displs[proc]+n] ? 0 : 1; 2536 seen = PetscBTLookup(seenProcs, nproc); 2537 flippedB = PetscBTLookup(flippedProcs, nproc) ? 1 : 0; 2538 2539 if (mismatch ^ (flippedA ^ flippedB)) { 2540 if (seen) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Previously seen procs %d and %d do not match: Fault mesh is non-orientable", proc, nproc); 2541 if (!flippedB) { 2542 ierr = PetscBTSet(flippedProcs, nproc);CHKERRQ(ierr); 2543 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable"); 2544 } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable"); 2545 if (!seen) { 2546 procFIFO[pBottom++] = nproc; 2547 ierr = PetscBTSet(seenProcs, nproc);CHKERRQ(ierr); 2548 } 2549 } 2550 } 2551 } 2552 ierr = PetscFree(procFIFO);CHKERRQ(ierr); 2553 2554 ierr = PetscFree2(recvcounts,displs);CHKERRQ(ierr); 2555 ierr = PetscFree2(adj,val);CHKERRQ(ierr); 2556 { 2557 PetscBool *flips; 2558 2559 ierr = PetscMalloc1(numProcs,&flips);CHKERRQ(ierr); 2560 for (p = 0; p < numProcs; ++p) { 2561 flips[p] = PetscBTLookup(flippedProcs, p) ? PETSC_TRUE : PETSC_FALSE; 2562 if (debug && flips[p]) {ierr = PetscPrintf(comm, "Flipping Proc %d:\n", p);} 2563 } 2564 ierr = MPI_Scatter(flips, 1, MPIU_BOOL, &flipped, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr); 2565 ierr = PetscFree(flips);CHKERRQ(ierr); 2566 } 2567 ierr = PetscBTDestroy(&seenProcs);CHKERRQ(ierr); 2568 ierr = PetscBTDestroy(&flippedProcs);CHKERRQ(ierr); 2569 } 2570 ierr = PetscFree4(match,nranks,rornt,lornt);CHKERRQ(ierr); 2571 ierr = PetscFree(neighbors);CHKERRQ(ierr); 2572 if (flipped) {for (c = cStart; c < cEnd; ++c) {ierr = PetscBTNegate(flippedCells, c-cStart);CHKERRQ(ierr);}} 2573 } 2574 } 2575 /* Reverse flipped cells in the mesh */ 2576 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, NULL);CHKERRQ(ierr); 2577 ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr); 2578 ierr = DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr); 2579 for (c = cStart; c < cEnd; ++c) { 2580 const PetscInt *cone, *coneO, *support; 2581 PetscInt coneSize, supportSize, faceSize, cp, sp; 2582 2583 if (!PetscBTLookup(flippedCells, c-cStart)) continue; 2584 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 2585 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 2586 ierr = DMPlexGetConeOrientation(dm, c, &coneO);CHKERRQ(ierr); 2587 for (cp = 0; cp < coneSize; ++cp) { 2588 const PetscInt rcp = coneSize-cp-1; 2589 2590 ierr = DMPlexGetConeSize(dm, cone[rcp], &faceSize);CHKERRQ(ierr); 2591 revcone[cp] = cone[rcp]; 2592 revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp]; 2593 } 2594 ierr = DMPlexSetCone(dm, c, revcone);CHKERRQ(ierr); 2595 ierr = DMPlexSetConeOrientation(dm, c, revconeO);CHKERRQ(ierr); 2596 /* Reverse orientations of support */ 2597 faceSize = coneSize; 2598 ierr = DMPlexGetSupportSize(dm, c, &supportSize);CHKERRQ(ierr); 2599 ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr); 2600 for (sp = 0; sp < supportSize; ++sp) { 2601 ierr = DMPlexGetConeSize(dm, support[sp], &coneSize);CHKERRQ(ierr); 2602 ierr = DMPlexGetCone(dm, support[sp], &cone);CHKERRQ(ierr); 2603 ierr = DMPlexGetConeOrientation(dm, support[sp], &coneO);CHKERRQ(ierr); 2604 for (cp = 0; cp < coneSize; ++cp) { 2605 if (cone[cp] != c) continue; 2606 ierr = DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);CHKERRQ(ierr); 2607 } 2608 } 2609 } 2610 ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);CHKERRQ(ierr); 2611 ierr = DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);CHKERRQ(ierr); 2612 ierr = PetscBTDestroy(&seenCells);CHKERRQ(ierr); 2613 ierr = PetscBTDestroy(&flippedCells);CHKERRQ(ierr); 2614 ierr = PetscBTDestroy(&seenFaces);CHKERRQ(ierr); 2615 ierr = PetscFree(faceFIFO);CHKERRQ(ierr); 2616 PetscFunctionReturn(0); 2617 } 2618 2619 #undef __FUNCT__ 2620 #define __FUNCT__ "DMPlexInvertCell_Internal" 2621 PetscErrorCode DMPlexInvertCell_Internal(PetscInt dim, PetscInt numCorners, PetscInt cone[]) 2622 { 2623 int tmpc; 2624 2625 PetscFunctionBegin; 2626 if (dim != 3) PetscFunctionReturn(0); 2627 switch (numCorners) { 2628 case 4: 2629 tmpc = cone[0]; 2630 cone[0] = cone[1]; 2631 cone[1] = tmpc; 2632 break; 2633 case 8: 2634 tmpc = cone[1]; 2635 cone[1] = cone[3]; 2636 cone[3] = tmpc; 2637 break; 2638 default: break; 2639 } 2640 PetscFunctionReturn(0); 2641 } 2642 2643 #undef __FUNCT__ 2644 #define __FUNCT__ "DMPlexInvertCell" 2645 /*@C 2646 DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched. 2647 2648 Input Parameters: 2649 + numCorners - The number of vertices in a cell 2650 - cone - The incoming cone 2651 2652 Output Parameter: 2653 . cone - The inverted cone (in-place) 2654 2655 Level: developer 2656 2657 .seealso: DMPlexGenerate() 2658 @*/ 2659 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[]) 2660 { 2661 int tmpc; 2662 2663 PetscFunctionBegin; 2664 if (dim != 3) PetscFunctionReturn(0); 2665 switch (numCorners) { 2666 case 4: 2667 tmpc = cone[0]; 2668 cone[0] = cone[1]; 2669 cone[1] = tmpc; 2670 break; 2671 case 8: 2672 tmpc = cone[1]; 2673 cone[1] = cone[3]; 2674 cone[3] = tmpc; 2675 break; 2676 default: break; 2677 } 2678 PetscFunctionReturn(0); 2679 } 2680 2681 #undef __FUNCT__ 2682 #define __FUNCT__ "DMPlexInvertCells_Internal" 2683 /* This is to fix the tetrahedron orientation from TetGen */ 2684 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[]) 2685 { 2686 PetscInt bound = numCells*numCorners, coff; 2687 PetscErrorCode ierr; 2688 2689 PetscFunctionBegin; 2690 for (coff = 0; coff < bound; coff += numCorners) { 2691 ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr); 2692 } 2693 PetscFunctionReturn(0); 2694 } 2695 2696 #if defined(PETSC_HAVE_TRIANGLE) 2697 #include <triangle.h> 2698 2699 #undef __FUNCT__ 2700 #define __FUNCT__ "InitInput_Triangle" 2701 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) 2702 { 2703 PetscFunctionBegin; 2704 inputCtx->numberofpoints = 0; 2705 inputCtx->numberofpointattributes = 0; 2706 inputCtx->pointlist = NULL; 2707 inputCtx->pointattributelist = NULL; 2708 inputCtx->pointmarkerlist = NULL; 2709 inputCtx->numberofsegments = 0; 2710 inputCtx->segmentlist = NULL; 2711 inputCtx->segmentmarkerlist = NULL; 2712 inputCtx->numberoftriangleattributes = 0; 2713 inputCtx->trianglelist = NULL; 2714 inputCtx->numberofholes = 0; 2715 inputCtx->holelist = NULL; 2716 inputCtx->numberofregions = 0; 2717 inputCtx->regionlist = NULL; 2718 PetscFunctionReturn(0); 2719 } 2720 2721 #undef __FUNCT__ 2722 #define __FUNCT__ "InitOutput_Triangle" 2723 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) 2724 { 2725 PetscFunctionBegin; 2726 outputCtx->numberofpoints = 0; 2727 outputCtx->pointlist = NULL; 2728 outputCtx->pointattributelist = NULL; 2729 outputCtx->pointmarkerlist = NULL; 2730 outputCtx->numberoftriangles = 0; 2731 outputCtx->trianglelist = NULL; 2732 outputCtx->triangleattributelist = NULL; 2733 outputCtx->neighborlist = NULL; 2734 outputCtx->segmentlist = NULL; 2735 outputCtx->segmentmarkerlist = NULL; 2736 outputCtx->numberofedges = 0; 2737 outputCtx->edgelist = NULL; 2738 outputCtx->edgemarkerlist = NULL; 2739 PetscFunctionReturn(0); 2740 } 2741 2742 #undef __FUNCT__ 2743 #define __FUNCT__ "FiniOutput_Triangle" 2744 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) 2745 { 2746 PetscFunctionBegin; 2747 free(outputCtx->pointlist); 2748 free(outputCtx->pointmarkerlist); 2749 free(outputCtx->segmentlist); 2750 free(outputCtx->segmentmarkerlist); 2751 free(outputCtx->edgelist); 2752 free(outputCtx->edgemarkerlist); 2753 free(outputCtx->trianglelist); 2754 free(outputCtx->neighborlist); 2755 PetscFunctionReturn(0); 2756 } 2757 2758 #undef __FUNCT__ 2759 #define __FUNCT__ "DMPlexGenerate_Triangle" 2760 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm) 2761 { 2762 MPI_Comm comm; 2763 PetscInt dim = 2; 2764 const PetscBool createConvexHull = PETSC_FALSE; 2765 const PetscBool constrained = PETSC_FALSE; 2766 struct triangulateio in; 2767 struct triangulateio out; 2768 PetscInt vStart, vEnd, v, eStart, eEnd, e; 2769 PetscMPIInt rank; 2770 PetscErrorCode ierr; 2771 2772 PetscFunctionBegin; 2773 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 2774 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 2775 ierr = InitInput_Triangle(&in);CHKERRQ(ierr); 2776 ierr = InitOutput_Triangle(&out);CHKERRQ(ierr); 2777 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 2778 2779 in.numberofpoints = vEnd - vStart; 2780 if (in.numberofpoints > 0) { 2781 PetscSection coordSection; 2782 Vec coordinates; 2783 PetscScalar *array; 2784 2785 ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr); 2786 ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr); 2787 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 2788 ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 2789 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 2790 for (v = vStart; v < vEnd; ++v) { 2791 const PetscInt idx = v - vStart; 2792 PetscInt off, d; 2793 2794 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 2795 for (d = 0; d < dim; ++d) { 2796 in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 2797 } 2798 ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 2799 } 2800 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 2801 } 2802 ierr = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr); 2803 in.numberofsegments = eEnd - eStart; 2804 if (in.numberofsegments > 0) { 2805 ierr = PetscMalloc1(in.numberofsegments*2, &in.segmentlist);CHKERRQ(ierr); 2806 ierr = PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);CHKERRQ(ierr); 2807 for (e = eStart; e < eEnd; ++e) { 2808 const PetscInt idx = e - eStart; 2809 const PetscInt *cone; 2810 2811 ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr); 2812 2813 in.segmentlist[idx*2+0] = cone[0] - vStart; 2814 in.segmentlist[idx*2+1] = cone[1] - vStart; 2815 2816 ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr); 2817 } 2818 } 2819 #if 0 /* Do not currently support holes */ 2820 PetscReal *holeCoords; 2821 PetscInt h, d; 2822 2823 ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr); 2824 if (in.numberofholes > 0) { 2825 ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr); 2826 for (h = 0; h < in.numberofholes; ++h) { 2827 for (d = 0; d < dim; ++d) { 2828 in.holelist[h*dim+d] = holeCoords[h*dim+d]; 2829 } 2830 } 2831 } 2832 #endif 2833 if (!rank) { 2834 char args[32]; 2835 2836 /* Take away 'Q' for verbose output */ 2837 ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr); 2838 if (createConvexHull) { 2839 ierr = PetscStrcat(args, "c");CHKERRQ(ierr); 2840 } 2841 if (constrained) { 2842 ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr); 2843 } 2844 triangulate(args, &in, &out, NULL); 2845 } 2846 ierr = PetscFree(in.pointlist);CHKERRQ(ierr); 2847 ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr); 2848 ierr = PetscFree(in.segmentlist);CHKERRQ(ierr); 2849 ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr); 2850 ierr = PetscFree(in.holelist);CHKERRQ(ierr); 2851 2852 { 2853 const PetscInt numCorners = 3; 2854 const PetscInt numCells = out.numberoftriangles; 2855 const PetscInt numVertices = out.numberofpoints; 2856 const int *cells = out.trianglelist; 2857 const double *meshCoords = out.pointlist; 2858 2859 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 2860 /* Set labels */ 2861 for (v = 0; v < numVertices; ++v) { 2862 if (out.pointmarkerlist[v]) { 2863 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 2864 } 2865 } 2866 if (interpolate) { 2867 for (e = 0; e < out.numberofedges; e++) { 2868 if (out.edgemarkerlist[e]) { 2869 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 2870 const PetscInt *edges; 2871 PetscInt numEdges; 2872 2873 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 2874 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 2875 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 2876 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 2877 } 2878 } 2879 } 2880 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 2881 } 2882 #if 0 /* Do not currently support holes */ 2883 ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr); 2884 #endif 2885 ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr); 2886 PetscFunctionReturn(0); 2887 } 2888 2889 #undef __FUNCT__ 2890 #define __FUNCT__ "DMPlexRefine_Triangle" 2891 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined) 2892 { 2893 MPI_Comm comm; 2894 PetscInt dim = 2; 2895 struct triangulateio in; 2896 struct triangulateio out; 2897 PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 2898 PetscMPIInt rank; 2899 PetscErrorCode ierr; 2900 2901 PetscFunctionBegin; 2902 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 2903 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 2904 ierr = InitInput_Triangle(&in);CHKERRQ(ierr); 2905 ierr = InitOutput_Triangle(&out);CHKERRQ(ierr); 2906 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2907 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 2908 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 2909 2910 in.numberofpoints = vEnd - vStart; 2911 if (in.numberofpoints > 0) { 2912 PetscSection coordSection; 2913 Vec coordinates; 2914 PetscScalar *array; 2915 2916 ierr = PetscMalloc1(in.numberofpoints*dim, &in.pointlist);CHKERRQ(ierr); 2917 ierr = PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);CHKERRQ(ierr); 2918 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 2919 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 2920 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 2921 for (v = vStart; v < vEnd; ++v) { 2922 const PetscInt idx = v - vStart; 2923 PetscInt off, d; 2924 2925 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 2926 for (d = 0; d < dim; ++d) { 2927 in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 2928 } 2929 ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 2930 } 2931 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 2932 } 2933 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2934 2935 in.numberofcorners = 3; 2936 in.numberoftriangles = cEnd - cStart; 2937 2938 in.trianglearealist = (double*) maxVolumes; 2939 if (in.numberoftriangles > 0) { 2940 ierr = PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);CHKERRQ(ierr); 2941 for (c = cStart; c < cEnd; ++c) { 2942 const PetscInt idx = c - cStart; 2943 PetscInt *closure = NULL; 2944 PetscInt closureSize; 2945 2946 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 2947 if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize); 2948 for (v = 0; v < 3; ++v) { 2949 in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart; 2950 } 2951 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 2952 } 2953 } 2954 /* TODO: Segment markers are missing on input */ 2955 #if 0 /* Do not currently support holes */ 2956 PetscReal *holeCoords; 2957 PetscInt h, d; 2958 2959 ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr); 2960 if (in.numberofholes > 0) { 2961 ierr = PetscMalloc1(in.numberofholes*dim, &in.holelist);CHKERRQ(ierr); 2962 for (h = 0; h < in.numberofholes; ++h) { 2963 for (d = 0; d < dim; ++d) { 2964 in.holelist[h*dim+d] = holeCoords[h*dim+d]; 2965 } 2966 } 2967 } 2968 #endif 2969 if (!rank) { 2970 char args[32]; 2971 2972 /* Take away 'Q' for verbose output */ 2973 ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr); 2974 triangulate(args, &in, &out, NULL); 2975 } 2976 ierr = PetscFree(in.pointlist);CHKERRQ(ierr); 2977 ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr); 2978 ierr = PetscFree(in.segmentlist);CHKERRQ(ierr); 2979 ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr); 2980 ierr = PetscFree(in.trianglelist);CHKERRQ(ierr); 2981 2982 { 2983 const PetscInt numCorners = 3; 2984 const PetscInt numCells = out.numberoftriangles; 2985 const PetscInt numVertices = out.numberofpoints; 2986 const int *cells = out.trianglelist; 2987 const double *meshCoords = out.pointlist; 2988 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 2989 2990 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 2991 /* Set labels */ 2992 for (v = 0; v < numVertices; ++v) { 2993 if (out.pointmarkerlist[v]) { 2994 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 2995 } 2996 } 2997 if (interpolate) { 2998 PetscInt e; 2999 3000 for (e = 0; e < out.numberofedges; e++) { 3001 if (out.edgemarkerlist[e]) { 3002 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3003 const PetscInt *edges; 3004 PetscInt numEdges; 3005 3006 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3007 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3008 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3009 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3010 } 3011 } 3012 } 3013 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 3014 } 3015 #if 0 /* Do not currently support holes */ 3016 ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr); 3017 #endif 3018 ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr); 3019 PetscFunctionReturn(0); 3020 } 3021 #endif 3022 3023 #if defined(PETSC_HAVE_TETGEN) 3024 #include <tetgen.h> 3025 #undef __FUNCT__ 3026 #define __FUNCT__ "DMPlexGenerate_Tetgen" 3027 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm) 3028 { 3029 MPI_Comm comm; 3030 const PetscInt dim = 3; 3031 ::tetgenio in; 3032 ::tetgenio out; 3033 PetscInt vStart, vEnd, v, fStart, fEnd, f; 3034 PetscMPIInt rank; 3035 PetscErrorCode ierr; 3036 3037 PetscFunctionBegin; 3038 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 3039 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3040 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 3041 in.numberofpoints = vEnd - vStart; 3042 if (in.numberofpoints > 0) { 3043 PetscSection coordSection; 3044 Vec coordinates; 3045 PetscScalar *array; 3046 3047 in.pointlist = new double[in.numberofpoints*dim]; 3048 in.pointmarkerlist = new int[in.numberofpoints]; 3049 3050 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 3051 ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 3052 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3053 for (v = vStart; v < vEnd; ++v) { 3054 const PetscInt idx = v - vStart; 3055 PetscInt off, d; 3056 3057 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3058 for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d]; 3059 ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3060 } 3061 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3062 } 3063 ierr = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr); 3064 3065 in.numberoffacets = fEnd - fStart; 3066 if (in.numberoffacets > 0) { 3067 in.facetlist = new tetgenio::facet[in.numberoffacets]; 3068 in.facetmarkerlist = new int[in.numberoffacets]; 3069 for (f = fStart; f < fEnd; ++f) { 3070 const PetscInt idx = f - fStart; 3071 PetscInt *points = NULL, numPoints, p, numVertices = 0, v; 3072 3073 in.facetlist[idx].numberofpolygons = 1; 3074 in.facetlist[idx].polygonlist = new tetgenio::polygon[in.facetlist[idx].numberofpolygons]; 3075 in.facetlist[idx].numberofholes = 0; 3076 in.facetlist[idx].holelist = NULL; 3077 3078 ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3079 for (p = 0; p < numPoints*2; p += 2) { 3080 const PetscInt point = points[p]; 3081 if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point; 3082 } 3083 3084 tetgenio::polygon *poly = in.facetlist[idx].polygonlist; 3085 poly->numberofvertices = numVertices; 3086 poly->vertexlist = new int[poly->numberofvertices]; 3087 for (v = 0; v < numVertices; ++v) { 3088 const PetscInt vIdx = points[v] - vStart; 3089 poly->vertexlist[v] = vIdx; 3090 } 3091 ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr); 3092 ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3093 } 3094 } 3095 if (!rank) { 3096 char args[32]; 3097 3098 /* Take away 'Q' for verbose output */ 3099 ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr); 3100 ::tetrahedralize(args, &in, &out); 3101 } 3102 { 3103 const PetscInt numCorners = 4; 3104 const PetscInt numCells = out.numberoftetrahedra; 3105 const PetscInt numVertices = out.numberofpoints; 3106 const double *meshCoords = out.pointlist; 3107 int *cells = out.tetrahedronlist; 3108 3109 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3110 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 3111 /* Set labels */ 3112 for (v = 0; v < numVertices; ++v) { 3113 if (out.pointmarkerlist[v]) { 3114 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3115 } 3116 } 3117 if (interpolate) { 3118 PetscInt e; 3119 3120 for (e = 0; e < out.numberofedges; e++) { 3121 if (out.edgemarkerlist[e]) { 3122 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3123 const PetscInt *edges; 3124 PetscInt numEdges; 3125 3126 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3127 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3128 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3129 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3130 } 3131 } 3132 for (f = 0; f < out.numberoftrifaces; f++) { 3133 if (out.trifacemarkerlist[f]) { 3134 const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells}; 3135 const PetscInt *faces; 3136 PetscInt numFaces; 3137 3138 ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3139 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3140 ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr); 3141 ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3142 } 3143 } 3144 } 3145 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 3146 } 3147 PetscFunctionReturn(0); 3148 } 3149 3150 #undef __FUNCT__ 3151 #define __FUNCT__ "DMPlexRefine_Tetgen" 3152 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined) 3153 { 3154 MPI_Comm comm; 3155 const PetscInt dim = 3; 3156 ::tetgenio in; 3157 ::tetgenio out; 3158 PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 3159 PetscMPIInt rank; 3160 PetscErrorCode ierr; 3161 3162 PetscFunctionBegin; 3163 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3164 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3165 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3166 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 3167 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3168 3169 in.numberofpoints = vEnd - vStart; 3170 if (in.numberofpoints > 0) { 3171 PetscSection coordSection; 3172 Vec coordinates; 3173 PetscScalar *array; 3174 3175 in.pointlist = new double[in.numberofpoints*dim]; 3176 in.pointmarkerlist = new int[in.numberofpoints]; 3177 3178 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3179 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3180 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3181 for (v = vStart; v < vEnd; ++v) { 3182 const PetscInt idx = v - vStart; 3183 PetscInt off, d; 3184 3185 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3186 for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d]; 3187 ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3188 } 3189 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3190 } 3191 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3192 3193 in.numberofcorners = 4; 3194 in.numberoftetrahedra = cEnd - cStart; 3195 in.tetrahedronvolumelist = (double*) maxVolumes; 3196 if (in.numberoftetrahedra > 0) { 3197 in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners]; 3198 for (c = cStart; c < cEnd; ++c) { 3199 const PetscInt idx = c - cStart; 3200 PetscInt *closure = NULL; 3201 PetscInt closureSize; 3202 3203 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3204 if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize); 3205 for (v = 0; v < 4; ++v) { 3206 in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart; 3207 } 3208 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3209 } 3210 } 3211 /* TODO: Put in boundary faces with markers */ 3212 if (!rank) { 3213 char args[32]; 3214 3215 /* Take away 'Q' for verbose output */ 3216 /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */ 3217 ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr); 3218 ::tetrahedralize(args, &in, &out); 3219 } 3220 in.tetrahedronvolumelist = NULL; 3221 3222 { 3223 const PetscInt numCorners = 4; 3224 const PetscInt numCells = out.numberoftetrahedra; 3225 const PetscInt numVertices = out.numberofpoints; 3226 const double *meshCoords = out.pointlist; 3227 int *cells = out.tetrahedronlist; 3228 3229 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 3230 3231 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3232 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 3233 /* Set labels */ 3234 for (v = 0; v < numVertices; ++v) { 3235 if (out.pointmarkerlist[v]) { 3236 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3237 } 3238 } 3239 if (interpolate) { 3240 PetscInt e, f; 3241 3242 for (e = 0; e < out.numberofedges; e++) { 3243 if (out.edgemarkerlist[e]) { 3244 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3245 const PetscInt *edges; 3246 PetscInt numEdges; 3247 3248 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3249 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3250 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3251 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3252 } 3253 } 3254 for (f = 0; f < out.numberoftrifaces; f++) { 3255 if (out.trifacemarkerlist[f]) { 3256 const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells}; 3257 const PetscInt *faces; 3258 PetscInt numFaces; 3259 3260 ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3261 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3262 ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr); 3263 ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3264 } 3265 } 3266 } 3267 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 3268 } 3269 PetscFunctionReturn(0); 3270 } 3271 #endif 3272 3273 #if defined(PETSC_HAVE_CTETGEN) 3274 #include <ctetgen.h> 3275 3276 #undef __FUNCT__ 3277 #define __FUNCT__ "DMPlexGenerate_CTetgen" 3278 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm) 3279 { 3280 MPI_Comm comm; 3281 const PetscInt dim = 3; 3282 PLC *in, *out; 3283 PetscInt verbose = 0, vStart, vEnd, v, fStart, fEnd, f; 3284 PetscMPIInt rank; 3285 PetscErrorCode ierr; 3286 3287 PetscFunctionBegin; 3288 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 3289 ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr); 3290 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3291 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 3292 ierr = PLCCreate(&in);CHKERRQ(ierr); 3293 ierr = PLCCreate(&out);CHKERRQ(ierr); 3294 3295 in->numberofpoints = vEnd - vStart; 3296 if (in->numberofpoints > 0) { 3297 PetscSection coordSection; 3298 Vec coordinates; 3299 PetscScalar *array; 3300 3301 ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr); 3302 ierr = PetscMalloc1(in->numberofpoints, &in->pointmarkerlist);CHKERRQ(ierr); 3303 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 3304 ierr = DMGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 3305 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3306 for (v = vStart; v < vEnd; ++v) { 3307 const PetscInt idx = v - vStart; 3308 PetscInt off, d, m; 3309 3310 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3311 for (d = 0; d < dim; ++d) { 3312 in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 3313 } 3314 ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr); 3315 3316 in->pointmarkerlist[idx] = (int) m; 3317 } 3318 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3319 } 3320 ierr = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr); 3321 3322 in->numberoffacets = fEnd - fStart; 3323 if (in->numberoffacets > 0) { 3324 ierr = PetscMalloc1(in->numberoffacets, &in->facetlist);CHKERRQ(ierr); 3325 ierr = PetscMalloc1(in->numberoffacets, &in->facetmarkerlist);CHKERRQ(ierr); 3326 for (f = fStart; f < fEnd; ++f) { 3327 const PetscInt idx = f - fStart; 3328 PetscInt *points = NULL, numPoints, p, numVertices = 0, v, m; 3329 polygon *poly; 3330 3331 in->facetlist[idx].numberofpolygons = 1; 3332 3333 ierr = PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);CHKERRQ(ierr); 3334 3335 in->facetlist[idx].numberofholes = 0; 3336 in->facetlist[idx].holelist = NULL; 3337 3338 ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3339 for (p = 0; p < numPoints*2; p += 2) { 3340 const PetscInt point = points[p]; 3341 if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point; 3342 } 3343 3344 poly = in->facetlist[idx].polygonlist; 3345 poly->numberofvertices = numVertices; 3346 ierr = PetscMalloc1(poly->numberofvertices, &poly->vertexlist);CHKERRQ(ierr); 3347 for (v = 0; v < numVertices; ++v) { 3348 const PetscInt vIdx = points[v] - vStart; 3349 poly->vertexlist[v] = vIdx; 3350 } 3351 ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr); 3352 in->facetmarkerlist[idx] = (int) m; 3353 ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3354 } 3355 } 3356 if (!rank) { 3357 TetGenOpts t; 3358 3359 ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr); 3360 t.in = boundary; /* Should go away */ 3361 t.plc = 1; 3362 t.quality = 1; 3363 t.edgesout = 1; 3364 t.zeroindex = 1; 3365 t.quiet = 1; 3366 t.verbose = verbose; 3367 ierr = TetGenCheckOpts(&t);CHKERRQ(ierr); 3368 ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr); 3369 } 3370 { 3371 const PetscInt numCorners = 4; 3372 const PetscInt numCells = out->numberoftetrahedra; 3373 const PetscInt numVertices = out->numberofpoints; 3374 const double *meshCoords = out->pointlist; 3375 int *cells = out->tetrahedronlist; 3376 3377 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3378 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 3379 /* Set labels */ 3380 for (v = 0; v < numVertices; ++v) { 3381 if (out->pointmarkerlist[v]) { 3382 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr); 3383 } 3384 } 3385 if (interpolate) { 3386 PetscInt e; 3387 3388 for (e = 0; e < out->numberofedges; e++) { 3389 if (out->edgemarkerlist[e]) { 3390 const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells}; 3391 const PetscInt *edges; 3392 PetscInt numEdges; 3393 3394 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3395 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3396 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr); 3397 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3398 } 3399 } 3400 for (f = 0; f < out->numberoftrifaces; f++) { 3401 if (out->trifacemarkerlist[f]) { 3402 const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells}; 3403 const PetscInt *faces; 3404 PetscInt numFaces; 3405 3406 ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3407 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3408 ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr); 3409 ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3410 } 3411 } 3412 } 3413 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 3414 } 3415 3416 ierr = PLCDestroy(&in);CHKERRQ(ierr); 3417 ierr = PLCDestroy(&out);CHKERRQ(ierr); 3418 PetscFunctionReturn(0); 3419 } 3420 3421 #undef __FUNCT__ 3422 #define __FUNCT__ "DMPlexRefine_CTetgen" 3423 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined) 3424 { 3425 MPI_Comm comm; 3426 const PetscInt dim = 3; 3427 PLC *in, *out; 3428 PetscInt verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 3429 PetscMPIInt rank; 3430 PetscErrorCode ierr; 3431 3432 PetscFunctionBegin; 3433 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3434 ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr); 3435 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3436 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3437 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 3438 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3439 ierr = PLCCreate(&in);CHKERRQ(ierr); 3440 ierr = PLCCreate(&out);CHKERRQ(ierr); 3441 3442 in->numberofpoints = vEnd - vStart; 3443 if (in->numberofpoints > 0) { 3444 PetscSection coordSection; 3445 Vec coordinates; 3446 PetscScalar *array; 3447 3448 ierr = PetscMalloc1(in->numberofpoints*dim, &in->pointlist);CHKERRQ(ierr); 3449 ierr = PetscMalloc1(in->numberofpoints, &in->pointmarkerlist);CHKERRQ(ierr); 3450 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3451 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3452 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3453 for (v = vStart; v < vEnd; ++v) { 3454 const PetscInt idx = v - vStart; 3455 PetscInt off, d, m; 3456 3457 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3458 for (d = 0; d < dim; ++d) { 3459 in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 3460 } 3461 ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr); 3462 3463 in->pointmarkerlist[idx] = (int) m; 3464 } 3465 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3466 } 3467 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3468 3469 in->numberofcorners = 4; 3470 in->numberoftetrahedra = cEnd - cStart; 3471 in->tetrahedronvolumelist = maxVolumes; 3472 if (in->numberoftetrahedra > 0) { 3473 ierr = PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);CHKERRQ(ierr); 3474 for (c = cStart; c < cEnd; ++c) { 3475 const PetscInt idx = c - cStart; 3476 PetscInt *closure = NULL; 3477 PetscInt closureSize; 3478 3479 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3480 if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize); 3481 for (v = 0; v < 4; ++v) { 3482 in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart; 3483 } 3484 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3485 } 3486 } 3487 if (!rank) { 3488 TetGenOpts t; 3489 3490 ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr); 3491 3492 t.in = dm; /* Should go away */ 3493 t.refine = 1; 3494 t.varvolume = 1; 3495 t.quality = 1; 3496 t.edgesout = 1; 3497 t.zeroindex = 1; 3498 t.quiet = 1; 3499 t.verbose = verbose; /* Change this */ 3500 3501 ierr = TetGenCheckOpts(&t);CHKERRQ(ierr); 3502 ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr); 3503 } 3504 { 3505 const PetscInt numCorners = 4; 3506 const PetscInt numCells = out->numberoftetrahedra; 3507 const PetscInt numVertices = out->numberofpoints; 3508 const double *meshCoords = out->pointlist; 3509 int *cells = out->tetrahedronlist; 3510 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 3511 3512 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3513 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 3514 /* Set labels */ 3515 for (v = 0; v < numVertices; ++v) { 3516 if (out->pointmarkerlist[v]) { 3517 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr); 3518 } 3519 } 3520 if (interpolate) { 3521 PetscInt e, f; 3522 3523 for (e = 0; e < out->numberofedges; e++) { 3524 if (out->edgemarkerlist[e]) { 3525 const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells}; 3526 const PetscInt *edges; 3527 PetscInt numEdges; 3528 3529 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3530 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3531 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr); 3532 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3533 } 3534 } 3535 for (f = 0; f < out->numberoftrifaces; f++) { 3536 if (out->trifacemarkerlist[f]) { 3537 const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells}; 3538 const PetscInt *faces; 3539 PetscInt numFaces; 3540 3541 ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3542 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3543 ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr); 3544 ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3545 } 3546 } 3547 } 3548 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 3549 } 3550 ierr = PLCDestroy(&in);CHKERRQ(ierr); 3551 ierr = PLCDestroy(&out);CHKERRQ(ierr); 3552 PetscFunctionReturn(0); 3553 } 3554 #endif 3555 3556 #undef __FUNCT__ 3557 #define __FUNCT__ "DMPlexGenerate" 3558 /*@C 3559 DMPlexGenerate - Generates a mesh. 3560 3561 Not Collective 3562 3563 Input Parameters: 3564 + boundary - The DMPlex boundary object 3565 . name - The mesh generation package name 3566 - interpolate - Flag to create intermediate mesh elements 3567 3568 Output Parameter: 3569 . mesh - The DMPlex object 3570 3571 Level: intermediate 3572 3573 .keywords: mesh, elements 3574 .seealso: DMPlexCreate(), DMRefine() 3575 @*/ 3576 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh) 3577 { 3578 PetscInt dim; 3579 char genname[1024]; 3580 PetscBool isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg; 3581 PetscErrorCode ierr; 3582 3583 PetscFunctionBegin; 3584 PetscValidHeaderSpecific(boundary, DM_CLASSID, 1); 3585 PetscValidLogicalCollectiveBool(boundary, interpolate, 2); 3586 ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr); 3587 ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr); 3588 if (flg) name = genname; 3589 if (name) { 3590 ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr); 3591 ierr = PetscStrcmp(name, "tetgen", &isTetgen);CHKERRQ(ierr); 3592 ierr = PetscStrcmp(name, "ctetgen", &isCTetgen);CHKERRQ(ierr); 3593 } 3594 switch (dim) { 3595 case 1: 3596 if (!name || isTriangle) { 3597 #if defined(PETSC_HAVE_TRIANGLE) 3598 ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr); 3599 #else 3600 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle."); 3601 #endif 3602 } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name); 3603 break; 3604 case 2: 3605 if (!name || isCTetgen) { 3606 #if defined(PETSC_HAVE_CTETGEN) 3607 ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr); 3608 #else 3609 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen."); 3610 #endif 3611 } else if (isTetgen) { 3612 #if defined(PETSC_HAVE_TETGEN) 3613 ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr); 3614 #else 3615 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen."); 3616 #endif 3617 } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name); 3618 break; 3619 default: 3620 SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim); 3621 } 3622 PetscFunctionReturn(0); 3623 } 3624 3625 #undef __FUNCT__ 3626 #define __FUNCT__ "DMRefine_Plex" 3627 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined) 3628 { 3629 PetscReal refinementLimit; 3630 PetscInt dim, cStart, cEnd; 3631 char genname[1024], *name = NULL; 3632 PetscBool isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg; 3633 PetscErrorCode ierr; 3634 3635 PetscFunctionBegin; 3636 ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr); 3637 if (isUniform) { 3638 CellRefiner cellRefiner; 3639 3640 ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr); 3641 ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr); 3642 PetscFunctionReturn(0); 3643 } 3644 ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr); 3645 if (refinementLimit == 0.0) PetscFunctionReturn(0); 3646 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 3647 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3648 ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr); 3649 if (flg) name = genname; 3650 if (name) { 3651 ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr); 3652 ierr = PetscStrcmp(name, "tetgen", &isTetgen);CHKERRQ(ierr); 3653 ierr = PetscStrcmp(name, "ctetgen", &isCTetgen);CHKERRQ(ierr); 3654 } 3655 switch (dim) { 3656 case 2: 3657 if (!name || isTriangle) { 3658 #if defined(PETSC_HAVE_TRIANGLE) 3659 double *maxVolumes; 3660 PetscInt c; 3661 3662 ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr); 3663 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 3664 ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 3665 ierr = PetscFree(maxVolumes);CHKERRQ(ierr); 3666 #else 3667 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle."); 3668 #endif 3669 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name); 3670 break; 3671 case 3: 3672 if (!name || isCTetgen) { 3673 #if defined(PETSC_HAVE_CTETGEN) 3674 PetscReal *maxVolumes; 3675 PetscInt c; 3676 3677 ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr); 3678 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 3679 ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 3680 #else 3681 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen."); 3682 #endif 3683 } else if (isTetgen) { 3684 #if defined(PETSC_HAVE_TETGEN) 3685 double *maxVolumes; 3686 PetscInt c; 3687 3688 ierr = PetscMalloc1((cEnd - cStart), &maxVolumes);CHKERRQ(ierr); 3689 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 3690 ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 3691 #else 3692 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen."); 3693 #endif 3694 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name); 3695 break; 3696 default: 3697 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim); 3698 } 3699 PetscFunctionReturn(0); 3700 } 3701 3702 #undef __FUNCT__ 3703 #define __FUNCT__ "DMRefineHierarchy_Plex" 3704 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[]) 3705 { 3706 DM cdm = dm; 3707 PetscInt r; 3708 PetscBool isUniform; 3709 PetscErrorCode ierr; 3710 3711 PetscFunctionBegin; 3712 ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr); 3713 if (!isUniform) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Non-uniform refinement is incompatible with the hierarchy"); 3714 for (r = 0; r < nlevels; ++r) { 3715 CellRefiner cellRefiner; 3716 3717 ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr); 3718 ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr); 3719 ierr = DMPlexSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr); 3720 cdm = dmRefined[r]; 3721 } 3722 PetscFunctionReturn(0); 3723 } 3724 3725 #undef __FUNCT__ 3726 #define __FUNCT__ "DMCoarsen_Plex" 3727 PetscErrorCode DMCoarsen_Plex(DM dm, MPI_Comm comm, DM *dmCoarsened) 3728 { 3729 DM_Plex *mesh = (DM_Plex*) dm->data; 3730 PetscErrorCode ierr; 3731 3732 PetscFunctionBegin; 3733 ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr); 3734 *dmCoarsened = mesh->coarseMesh; 3735 PetscFunctionReturn(0); 3736 } 3737 3738 #undef __FUNCT__ 3739 #define __FUNCT__ "DMPlexLocalizeCoordinate_Internal" 3740 PetscErrorCode DMPlexLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 3741 { 3742 PetscInt d; 3743 3744 PetscFunctionBegin; 3745 if (!dm->maxCell) { 3746 for (d = 0; d < dim; ++d) out[d] = in[d]; 3747 } else { 3748 for (d = 0; d < dim; ++d) { 3749 if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) { 3750 out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 3751 } else { 3752 out[d] = in[d]; 3753 } 3754 } 3755 } 3756 PetscFunctionReturn(0); 3757 } 3758 3759 #undef __FUNCT__ 3760 #define __FUNCT__ "DMPlexLocalizeAddCoordinate_Internal" 3761 PetscErrorCode DMPlexLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 3762 { 3763 PetscInt d; 3764 3765 PetscFunctionBegin; 3766 if (!dm->maxCell) { 3767 for (d = 0; d < dim; ++d) out[d] += in[d]; 3768 } else { 3769 for (d = 0; d < dim; ++d) { 3770 if (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d]) { 3771 out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 3772 } else { 3773 out[d] += in[d]; 3774 } 3775 } 3776 } 3777 PetscFunctionReturn(0); 3778 } 3779 3780 #undef __FUNCT__ 3781 #define __FUNCT__ "DMPlexLocalizeCoordinates" 3782 PetscErrorCode DMPlexLocalizeCoordinates(DM dm) 3783 { 3784 PetscSection coordSection, cSection; 3785 Vec coordinates, cVec; 3786 PetscScalar *coords, *coords2, *anchor; 3787 PetscInt cStart, cEnd, c, vStart, vEnd, v, dof, d, off, off2, bs, coordSize; 3788 PetscErrorCode ierr; 3789 3790 PetscFunctionBegin; 3791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3792 if (!dm->maxCell) PetscFunctionReturn(0); 3793 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3794 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3795 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3796 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3797 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr); 3798 ierr = PetscSectionSetChart(cSection, cStart, vEnd);CHKERRQ(ierr); 3799 for (v = vStart; v < vEnd; ++v) { 3800 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 3801 ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr); 3802 } 3803 for (c = cStart; c < cEnd; ++c) { 3804 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, NULL);CHKERRQ(ierr); 3805 ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr); 3806 } 3807 ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr); 3808 ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr); 3809 ierr = VecCreate(PetscObjectComm((PetscObject) dm), &cVec);CHKERRQ(ierr); 3810 ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr); 3811 ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr); 3812 ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr); 3813 ierr = VecSetType(cVec,VECSTANDARD);CHKERRQ(ierr); 3814 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 3815 ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr); 3816 for (v = vStart; v < vEnd; ++v) { 3817 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 3818 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3819 ierr = PetscSectionGetOffset(cSection, v, &off2);CHKERRQ(ierr); 3820 for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d]; 3821 } 3822 ierr = DMGetWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr); 3823 for (c = cStart; c < cEnd; ++c) { 3824 PetscScalar *cellCoords = NULL; 3825 PetscInt b; 3826 3827 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr); 3828 ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr); 3829 for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b]; 3830 for (d = 0; d < dof/bs; ++d) {ierr = DMPlexLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);} 3831 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr); 3832 } 3833 ierr = DMRestoreWorkArray(dm, 3, PETSC_SCALAR, &anchor);CHKERRQ(ierr); 3834 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 3835 ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr); 3836 ierr = DMSetCoordinateSection(dm, cSection);CHKERRQ(ierr); 3837 ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr); 3838 ierr = VecDestroy(&cVec);CHKERRQ(ierr); 3839 ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr); 3840 PetscFunctionReturn(0); 3841 } 3842 3843 #undef __FUNCT__ 3844 #define __FUNCT__ "DMPlexGetDepthLabel" 3845 /*@ 3846 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 3847 3848 Not Collective 3849 3850 Input Parameter: 3851 . dm - The DMPlex object 3852 3853 Output Parameter: 3854 . depthLabel - The DMLabel recording point depth 3855 3856 Level: developer 3857 3858 .keywords: mesh, points 3859 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 3860 @*/ 3861 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 3862 { 3863 DM_Plex *mesh = (DM_Plex*) dm->data; 3864 PetscErrorCode ierr; 3865 3866 PetscFunctionBegin; 3867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3868 PetscValidPointer(depthLabel, 2); 3869 if (!mesh->depthLabel) {ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);} 3870 *depthLabel = mesh->depthLabel; 3871 PetscFunctionReturn(0); 3872 } 3873 3874 #undef __FUNCT__ 3875 #define __FUNCT__ "DMPlexGetDepth" 3876 /*@ 3877 DMPlexGetDepth - Get the depth of the DAG representing this mesh 3878 3879 Not Collective 3880 3881 Input Parameter: 3882 . dm - The DMPlex object 3883 3884 Output Parameter: 3885 . depth - The number of strata (breadth first levels) in the DAG 3886 3887 Level: developer 3888 3889 .keywords: mesh, points 3890 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 3891 @*/ 3892 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 3893 { 3894 DMLabel label; 3895 PetscInt d = 0; 3896 PetscErrorCode ierr; 3897 3898 PetscFunctionBegin; 3899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3900 PetscValidPointer(depth, 2); 3901 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3902 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 3903 *depth = d-1; 3904 PetscFunctionReturn(0); 3905 } 3906 3907 #undef __FUNCT__ 3908 #define __FUNCT__ "DMPlexGetDepthStratum" 3909 /*@ 3910 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 3911 3912 Not Collective 3913 3914 Input Parameters: 3915 + dm - The DMPlex object 3916 - stratumValue - The requested depth 3917 3918 Output Parameters: 3919 + start - The first point at this depth 3920 - end - One beyond the last point at this depth 3921 3922 Level: developer 3923 3924 .keywords: mesh, points 3925 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth() 3926 @*/ 3927 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3928 { 3929 DMLabel label; 3930 PetscInt pStart, pEnd; 3931 PetscErrorCode ierr; 3932 3933 PetscFunctionBegin; 3934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3935 if (start) {PetscValidPointer(start, 3); *start = 0;} 3936 if (end) {PetscValidPointer(end, 4); *end = 0;} 3937 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3938 if (pStart == pEnd) PetscFunctionReturn(0); 3939 if (stratumValue < 0) { 3940 if (start) *start = pStart; 3941 if (end) *end = pEnd; 3942 PetscFunctionReturn(0); 3943 } 3944 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3945 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 3946 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 3947 PetscFunctionReturn(0); 3948 } 3949 3950 #undef __FUNCT__ 3951 #define __FUNCT__ "DMPlexGetHeightStratum" 3952 /*@ 3953 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 3954 3955 Not Collective 3956 3957 Input Parameters: 3958 + dm - The DMPlex object 3959 - stratumValue - The requested height 3960 3961 Output Parameters: 3962 + start - The first point at this height 3963 - end - One beyond the last point at this height 3964 3965 Level: developer 3966 3967 .keywords: mesh, points 3968 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth() 3969 @*/ 3970 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 3971 { 3972 DMLabel label; 3973 PetscInt depth, pStart, pEnd; 3974 PetscErrorCode ierr; 3975 3976 PetscFunctionBegin; 3977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3978 if (start) {PetscValidPointer(start, 3); *start = 0;} 3979 if (end) {PetscValidPointer(end, 4); *end = 0;} 3980 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3981 if (pStart == pEnd) PetscFunctionReturn(0); 3982 if (stratumValue < 0) { 3983 if (start) *start = pStart; 3984 if (end) *end = pEnd; 3985 PetscFunctionReturn(0); 3986 } 3987 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 3988 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr); 3989 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 3990 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 3991 PetscFunctionReturn(0); 3992 } 3993 3994 #undef __FUNCT__ 3995 #define __FUNCT__ "DMPlexCreateSectionInitial" 3996 /* Set the number of dof on each point and separate by fields */ 3997 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) 3998 { 3999 PetscInt *numDofTot; 4000 PetscInt depth, pStart = 0, pEnd = 0; 4001 PetscInt p, d, dep, f; 4002 PetscErrorCode ierr; 4003 4004 PetscFunctionBegin; 4005 ierr = PetscMalloc1((dim+1), &numDofTot);CHKERRQ(ierr); 4006 for (d = 0; d <= dim; ++d) { 4007 numDofTot[d] = 0; 4008 for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d]; 4009 } 4010 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); 4011 if (numFields > 0) { 4012 ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr); 4013 if (numComp) { 4014 for (f = 0; f < numFields; ++f) { 4015 ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr); 4016 } 4017 } 4018 } 4019 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4020 ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr); 4021 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4022 for (dep = 0; dep <= depth; ++dep) { 4023 d = dim == depth ? dep : (!dep ? 0 : dim); 4024 ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr); 4025 for (p = pStart; p < pEnd; ++p) { 4026 for (f = 0; f < numFields; ++f) { 4027 ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr); 4028 } 4029 ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr); 4030 } 4031 } 4032 ierr = PetscFree(numDofTot);CHKERRQ(ierr); 4033 PetscFunctionReturn(0); 4034 } 4035 4036 #undef __FUNCT__ 4037 #define __FUNCT__ "DMPlexCreateSectionBCDof" 4038 /* Set the number of dof on each point and separate by fields 4039 If constDof is PETSC_DETERMINE, constrain every dof on the point 4040 */ 4041 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) 4042 { 4043 PetscInt numFields; 4044 PetscInt bc; 4045 PetscErrorCode ierr; 4046 4047 PetscFunctionBegin; 4048 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4049 for (bc = 0; bc < numBC; ++bc) { 4050 PetscInt field = 0; 4051 const PetscInt *idx; 4052 PetscInt n, i; 4053 4054 if (numFields) field = bcField[bc]; 4055 ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr); 4056 ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 4057 for (i = 0; i < n; ++i) { 4058 const PetscInt p = idx[i]; 4059 PetscInt numConst = constDof; 4060 4061 /* Constrain every dof on the point */ 4062 if (numConst < 0) { 4063 if (numFields) { 4064 ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr); 4065 } else { 4066 ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr); 4067 } 4068 } 4069 if (numFields) { 4070 ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr); 4071 } 4072 ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr); 4073 } 4074 ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 4075 } 4076 PetscFunctionReturn(0); 4077 } 4078 4079 #undef __FUNCT__ 4080 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll" 4081 /* Set the constrained indices on each point and separate by fields */ 4082 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) 4083 { 4084 PetscInt *maxConstraints; 4085 PetscInt numFields, f, pStart = 0, pEnd = 0, p; 4086 PetscErrorCode ierr; 4087 4088 PetscFunctionBegin; 4089 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4090 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4091 ierr = PetscMalloc1((numFields+1), &maxConstraints);CHKERRQ(ierr); 4092 for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0; 4093 for (p = pStart; p < pEnd; ++p) { 4094 PetscInt cdof; 4095 4096 if (numFields) { 4097 for (f = 0; f < numFields; ++f) { 4098 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr); 4099 maxConstraints[f] = PetscMax(maxConstraints[f], cdof); 4100 } 4101 } else { 4102 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4103 maxConstraints[0] = PetscMax(maxConstraints[0], cdof); 4104 } 4105 } 4106 for (f = 0; f < numFields; ++f) { 4107 maxConstraints[numFields] += maxConstraints[f]; 4108 } 4109 if (maxConstraints[numFields]) { 4110 PetscInt *indices; 4111 4112 ierr = PetscMalloc1(maxConstraints[numFields], &indices);CHKERRQ(ierr); 4113 for (p = pStart; p < pEnd; ++p) { 4114 PetscInt cdof, d; 4115 4116 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4117 if (cdof) { 4118 if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]); 4119 if (numFields) { 4120 PetscInt numConst = 0, foff = 0; 4121 4122 for (f = 0; f < numFields; ++f) { 4123 PetscInt cfdof, fdof; 4124 4125 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 4126 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr); 4127 /* Change constraint numbering from absolute local dof number to field relative local dof number */ 4128 for (d = 0; d < cfdof; ++d) indices[numConst+d] = d; 4129 ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr); 4130 for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff; 4131 numConst += cfdof; 4132 foff += fdof; 4133 } 4134 if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof); 4135 } else { 4136 for (d = 0; d < cdof; ++d) indices[d] = d; 4137 } 4138 ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr); 4139 } 4140 } 4141 ierr = PetscFree(indices);CHKERRQ(ierr); 4142 } 4143 ierr = PetscFree(maxConstraints);CHKERRQ(ierr); 4144 PetscFunctionReturn(0); 4145 } 4146 4147 #undef __FUNCT__ 4148 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField" 4149 /* Set the constrained field indices on each point */ 4150 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) 4151 { 4152 const PetscInt *points, *indices; 4153 PetscInt numFields, maxDof, numPoints, p, numConstraints; 4154 PetscErrorCode ierr; 4155 4156 PetscFunctionBegin; 4157 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4158 if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields); 4159 4160 ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr); 4161 ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr); 4162 if (!constraintIndices) { 4163 PetscInt *idx, i; 4164 4165 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 4166 ierr = PetscMalloc1(maxDof, &idx);CHKERRQ(ierr); 4167 for (i = 0; i < maxDof; ++i) idx[i] = i; 4168 for (p = 0; p < numPoints; ++p) { 4169 ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr); 4170 } 4171 ierr = PetscFree(idx);CHKERRQ(ierr); 4172 } else { 4173 ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr); 4174 ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr); 4175 for (p = 0; p < numPoints; ++p) { 4176 PetscInt fcdof; 4177 4178 ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr); 4179 if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints); 4180 ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr); 4181 } 4182 ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr); 4183 } 4184 ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr); 4185 PetscFunctionReturn(0); 4186 } 4187 4188 #undef __FUNCT__ 4189 #define __FUNCT__ "DMPlexCreateSectionBCIndices" 4190 /* Set the constrained indices on each point and separate by fields */ 4191 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) 4192 { 4193 PetscInt *indices; 4194 PetscInt numFields, maxDof, f, pStart = 0, pEnd = 0, p; 4195 PetscErrorCode ierr; 4196 4197 PetscFunctionBegin; 4198 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 4199 ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr); 4200 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4201 if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices."); 4202 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4203 for (p = pStart; p < pEnd; ++p) { 4204 PetscInt cdof, d; 4205 4206 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4207 if (cdof) { 4208 PetscInt numConst = 0, foff = 0; 4209 4210 for (f = 0; f < numFields; ++f) { 4211 const PetscInt *fcind; 4212 PetscInt fdof, fcdof; 4213 4214 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 4215 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 4216 if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);} 4217 /* Change constraint numbering from field relative local dof number to absolute local dof number */ 4218 for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff; 4219 foff += fdof; 4220 numConst += fcdof; 4221 } 4222 if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof); 4223 ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr); 4224 } 4225 } 4226 ierr = PetscFree(indices);CHKERRQ(ierr); 4227 PetscFunctionReturn(0); 4228 } 4229 4230 #undef __FUNCT__ 4231 #define __FUNCT__ "DMPlexCreateSection" 4232 /*@C 4233 DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided. 4234 4235 Not Collective 4236 4237 Input Parameters: 4238 + dm - The DMPlex object 4239 . dim - The spatial dimension of the problem 4240 . numFields - The number of fields in the problem 4241 . numComp - An array of size numFields that holds the number of components for each field 4242 . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d 4243 . numBC - The number of boundary conditions 4244 . bcField - An array of size numBC giving the field number for each boundry condition 4245 . bcPoints - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies 4246 - perm - Optional permutation of the chart, or NULL 4247 4248 Output Parameter: 4249 . section - The PetscSection object 4250 4251 Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the 4252 number of dof for field 0 on each edge. 4253 4254 The chart permutation is the same one set using PetscSectionSetPermutation() 4255 4256 Level: developer 4257 4258 Fortran Notes: 4259 A Fortran 90 version is available as DMPlexCreateSectionF90() 4260 4261 .keywords: mesh, elements 4262 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation() 4263 @*/ 4264 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], IS perm, PetscSection *section) 4265 { 4266 PetscErrorCode ierr; 4267 4268 PetscFunctionBegin; 4269 ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr); 4270 ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr); 4271 if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);} 4272 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 4273 if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);} 4274 ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr); 4275 PetscFunctionReturn(0); 4276 } 4277 4278 #undef __FUNCT__ 4279 #define __FUNCT__ "DMCreateCoordinateDM_Plex" 4280 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 4281 { 4282 PetscSection section; 4283 PetscErrorCode ierr; 4284 4285 PetscFunctionBegin; 4286 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 4287 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 4288 ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr); 4289 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 4290 PetscFunctionReturn(0); 4291 } 4292 4293 #undef __FUNCT__ 4294 #define __FUNCT__ "DMPlexGetConeSection" 4295 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 4296 { 4297 DM_Plex *mesh = (DM_Plex*) dm->data; 4298 4299 PetscFunctionBegin; 4300 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4301 if (section) *section = mesh->coneSection; 4302 PetscFunctionReturn(0); 4303 } 4304 4305 #undef __FUNCT__ 4306 #define __FUNCT__ "DMPlexGetSupportSection" 4307 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 4308 { 4309 DM_Plex *mesh = (DM_Plex*) dm->data; 4310 4311 PetscFunctionBegin; 4312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4313 if (section) *section = mesh->supportSection; 4314 PetscFunctionReturn(0); 4315 } 4316 4317 #undef __FUNCT__ 4318 #define __FUNCT__ "DMPlexGetCones" 4319 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 4320 { 4321 DM_Plex *mesh = (DM_Plex*) dm->data; 4322 4323 PetscFunctionBegin; 4324 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4325 if (cones) *cones = mesh->cones; 4326 PetscFunctionReturn(0); 4327 } 4328 4329 #undef __FUNCT__ 4330 #define __FUNCT__ "DMPlexGetConeOrientations" 4331 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 4332 { 4333 DM_Plex *mesh = (DM_Plex*) dm->data; 4334 4335 PetscFunctionBegin; 4336 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4337 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 4338 PetscFunctionReturn(0); 4339 } 4340 4341 /******************************** FEM Support **********************************/ 4342 4343 #undef __FUNCT__ 4344 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static" 4345 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4346 { 4347 PetscScalar *array, *vArray; 4348 const PetscInt *cone, *coneO; 4349 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 4350 PetscErrorCode ierr; 4351 4352 PetscFunctionBeginHot; 4353 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4354 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4355 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4356 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4357 if (!values || !*values) { 4358 if ((point >= pStart) && (point < pEnd)) { 4359 PetscInt dof; 4360 4361 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4362 size += dof; 4363 } 4364 for (p = 0; p < numPoints; ++p) { 4365 const PetscInt cp = cone[p]; 4366 PetscInt dof; 4367 4368 if ((cp < pStart) || (cp >= pEnd)) continue; 4369 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4370 size += dof; 4371 } 4372 if (!values) { 4373 if (csize) *csize = size; 4374 PetscFunctionReturn(0); 4375 } 4376 ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr); 4377 } else { 4378 array = *values; 4379 } 4380 size = 0; 4381 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4382 if ((point >= pStart) && (point < pEnd)) { 4383 PetscInt dof, off, d; 4384 PetscScalar *varr; 4385 4386 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4387 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4388 varr = &vArray[off]; 4389 for (d = 0; d < dof; ++d, ++offset) { 4390 array[offset] = varr[d]; 4391 } 4392 size += dof; 4393 } 4394 for (p = 0; p < numPoints; ++p) { 4395 const PetscInt cp = cone[p]; 4396 PetscInt o = coneO[p]; 4397 PetscInt dof, off, d; 4398 PetscScalar *varr; 4399 4400 if ((cp < pStart) || (cp >= pEnd)) continue; 4401 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4402 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 4403 varr = &vArray[off]; 4404 if (o >= 0) { 4405 for (d = 0; d < dof; ++d, ++offset) { 4406 array[offset] = varr[d]; 4407 } 4408 } else { 4409 for (d = dof-1; d >= 0; --d, ++offset) { 4410 array[offset] = varr[d]; 4411 } 4412 } 4413 size += dof; 4414 } 4415 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4416 if (!*values) { 4417 if (csize) *csize = size; 4418 *values = array; 4419 } else { 4420 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size); 4421 *csize = size; 4422 } 4423 PetscFunctionReturn(0); 4424 } 4425 4426 #undef __FUNCT__ 4427 #define __FUNCT__ "DMPlexVecGetClosure_Static" 4428 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 4429 { 4430 PetscInt offset = 0, p; 4431 PetscErrorCode ierr; 4432 4433 PetscFunctionBeginHot; 4434 *size = 0; 4435 for (p = 0; p < numPoints*2; p += 2) { 4436 const PetscInt point = points[p]; 4437 const PetscInt o = points[p+1]; 4438 PetscInt dof, off, d; 4439 const PetscScalar *varr; 4440 4441 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4442 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4443 varr = &vArray[off]; 4444 if (o >= 0) { 4445 for (d = 0; d < dof; ++d, ++offset) array[offset] = varr[d]; 4446 } else { 4447 for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d]; 4448 } 4449 } 4450 *size = offset; 4451 PetscFunctionReturn(0); 4452 } 4453 4454 #undef __FUNCT__ 4455 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static" 4456 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 4457 { 4458 PetscInt offset = 0, f; 4459 PetscErrorCode ierr; 4460 4461 PetscFunctionBeginHot; 4462 *size = 0; 4463 for (f = 0; f < numFields; ++f) { 4464 PetscInt fcomp, p; 4465 4466 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4467 for (p = 0; p < numPoints*2; p += 2) { 4468 const PetscInt point = points[p]; 4469 const PetscInt o = points[p+1]; 4470 PetscInt fdof, foff, d, c; 4471 const PetscScalar *varr; 4472 4473 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4474 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4475 varr = &vArray[foff]; 4476 if (o >= 0) { 4477 for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d]; 4478 } else { 4479 for (d = fdof/fcomp-1; d >= 0; --d) { 4480 for (c = 0; c < fcomp; ++c, ++offset) { 4481 array[offset] = varr[d*fcomp+c]; 4482 } 4483 } 4484 } 4485 } 4486 } 4487 *size = offset; 4488 PetscFunctionReturn(0); 4489 } 4490 4491 #undef __FUNCT__ 4492 #define __FUNCT__ "DMPlexVecGetClosure" 4493 /*@C 4494 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 4495 4496 Not collective 4497 4498 Input Parameters: 4499 + dm - The DM 4500 . section - The section describing the layout in v, or NULL to use the default section 4501 . v - The local vector 4502 - point - The sieve point in the DM 4503 4504 Output Parameters: 4505 + csize - The number of values in the closure, or NULL 4506 - values - The array of values, which is a borrowed array and should not be freed 4507 4508 Fortran Notes: 4509 Since it returns an array, this routine is only available in Fortran 90, and you must 4510 include petsc.h90 in your code. 4511 4512 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4513 4514 Level: intermediate 4515 4516 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4517 @*/ 4518 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4519 { 4520 PetscSection clSection; 4521 IS clPoints; 4522 PetscScalar *array, *vArray; 4523 PetscInt *points = NULL; 4524 const PetscInt *clp; 4525 PetscInt depth, numFields, numPoints, size; 4526 PetscErrorCode ierr; 4527 4528 PetscFunctionBeginHot; 4529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4530 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 4531 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4532 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4533 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4534 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4535 if (depth == 1 && numFields < 2) { 4536 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 4537 PetscFunctionReturn(0); 4538 } 4539 /* Get points */ 4540 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr); 4541 if (!clPoints) { 4542 PetscInt pStart, pEnd, p, q; 4543 4544 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4545 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 4546 /* Compress out points not in the section */ 4547 for (p = 0, q = 0; p < numPoints*2; p += 2) { 4548 if ((points[p] >= pStart) && (points[p] < pEnd)) { 4549 points[q*2] = points[p]; 4550 points[q*2+1] = points[p+1]; 4551 ++q; 4552 } 4553 } 4554 numPoints = q; 4555 } else { 4556 PetscInt dof, off; 4557 4558 ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr); 4559 ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr); 4560 ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr); 4561 numPoints = dof/2; 4562 points = (PetscInt *) &clp[off]; 4563 } 4564 /* Get array */ 4565 if (!values || !*values) { 4566 PetscInt asize = 0, dof, p; 4567 4568 for (p = 0; p < numPoints*2; p += 2) { 4569 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4570 asize += dof; 4571 } 4572 if (!values) { 4573 if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);} 4574 else {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);} 4575 if (csize) *csize = asize; 4576 PetscFunctionReturn(0); 4577 } 4578 ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr); 4579 } else { 4580 array = *values; 4581 } 4582 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4583 /* Get values */ 4584 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);CHKERRQ(ierr);} 4585 else {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);CHKERRQ(ierr);} 4586 /* Cleanup points */ 4587 if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);} 4588 else {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);} 4589 /* Cleanup array */ 4590 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4591 if (!*values) { 4592 if (csize) *csize = size; 4593 *values = array; 4594 } else { 4595 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size); 4596 *csize = size; 4597 } 4598 PetscFunctionReturn(0); 4599 } 4600 4601 #undef __FUNCT__ 4602 #define __FUNCT__ "DMPlexVecRestoreClosure" 4603 /*@C 4604 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 4605 4606 Not collective 4607 4608 Input Parameters: 4609 + dm - The DM 4610 . section - The section describing the layout in v, or NULL to use the default section 4611 . v - The local vector 4612 . point - The sieve point in the DM 4613 . csize - The number of values in the closure, or NULL 4614 - values - The array of values, which is a borrowed array and should not be freed 4615 4616 Fortran Notes: 4617 Since it returns an array, this routine is only available in Fortran 90, and you must 4618 include petsc.h90 in your code. 4619 4620 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4621 4622 Level: intermediate 4623 4624 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4625 @*/ 4626 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4627 { 4628 PetscInt size = 0; 4629 PetscErrorCode ierr; 4630 4631 PetscFunctionBegin; 4632 /* Should work without recalculating size */ 4633 ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr); 4634 PetscFunctionReturn(0); 4635 } 4636 4637 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 4638 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 4639 4640 #undef __FUNCT__ 4641 #define __FUNCT__ "updatePoint_private" 4642 PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 4643 { 4644 PetscInt cdof; /* The number of constraints on this point */ 4645 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4646 PetscScalar *a; 4647 PetscInt off, cind = 0, k; 4648 PetscErrorCode ierr; 4649 4650 PetscFunctionBegin; 4651 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4652 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4653 a = &array[off]; 4654 if (!cdof || setBC) { 4655 if (orientation >= 0) { 4656 for (k = 0; k < dof; ++k) { 4657 fuse(&a[k], values[k]); 4658 } 4659 } else { 4660 for (k = 0; k < dof; ++k) { 4661 fuse(&a[k], values[dof-k-1]); 4662 } 4663 } 4664 } else { 4665 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4666 if (orientation >= 0) { 4667 for (k = 0; k < dof; ++k) { 4668 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4669 fuse(&a[k], values[k]); 4670 } 4671 } else { 4672 for (k = 0; k < dof; ++k) { 4673 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4674 fuse(&a[k], values[dof-k-1]); 4675 } 4676 } 4677 } 4678 PetscFunctionReturn(0); 4679 } 4680 4681 #undef __FUNCT__ 4682 #define __FUNCT__ "updatePointBC_private" 4683 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 4684 { 4685 PetscInt cdof; /* The number of constraints on this point */ 4686 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4687 PetscScalar *a; 4688 PetscInt off, cind = 0, k; 4689 PetscErrorCode ierr; 4690 4691 PetscFunctionBegin; 4692 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4693 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4694 a = &array[off]; 4695 if (cdof) { 4696 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4697 if (orientation >= 0) { 4698 for (k = 0; k < dof; ++k) { 4699 if ((cind < cdof) && (k == cdofs[cind])) { 4700 fuse(&a[k], values[k]); 4701 ++cind; 4702 } 4703 } 4704 } else { 4705 for (k = 0; k < dof; ++k) { 4706 if ((cind < cdof) && (k == cdofs[cind])) { 4707 fuse(&a[k], values[dof-k-1]); 4708 ++cind; 4709 } 4710 } 4711 } 4712 } 4713 PetscFunctionReturn(0); 4714 } 4715 4716 #undef __FUNCT__ 4717 #define __FUNCT__ "updatePointFields_private" 4718 PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 4719 { 4720 PetscScalar *a; 4721 PetscInt fdof, foff, fcdof, foffset = *offset; 4722 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4723 PetscInt cind = 0, k, c; 4724 PetscErrorCode ierr; 4725 4726 PetscFunctionBegin; 4727 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4728 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4729 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4730 a = &array[foff]; 4731 if (!fcdof || setBC) { 4732 if (o >= 0) { 4733 for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]); 4734 } else { 4735 for (k = fdof/fcomp-1; k >= 0; --k) { 4736 for (c = 0; c < fcomp; ++c) { 4737 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]); 4738 } 4739 } 4740 } 4741 } else { 4742 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4743 if (o >= 0) { 4744 for (k = 0; k < fdof; ++k) { 4745 if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;} 4746 fuse(&a[k], values[foffset+k]); 4747 } 4748 } else { 4749 for (k = fdof/fcomp-1; k >= 0; --k) { 4750 for (c = 0; c < fcomp; ++c) { 4751 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;} 4752 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]); 4753 } 4754 } 4755 } 4756 } 4757 *offset += fdof; 4758 PetscFunctionReturn(0); 4759 } 4760 4761 #undef __FUNCT__ 4762 #define __FUNCT__ "updatePointFieldsBC_private" 4763 PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 4764 { 4765 PetscScalar *a; 4766 PetscInt fdof, foff, fcdof, foffset = *offset; 4767 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4768 PetscInt cind = 0, k, c; 4769 PetscErrorCode ierr; 4770 4771 PetscFunctionBegin; 4772 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4773 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4774 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4775 a = &array[foff]; 4776 if (fcdof) { 4777 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4778 if (o >= 0) { 4779 for (k = 0; k < fdof; ++k) { 4780 if ((cind < fcdof) && (k == fcdofs[cind])) { 4781 fuse(&a[k], values[foffset+k]); 4782 ++cind; 4783 } 4784 } 4785 } else { 4786 for (k = fdof/fcomp-1; k >= 0; --k) { 4787 for (c = 0; c < fcomp; ++c) { 4788 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) { 4789 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]); 4790 ++cind; 4791 } 4792 } 4793 } 4794 } 4795 } 4796 *offset += fdof; 4797 PetscFunctionReturn(0); 4798 } 4799 4800 #undef __FUNCT__ 4801 #define __FUNCT__ "DMPlexVecSetClosure_Static" 4802 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 4803 { 4804 PetscScalar *array; 4805 const PetscInt *cone, *coneO; 4806 PetscInt pStart, pEnd, p, numPoints, off, dof; 4807 PetscErrorCode ierr; 4808 4809 PetscFunctionBeginHot; 4810 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4811 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4812 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4813 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4814 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 4815 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 4816 const PetscInt cp = !p ? point : cone[p-1]; 4817 const PetscInt o = !p ? 0 : coneO[p-1]; 4818 4819 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 4820 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4821 /* ADD_VALUES */ 4822 { 4823 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4824 PetscScalar *a; 4825 PetscInt cdof, coff, cind = 0, k; 4826 4827 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 4828 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 4829 a = &array[coff]; 4830 if (!cdof) { 4831 if (o >= 0) { 4832 for (k = 0; k < dof; ++k) { 4833 a[k] += values[off+k]; 4834 } 4835 } else { 4836 for (k = 0; k < dof; ++k) { 4837 a[k] += values[off+dof-k-1]; 4838 } 4839 } 4840 } else { 4841 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 4842 if (o >= 0) { 4843 for (k = 0; k < dof; ++k) { 4844 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4845 a[k] += values[off+k]; 4846 } 4847 } else { 4848 for (k = 0; k < dof; ++k) { 4849 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4850 a[k] += values[off+dof-k-1]; 4851 } 4852 } 4853 } 4854 } 4855 } 4856 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 4857 PetscFunctionReturn(0); 4858 } 4859 4860 #undef __FUNCT__ 4861 #define __FUNCT__ "DMPlexVecSetClosure" 4862 /*@C 4863 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 4864 4865 Not collective 4866 4867 Input Parameters: 4868 + dm - The DM 4869 . section - The section describing the layout in v, or NULL to use the default section 4870 . v - The local vector 4871 . point - The sieve point in the DM 4872 . values - The array of values 4873 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 4874 4875 Fortran Notes: 4876 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 4877 4878 Level: intermediate 4879 4880 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 4881 @*/ 4882 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 4883 { 4884 PetscSection clSection; 4885 IS clPoints; 4886 PetscScalar *array; 4887 PetscInt *points = NULL; 4888 const PetscInt *clp; 4889 PetscInt depth, numFields, numPoints, p; 4890 PetscErrorCode ierr; 4891 4892 PetscFunctionBeginHot; 4893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4894 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 4895 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4896 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4897 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4898 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4899 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 4900 ierr = DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);CHKERRQ(ierr); 4901 PetscFunctionReturn(0); 4902 } 4903 /* Get points */ 4904 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr); 4905 if (!clPoints) { 4906 PetscInt pStart, pEnd, q; 4907 4908 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4909 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 4910 /* Compress out points not in the section */ 4911 for (p = 0, q = 0; p < numPoints*2; p += 2) { 4912 if ((points[p] >= pStart) && (points[p] < pEnd)) { 4913 points[q*2] = points[p]; 4914 points[q*2+1] = points[p+1]; 4915 ++q; 4916 } 4917 } 4918 numPoints = q; 4919 } else { 4920 PetscInt dof, off; 4921 4922 ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr); 4923 ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr); 4924 ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr); 4925 numPoints = dof/2; 4926 points = (PetscInt *) &clp[off]; 4927 } 4928 /* Get array */ 4929 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 4930 /* Get values */ 4931 if (numFields > 0) { 4932 PetscInt offset = 0, fcomp, f; 4933 for (f = 0; f < numFields; ++f) { 4934 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4935 switch (mode) { 4936 case INSERT_VALUES: 4937 for (p = 0; p < numPoints*2; p += 2) { 4938 const PetscInt point = points[p]; 4939 const PetscInt o = points[p+1]; 4940 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array); 4941 } break; 4942 case INSERT_ALL_VALUES: 4943 for (p = 0; p < numPoints*2; p += 2) { 4944 const PetscInt point = points[p]; 4945 const PetscInt o = points[p+1]; 4946 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array); 4947 } break; 4948 case INSERT_BC_VALUES: 4949 for (p = 0; p < numPoints*2; p += 2) { 4950 const PetscInt point = points[p]; 4951 const PetscInt o = points[p+1]; 4952 updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array); 4953 } break; 4954 case ADD_VALUES: 4955 for (p = 0; p < numPoints*2; p += 2) { 4956 const PetscInt point = points[p]; 4957 const PetscInt o = points[p+1]; 4958 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array); 4959 } break; 4960 case ADD_ALL_VALUES: 4961 for (p = 0; p < numPoints*2; p += 2) { 4962 const PetscInt point = points[p]; 4963 const PetscInt o = points[p+1]; 4964 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array); 4965 } break; 4966 default: 4967 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode); 4968 } 4969 } 4970 } else { 4971 PetscInt dof, off; 4972 4973 switch (mode) { 4974 case INSERT_VALUES: 4975 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4976 PetscInt o = points[p+1]; 4977 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4978 updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array); 4979 } break; 4980 case INSERT_ALL_VALUES: 4981 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4982 PetscInt o = points[p+1]; 4983 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4984 updatePoint_private(section, points[p], dof, insert, PETSC_TRUE, o, &values[off], array); 4985 } break; 4986 case INSERT_BC_VALUES: 4987 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4988 PetscInt o = points[p+1]; 4989 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4990 updatePointBC_private(section, points[p], dof, insert, o, &values[off], array); 4991 } break; 4992 case ADD_VALUES: 4993 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4994 PetscInt o = points[p+1]; 4995 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4996 updatePoint_private(section, points[p], dof, add, PETSC_FALSE, o, &values[off], array); 4997 } break; 4998 case ADD_ALL_VALUES: 4999 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5000 PetscInt o = points[p+1]; 5001 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5002 updatePoint_private(section, points[p], dof, add, PETSC_TRUE, o, &values[off], array); 5003 } break; 5004 default: 5005 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode); 5006 } 5007 } 5008 /* Cleanup points */ 5009 if (!clPoints) {ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);} 5010 else {ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr);} 5011 /* Cleanup array */ 5012 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5013 PetscFunctionReturn(0); 5014 } 5015 5016 #undef __FUNCT__ 5017 #define __FUNCT__ "DMPlexPrintMatSetValues" 5018 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 5019 { 5020 PetscMPIInt rank; 5021 PetscInt i, j; 5022 PetscErrorCode ierr; 5023 5024 PetscFunctionBegin; 5025 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr); 5026 ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr); 5027 for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);} 5028 for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);} 5029 numCIndices = numCIndices ? numCIndices : numRIndices; 5030 for (i = 0; i < numRIndices; i++) { 5031 ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr); 5032 for (j = 0; j < numCIndices; j++) { 5033 #if defined(PETSC_USE_COMPLEX) 5034 ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr); 5035 #else 5036 ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr); 5037 #endif 5038 } 5039 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 5040 } 5041 PetscFunctionReturn(0); 5042 } 5043 5044 #undef __FUNCT__ 5045 #define __FUNCT__ "indicesPoint_private" 5046 /* . off - The global offset of this point */ 5047 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[]) 5048 { 5049 PetscInt dof; /* The number of unknowns on this point */ 5050 PetscInt cdof; /* The number of constraints on this point */ 5051 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5052 PetscInt cind = 0, k; 5053 PetscErrorCode ierr; 5054 5055 PetscFunctionBegin; 5056 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5057 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5058 if (!cdof || setBC) { 5059 if (orientation >= 0) { 5060 for (k = 0; k < dof; ++k) indices[*loff+k] = off+k; 5061 } else { 5062 for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k; 5063 } 5064 } else { 5065 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5066 if (orientation >= 0) { 5067 for (k = 0; k < dof; ++k) { 5068 if ((cind < cdof) && (k == cdofs[cind])) { 5069 /* Insert check for returning constrained indices */ 5070 indices[*loff+k] = -(off+k+1); 5071 ++cind; 5072 } else { 5073 indices[*loff+k] = off+k-cind; 5074 } 5075 } 5076 } else { 5077 for (k = 0; k < dof; ++k) { 5078 if ((cind < cdof) && (k == cdofs[cind])) { 5079 /* Insert check for returning constrained indices */ 5080 indices[*loff+dof-k-1] = -(off+k+1); 5081 ++cind; 5082 } else { 5083 indices[*loff+dof-k-1] = off+k-cind; 5084 } 5085 } 5086 } 5087 } 5088 *loff += dof; 5089 PetscFunctionReturn(0); 5090 } 5091 5092 #undef __FUNCT__ 5093 #define __FUNCT__ "indicesPointFields_private" 5094 /* . off - The global offset of this point */ 5095 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) 5096 { 5097 PetscInt numFields, foff, f; 5098 PetscErrorCode ierr; 5099 5100 PetscFunctionBegin; 5101 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5102 for (f = 0, foff = 0; f < numFields; ++f) { 5103 PetscInt fdof, fcomp, cfdof; 5104 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5105 PetscInt cind = 0, k, c; 5106 5107 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 5108 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5109 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5110 if (!cfdof || setBC) { 5111 if (orientation >= 0) { 5112 for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k; 5113 } else { 5114 for (k = fdof/fcomp-1; k >= 0; --k) { 5115 for (c = 0; c < fcomp; ++c) { 5116 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c; 5117 } 5118 } 5119 } 5120 } else { 5121 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5122 if (orientation >= 0) { 5123 for (k = 0; k < fdof; ++k) { 5124 if ((cind < cfdof) && (k == fcdofs[cind])) { 5125 indices[foffs[f]+k] = -(off+foff+k+1); 5126 ++cind; 5127 } else { 5128 indices[foffs[f]+k] = off+foff+k-cind; 5129 } 5130 } 5131 } else { 5132 for (k = fdof/fcomp-1; k >= 0; --k) { 5133 for (c = 0; c < fcomp; ++c) { 5134 if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) { 5135 indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1); 5136 ++cind; 5137 } else { 5138 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind; 5139 } 5140 } 5141 } 5142 } 5143 } 5144 foff += fdof - cfdof; 5145 foffs[f] += fdof; 5146 } 5147 PetscFunctionReturn(0); 5148 } 5149 5150 #undef __FUNCT__ 5151 #define __FUNCT__ "DMPlexMatSetClosure" 5152 /*@C 5153 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 5154 5155 Not collective 5156 5157 Input Parameters: 5158 + dm - The DM 5159 . section - The section describing the layout in v, or NULL to use the default section 5160 . globalSection - The section describing the layout in v, or NULL to use the default global section 5161 . A - The matrix 5162 . point - The sieve point in the DM 5163 . values - The array of values 5164 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 5165 5166 Fortran Notes: 5167 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5168 5169 Level: intermediate 5170 5171 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure() 5172 @*/ 5173 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 5174 { 5175 DM_Plex *mesh = (DM_Plex*) dm->data; 5176 PetscSection clSection; 5177 IS clPoints; 5178 PetscInt *points = NULL; 5179 const PetscInt *clp; 5180 PetscInt *indices; 5181 PetscInt offsets[32]; 5182 PetscInt numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f; 5183 PetscErrorCode ierr; 5184 5185 PetscFunctionBegin; 5186 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5187 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 5188 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5189 if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 5190 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 5191 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 5192 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5193 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5194 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5195 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);CHKERRQ(ierr); 5196 if (!clPoints) { 5197 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5198 /* Compress out points not in the section */ 5199 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5200 for (p = 0, q = 0; p < numPoints*2; p += 2) { 5201 if ((points[p] >= pStart) && (points[p] < pEnd)) { 5202 points[q*2] = points[p]; 5203 points[q*2+1] = points[p+1]; 5204 ++q; 5205 } 5206 } 5207 numPoints = q; 5208 } else { 5209 PetscInt dof, off; 5210 5211 ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr); 5212 numPoints = dof/2; 5213 ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr); 5214 ierr = ISGetIndices(clPoints, &clp);CHKERRQ(ierr); 5215 points = (PetscInt *) &clp[off]; 5216 } 5217 for (p = 0, numIndices = 0; p < numPoints*2; p += 2) { 5218 PetscInt fdof; 5219 5220 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5221 for (f = 0; f < numFields; ++f) { 5222 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5223 offsets[f+1] += fdof; 5224 } 5225 numIndices += dof; 5226 } 5227 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 5228 5229 if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices); 5230 ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5231 if (numFields) { 5232 for (p = 0; p < numPoints*2; p += 2) { 5233 PetscInt o = points[p+1]; 5234 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5235 indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices); 5236 } 5237 } else { 5238 for (p = 0, off = 0; p < numPoints*2; p += 2) { 5239 PetscInt o = points[p+1]; 5240 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5241 indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices); 5242 } 5243 } 5244 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);} 5245 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 5246 if (ierr) { 5247 PetscMPIInt rank; 5248 PetscErrorCode ierr2; 5249 5250 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 5251 ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 5252 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2); 5253 ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2); 5254 CHKERRQ(ierr); 5255 } 5256 if (!clPoints) { 5257 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5258 } else { 5259 ierr = ISRestoreIndices(clPoints, &clp);CHKERRQ(ierr); 5260 } 5261 ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5262 PetscFunctionReturn(0); 5263 } 5264 5265 #undef __FUNCT__ 5266 #define __FUNCT__ "DMPlexMatSetClosureRefined" 5267 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 5268 { 5269 DM_Plex *mesh = (DM_Plex*) dmf->data; 5270 PetscInt *fpoints = NULL, *ftotpoints = NULL; 5271 PetscInt *cpoints = NULL; 5272 PetscInt *findices, *cindices; 5273 PetscInt foffsets[32], coffsets[32]; 5274 CellRefiner cellRefiner; 5275 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 5276 PetscErrorCode ierr; 5277 5278 PetscFunctionBegin; 5279 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 5280 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 5281 if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);} 5282 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 5283 if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);} 5284 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 5285 if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 5286 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 5287 if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 5288 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 5289 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 5290 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 5291 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5292 ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5293 ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5294 /* Column indices */ 5295 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5296 maxFPoints = numCPoints; 5297 /* Compress out points not in the section */ 5298 /* TODO: Squeeze out points with 0 dof as well */ 5299 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 5300 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 5301 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 5302 cpoints[q*2] = cpoints[p]; 5303 cpoints[q*2+1] = cpoints[p+1]; 5304 ++q; 5305 } 5306 } 5307 numCPoints = q; 5308 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 5309 PetscInt fdof; 5310 5311 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 5312 if (!dof) continue; 5313 for (f = 0; f < numFields; ++f) { 5314 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 5315 coffsets[f+1] += fdof; 5316 } 5317 numCIndices += dof; 5318 } 5319 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 5320 /* Row indices */ 5321 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 5322 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 5323 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5324 for (r = 0, q = 0; r < numSubcells; ++r) { 5325 /* TODO Map from coarse to fine cells */ 5326 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5327 /* Compress out points not in the section */ 5328 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 5329 for (p = 0; p < numFPoints*2; p += 2) { 5330 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 5331 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 5332 if (!dof) continue; 5333 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 5334 if (s < q) continue; 5335 ftotpoints[q*2] = fpoints[p]; 5336 ftotpoints[q*2+1] = fpoints[p+1]; 5337 ++q; 5338 } 5339 } 5340 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5341 } 5342 numFPoints = q; 5343 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 5344 PetscInt fdof; 5345 5346 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 5347 if (!dof) continue; 5348 for (f = 0; f < numFields; ++f) { 5349 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 5350 foffsets[f+1] += fdof; 5351 } 5352 numFIndices += dof; 5353 } 5354 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 5355 5356 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices); 5357 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices); 5358 ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr); 5359 ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr); 5360 if (numFields) { 5361 for (p = 0; p < numFPoints*2; p += 2) { 5362 PetscInt o = ftotpoints[p+1]; 5363 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5364 indicesPointFields_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices); 5365 } 5366 for (p = 0; p < numCPoints*2; p += 2) { 5367 PetscInt o = cpoints[p+1]; 5368 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5369 indicesPointFields_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices); 5370 } 5371 } else { 5372 for (p = 0, off = 0; p < numFPoints*2; p += 2) { 5373 PetscInt o = ftotpoints[p+1]; 5374 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5375 indicesPoint_private(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices); 5376 } 5377 for (p = 0, off = 0; p < numCPoints*2; p += 2) { 5378 PetscInt o = cpoints[p+1]; 5379 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5380 indicesPoint_private(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices); 5381 } 5382 } 5383 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);} 5384 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 5385 if (ierr) { 5386 PetscMPIInt rank; 5387 PetscErrorCode ierr2; 5388 5389 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 5390 ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 5391 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2); 5392 ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2); 5393 ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2); 5394 CHKERRQ(ierr); 5395 } 5396 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5397 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5398 ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr); 5399 ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr); 5400 PetscFunctionReturn(0); 5401 } 5402 5403 #undef __FUNCT__ 5404 #define __FUNCT__ "DMPlexGetHybridBounds" 5405 /*@ 5406 DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid 5407 5408 Input Parameter: 5409 . dm - The DMPlex object 5410 5411 Output Parameters: 5412 + cMax - The first hybrid cell 5413 . cMax - The first hybrid face 5414 . cMax - The first hybrid edge 5415 - cMax - The first hybrid vertex 5416 5417 Level: developer 5418 5419 .seealso DMPlexCreateHybridMesh() 5420 @*/ 5421 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax) 5422 { 5423 DM_Plex *mesh = (DM_Plex*) dm->data; 5424 PetscInt dim; 5425 PetscErrorCode ierr; 5426 5427 PetscFunctionBegin; 5428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5429 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5430 if (cMax) *cMax = mesh->hybridPointMax[dim]; 5431 if (fMax) *fMax = mesh->hybridPointMax[dim-1]; 5432 if (eMax) *eMax = mesh->hybridPointMax[1]; 5433 if (vMax) *vMax = mesh->hybridPointMax[0]; 5434 PetscFunctionReturn(0); 5435 } 5436 5437 #undef __FUNCT__ 5438 #define __FUNCT__ "DMPlexSetHybridBounds" 5439 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax) 5440 { 5441 DM_Plex *mesh = (DM_Plex*) dm->data; 5442 PetscInt dim; 5443 PetscErrorCode ierr; 5444 5445 PetscFunctionBegin; 5446 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5447 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5448 if (cMax >= 0) mesh->hybridPointMax[dim] = cMax; 5449 if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax; 5450 if (eMax >= 0) mesh->hybridPointMax[1] = eMax; 5451 if (vMax >= 0) mesh->hybridPointMax[0] = vMax; 5452 PetscFunctionReturn(0); 5453 } 5454 5455 #undef __FUNCT__ 5456 #define __FUNCT__ "DMPlexGetVTKCellHeight" 5457 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 5458 { 5459 DM_Plex *mesh = (DM_Plex*) dm->data; 5460 5461 PetscFunctionBegin; 5462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5463 PetscValidPointer(cellHeight, 2); 5464 *cellHeight = mesh->vtkCellHeight; 5465 PetscFunctionReturn(0); 5466 } 5467 5468 #undef __FUNCT__ 5469 #define __FUNCT__ "DMPlexSetVTKCellHeight" 5470 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 5471 { 5472 DM_Plex *mesh = (DM_Plex*) dm->data; 5473 5474 PetscFunctionBegin; 5475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5476 mesh->vtkCellHeight = cellHeight; 5477 PetscFunctionReturn(0); 5478 } 5479 5480 #undef __FUNCT__ 5481 #define __FUNCT__ "DMPlexCreateNumbering_Private" 5482 /* We can easily have a form that takes an IS instead */ 5483 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 5484 { 5485 PetscSection section, globalSection; 5486 PetscInt *numbers, p; 5487 PetscErrorCode ierr; 5488 5489 PetscFunctionBegin; 5490 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 5491 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 5492 for (p = pStart; p < pEnd; ++p) { 5493 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 5494 } 5495 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 5496 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 5497 ierr = PetscMalloc1((pEnd - pStart), &numbers);CHKERRQ(ierr); 5498 for (p = pStart; p < pEnd; ++p) { 5499 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 5500 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 5501 else numbers[p-pStart] += shift; 5502 } 5503 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 5504 if (globalSize) { 5505 PetscLayout layout; 5506 ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr); 5507 ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr); 5508 ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr); 5509 } 5510 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 5511 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 5512 PetscFunctionReturn(0); 5513 } 5514 5515 #undef __FUNCT__ 5516 #define __FUNCT__ "DMPlexGetCellNumbering" 5517 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 5518 { 5519 DM_Plex *mesh = (DM_Plex*) dm->data; 5520 PetscInt cellHeight, cStart, cEnd, cMax; 5521 PetscErrorCode ierr; 5522 5523 PetscFunctionBegin; 5524 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5525 if (!mesh->globalCellNumbers) { 5526 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 5527 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 5528 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 5529 if (cMax >= 0) cEnd = PetscMin(cEnd, cMax); 5530 ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr); 5531 } 5532 *globalCellNumbers = mesh->globalCellNumbers; 5533 PetscFunctionReturn(0); 5534 } 5535 5536 #undef __FUNCT__ 5537 #define __FUNCT__ "DMPlexGetVertexNumbering" 5538 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 5539 { 5540 DM_Plex *mesh = (DM_Plex*) dm->data; 5541 PetscInt vStart, vEnd, vMax; 5542 PetscErrorCode ierr; 5543 5544 PetscFunctionBegin; 5545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5546 if (!mesh->globalVertexNumbers) { 5547 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5548 ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); 5549 if (vMax >= 0) vEnd = PetscMin(vEnd, vMax); 5550 ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr); 5551 } 5552 *globalVertexNumbers = mesh->globalVertexNumbers; 5553 PetscFunctionReturn(0); 5554 } 5555 5556 #undef __FUNCT__ 5557 #define __FUNCT__ "DMPlexCreatePointNumbering" 5558 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 5559 { 5560 IS nums[4]; 5561 PetscInt depths[4]; 5562 PetscInt depth, d, shift = 0; 5563 PetscErrorCode ierr; 5564 5565 PetscFunctionBegin; 5566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5567 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5568 depths[0] = depth; depths[1] = 0; 5569 for (d = 2; d <= depth; ++d) depths[d] = depth-d+1; 5570 for (d = 0; d <= depth; ++d) { 5571 PetscInt pStart, pEnd, gsize; 5572 5573 ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr); 5574 ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr); 5575 shift += gsize; 5576 } 5577 ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers); 5578 for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);} 5579 PetscFunctionReturn(0); 5580 } 5581 5582 5583 #undef __FUNCT__ 5584 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel" 5585 /*@C 5586 PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using 5587 the local section and an SF describing the section point overlap. 5588 5589 Input Parameters: 5590 + s - The PetscSection for the local field layout 5591 . sf - The SF describing parallel layout of the section points 5592 . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs 5593 . label - The label specifying the points 5594 - labelValue - The label stratum specifying the points 5595 5596 Output Parameter: 5597 . gsection - The PetscSection for the global field layout 5598 5599 Note: This gives negative sizes and offsets to points not owned by this process 5600 5601 Level: developer 5602 5603 .seealso: PetscSectionCreate() 5604 @*/ 5605 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection) 5606 { 5607 PetscInt *neg = NULL, *tmpOff = NULL; 5608 PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots; 5609 PetscErrorCode ierr; 5610 5611 PetscFunctionBegin; 5612 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) s), gsection);CHKERRQ(ierr); 5613 ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr); 5614 ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr); 5615 ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 5616 if (nroots >= 0) { 5617 if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart); 5618 ierr = PetscCalloc1(nroots, &neg);CHKERRQ(ierr); 5619 if (nroots > pEnd-pStart) { 5620 ierr = PetscCalloc1(nroots, &tmpOff);CHKERRQ(ierr); 5621 } else { 5622 tmpOff = &(*gsection)->atlasDof[-pStart]; 5623 } 5624 } 5625 /* Mark ghost points with negative dof */ 5626 for (p = pStart; p < pEnd; ++p) { 5627 PetscInt value; 5628 5629 ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr); 5630 if (value != labelValue) continue; 5631 ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr); 5632 ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr); 5633 ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr); 5634 if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);} 5635 if (neg) neg[p] = -(dof+1); 5636 } 5637 ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr); 5638 if (nroots >= 0) { 5639 ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5640 ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5641 if (nroots > pEnd-pStart) { 5642 for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];} 5643 } 5644 } 5645 /* Calculate new sizes, get proccess offset, and calculate point offsets */ 5646 for (p = 0, off = 0; p < pEnd-pStart; ++p) { 5647 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0; 5648 (*gsection)->atlasOff[p] = off; 5649 off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0; 5650 } 5651 ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) s));CHKERRQ(ierr); 5652 globalOff -= off; 5653 for (p = 0, off = 0; p < pEnd-pStart; ++p) { 5654 (*gsection)->atlasOff[p] += globalOff; 5655 if (neg) neg[p] = -((*gsection)->atlasOff[p]+1); 5656 } 5657 /* Put in negative offsets for ghost points */ 5658 if (nroots >= 0) { 5659 ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5660 ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5661 if (nroots > pEnd-pStart) { 5662 for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];} 5663 } 5664 } 5665 if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);} 5666 ierr = PetscFree(neg);CHKERRQ(ierr); 5667 PetscFunctionReturn(0); 5668 } 5669 5670 #undef __FUNCT__ 5671 #define __FUNCT__ "DMPlexCheckSymmetry" 5672 /*@ 5673 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 5674 5675 Input Parameters: 5676 + dm - The DMPlex object 5677 5678 Note: This is a useful diagnostic when creating meshes programmatically. 5679 5680 Level: developer 5681 5682 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces() 5683 @*/ 5684 PetscErrorCode DMPlexCheckSymmetry(DM dm) 5685 { 5686 PetscSection coneSection, supportSection; 5687 const PetscInt *cone, *support; 5688 PetscInt coneSize, c, supportSize, s; 5689 PetscInt pStart, pEnd, p, csize, ssize; 5690 PetscErrorCode ierr; 5691 5692 PetscFunctionBegin; 5693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5694 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 5695 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 5696 /* Check that point p is found in the support of its cone points, and vice versa */ 5697 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 5698 for (p = pStart; p < pEnd; ++p) { 5699 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 5700 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 5701 for (c = 0; c < coneSize; ++c) { 5702 PetscBool dup = PETSC_FALSE; 5703 PetscInt d; 5704 for (d = c-1; d >= 0; --d) { 5705 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 5706 } 5707 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 5708 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 5709 for (s = 0; s < supportSize; ++s) { 5710 if (support[s] == p) break; 5711 } 5712 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 5713 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p); 5714 for (s = 0; s < coneSize; ++s) { 5715 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]); 5716 } 5717 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 5718 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]); 5719 for (s = 0; s < supportSize; ++s) { 5720 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]); 5721 } 5722 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 5723 if (dup) { 5724 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]); 5725 } else { 5726 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]); 5727 } 5728 } 5729 } 5730 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 5731 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 5732 for (s = 0; s < supportSize; ++s) { 5733 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 5734 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 5735 for (c = 0; c < coneSize; ++c) { 5736 if (cone[c] == p) break; 5737 } 5738 if (c >= coneSize) { 5739 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p); 5740 for (c = 0; c < supportSize; ++c) { 5741 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]); 5742 } 5743 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 5744 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]); 5745 for (c = 0; c < coneSize; ++c) { 5746 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]); 5747 } 5748 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 5749 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]); 5750 } 5751 } 5752 } 5753 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 5754 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 5755 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize); 5756 PetscFunctionReturn(0); 5757 } 5758 5759 #undef __FUNCT__ 5760 #define __FUNCT__ "DMPlexCheckSkeleton" 5761 /*@ 5762 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 5763 5764 Input Parameters: 5765 + dm - The DMPlex object 5766 . isSimplex - Are the cells simplices or tensor products 5767 - cellHeight - Normally 0 5768 5769 Note: This is a useful diagnostic when creating meshes programmatically. 5770 5771 Level: developer 5772 5773 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces() 5774 @*/ 5775 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight) 5776 { 5777 PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c; 5778 PetscErrorCode ierr; 5779 5780 PetscFunctionBegin; 5781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5782 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5783 switch (dim) { 5784 case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break; 5785 case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break; 5786 case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break; 5787 default: 5788 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim); 5789 } 5790 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5791 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 5792 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 5793 cMax = cMax >= 0 ? cMax : cEnd; 5794 for (c = cStart; c < cMax; ++c) { 5795 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 5796 5797 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5798 for (cl = 0; cl < closureSize*2; cl += 2) { 5799 const PetscInt p = closure[cl]; 5800 if ((p >= vStart) && (p < vEnd)) ++coneSize; 5801 } 5802 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5803 if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d vertices != %d", c, coneSize, numCorners); 5804 } 5805 for (c = cMax; c < cEnd; ++c) { 5806 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 5807 5808 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5809 for (cl = 0; cl < closureSize*2; cl += 2) { 5810 const PetscInt p = closure[cl]; 5811 if ((p >= vStart) && (p < vEnd)) ++coneSize; 5812 } 5813 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5814 if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has %d vertices > %d", c, coneSize, numHybridCorners); 5815 } 5816 PetscFunctionReturn(0); 5817 } 5818 5819 #undef __FUNCT__ 5820 #define __FUNCT__ "DMPlexCheckFaces" 5821 /*@ 5822 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 5823 5824 Input Parameters: 5825 + dm - The DMPlex object 5826 . isSimplex - Are the cells simplices or tensor products 5827 - cellHeight - Normally 0 5828 5829 Note: This is a useful diagnostic when creating meshes programmatically. 5830 5831 Level: developer 5832 5833 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton() 5834 @*/ 5835 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight) 5836 { 5837 PetscInt pMax[4]; 5838 PetscInt dim, vStart, vEnd, cStart, cEnd, c, h; 5839 PetscErrorCode ierr; 5840 5841 PetscFunctionBegin; 5842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5843 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5844 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5845 ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr); 5846 for (h = cellHeight; h < dim; ++h) { 5847 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 5848 for (c = cStart; c < cEnd; ++c) { 5849 const PetscInt *cone, *ornt, *faces; 5850 PetscInt numFaces, faceSize, coneSize,f; 5851 PetscInt *closure = NULL, closureSize, cl, numCorners = 0; 5852 5853 if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue; 5854 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 5855 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 5856 ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr); 5857 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5858 for (cl = 0; cl < closureSize*2; cl += 2) { 5859 const PetscInt p = closure[cl]; 5860 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 5861 } 5862 ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 5863 if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces); 5864 for (f = 0; f < numFaces; ++f) { 5865 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 5866 5867 ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 5868 for (cl = 0; cl < fclosureSize*2; cl += 2) { 5869 const PetscInt p = fclosure[cl]; 5870 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 5871 } 5872 if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d has %d vertices but should have %d", cone[f], f, c, fnumCorners, faceSize); 5873 for (v = 0; v < fnumCorners; ++v) { 5874 if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d vertex %d, %d != %d", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]); 5875 } 5876 ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 5877 } 5878 ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 5879 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5880 } 5881 } 5882 PetscFunctionReturn(0); 5883 } 5884 5885 #undef __FUNCT__ 5886 #define __FUNCT__ "DMCreateInterpolation_Plex" 5887 /* Pointwise interpolation 5888 Just code FEM for now 5889 u^f = I u^c 5890 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 5891 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 5892 I_{ij} = psi^f_i phi^c_j 5893 */ 5894 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 5895 { 5896 PetscSection gsc, gsf; 5897 PetscInt m, n; 5898 void *ctx; 5899 PetscErrorCode ierr; 5900 5901 PetscFunctionBegin; 5902 /* 5903 Loop over coarse cells 5904 Loop over coarse basis functions 5905 Loop over fine cells in coarse cell 5906 Loop over fine dual basis functions 5907 Evaluate coarse basis on fine dual basis quad points 5908 Sum 5909 Update local element matrix 5910 Accumulate to interpolation matrix 5911 5912 Can extend PetscFEIntegrateJacobian_Basic() to do a specialized cell loop 5913 */ 5914 ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 5915 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 5916 ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 5917 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 5918 /* We need to preallocate properly */ 5919 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr); 5920 ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 5921 ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr); 5922 ierr = MatSetUp(*interpolation);CHKERRQ(ierr); 5923 ierr = MatSetFromOptions(*interpolation);CHKERRQ(ierr); 5924 ierr = MatSetOption(*interpolation, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE);CHKERRQ(ierr); 5925 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 5926 ierr = DMPlexComputeInterpolatorFEM(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr); 5927 /* Use naive scaling */ 5928 ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr); 5929 PetscFunctionReturn(0); 5930 } 5931 5932 #undef __FUNCT__ 5933 #define __FUNCT__ "DMCreateInjection_Plex" 5934 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, VecScatter *ctx) 5935 { 5936 Vec cv, fv; 5937 IS cis, fis, fpointIS; 5938 PetscSection sc, gsc, gsf; 5939 const PetscInt *fpoints; 5940 PetscInt *cindices, *findices; 5941 PetscInt cpStart, cpEnd, m, off, cp; 5942 PetscErrorCode ierr; 5943 5944 PetscFunctionBegin; 5945 ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 5946 ierr = DMGetGlobalVector(dmFine, &fv);CHKERRQ(ierr); 5947 ierr = DMGetDefaultSection(dmCoarse, &sc);CHKERRQ(ierr); 5948 ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 5949 ierr = DMGetGlobalVector(dmCoarse, &cv);CHKERRQ(ierr); 5950 ierr = DMPlexCreateCoarsePointIS(dmCoarse, &fpointIS);CHKERRQ(ierr); 5951 ierr = PetscSectionGetConstrainedStorageSize(gsc, &m);CHKERRQ(ierr); 5952 ierr = PetscMalloc2(m,&cindices,m,&findices);CHKERRQ(ierr); 5953 ierr = PetscSectionGetChart(gsc, &cpStart, &cpEnd);CHKERRQ(ierr); 5954 ierr = ISGetIndices(fpointIS, &fpoints);CHKERRQ(ierr); 5955 for (cp = cpStart, off = 0; cp < cpEnd; ++cp) { 5956 const PetscInt *cdofsC = NULL; 5957 PetscInt fp = fpoints[cp-cpStart], dofC, cdofC, dofF, offC, offF, d, e; 5958 5959 ierr = PetscSectionGetDof(gsc, cp, &dofC);CHKERRQ(ierr); 5960 if (dofC <= 0) continue; 5961 ierr = PetscSectionGetConstraintDof(sc, cp, &cdofC);CHKERRQ(ierr); 5962 ierr = PetscSectionGetDof(gsf, fp, &dofF);CHKERRQ(ierr); 5963 ierr = PetscSectionGetOffset(gsc, cp, &offC);CHKERRQ(ierr); 5964 ierr = PetscSectionGetOffset(gsf, fp, &offF);CHKERRQ(ierr); 5965 if (cdofC) {ierr = PetscSectionGetConstraintIndices(sc, cp, &cdofsC);CHKERRQ(ierr);} 5966 if (dofC != dofF) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d (%d) has %d coarse dofs != %d fine dofs", cp, fp, dofC, dofF); 5967 if (offC < 0 || offF < 0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Coarse point %d has invalid offset %d (%d)", cp, offC, offF); 5968 for (d = 0, e = 0; d < dofC; ++d) { 5969 if (cdofsC && cdofsC[e] == d) {++e; continue;} 5970 cindices[off+d-e] = offC+d; findices[off+d-e] = offF+d; 5971 } 5972 if (e != cdofC) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d (%d) has invalid number of constraints %d != %d", cp, fp, e, cdofC); 5973 off += dofC-cdofC; 5974 } 5975 ierr = ISRestoreIndices(fpointIS, &fpoints);CHKERRQ(ierr); 5976 if (off != m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of coarse dofs %d != %d", off, m); 5977 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr); 5978 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr); 5979 ierr = VecScatterCreate(cv, cis, fv, fis, ctx);CHKERRQ(ierr); 5980 ierr = ISDestroy(&cis);CHKERRQ(ierr); 5981 ierr = ISDestroy(&fis);CHKERRQ(ierr); 5982 ierr = DMRestoreGlobalVector(dmFine, &fv);CHKERRQ(ierr); 5983 ierr = DMRestoreGlobalVector(dmCoarse, &cv);CHKERRQ(ierr); 5984 ierr = ISDestroy(&fpointIS);CHKERRQ(ierr); 5985 PetscFunctionReturn(0); 5986 } 5987 5988 #undef __FUNCT__ 5989 #define __FUNCT__ "DMCreateDefaultSection_Plex" 5990 /* Pointwise interpolation 5991 Just code FEM for now 5992 u^f = I u^c 5993 sum_k u^f_k phi^f_k = I sum_l u^c_l phi^c_l 5994 u^f_i = sum_l int psi^f_i I phi^c_l u^c_l 5995 I_{ij} = int psi^f_i phi^c_j 5996 */ 5997 PetscErrorCode DMCreateDefaultSection_Plex(DM dm) 5998 { 5999 PetscSection section; 6000 IS *bcPoints; 6001 PetscInt *bcFields, *numComp, *numDof; 6002 PetscInt depth, dim, numBd, numBC = 0, numFields, bd, bc, f; 6003 PetscErrorCode ierr; 6004 6005 PetscFunctionBegin; 6006 /* Handle boundary conditions */ 6007 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 6008 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 6009 ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr); 6010 for (bd = 0; bd < numBd; ++bd) { 6011 PetscBool isEssential; 6012 ierr = DMPlexGetBoundary(dm, bd, &isEssential, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 6013 if (isEssential) ++numBC; 6014 } 6015 ierr = PetscMalloc2(numBC,&bcFields,numBC,&bcPoints);CHKERRQ(ierr); 6016 for (bd = 0, bc = 0; bd < numBd; ++bd) { 6017 const char *bdLabel; 6018 DMLabel label; 6019 const PetscInt *values; 6020 PetscInt field, numValues; 6021 PetscBool isEssential, has; 6022 6023 ierr = DMPlexGetBoundary(dm, bd, &isEssential, &bdLabel, &field, NULL, &numValues, &values, NULL);CHKERRQ(ierr); 6024 if (numValues != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Bug me and I will fix this"); 6025 ierr = DMPlexHasLabel(dm, bdLabel, &has);CHKERRQ(ierr); 6026 if (!has) { 6027 ierr = DMPlexCreateLabel(dm, bdLabel);CHKERRQ(ierr); 6028 ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr); 6029 ierr = DMPlexMarkBoundaryFaces(dm, label);CHKERRQ(ierr); 6030 } 6031 ierr = DMPlexGetLabel(dm, bdLabel, &label);CHKERRQ(ierr); 6032 /* Only want to do this for FEM */ 6033 ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr); 6034 ierr = DMPlexLabelAddCells(dm, label);CHKERRQ(ierr); 6035 /* Filter out cells, if you actually want to constraint cells you need to do things by hand right now */ 6036 if (isEssential) { 6037 IS tmp; 6038 PetscInt *newidx; 6039 const PetscInt *idx; 6040 PetscInt cStart, cEnd, n, p, newn = 0; 6041 6042 bcFields[bc] = field; 6043 ierr = DMPlexGetStratumIS(dm, bdLabel, values[0], &tmp);CHKERRQ(ierr); 6044 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 6045 ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr); 6046 ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr); 6047 for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn; 6048 ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr); 6049 newn = 0; 6050 for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p]; 6051 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr); 6052 ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr); 6053 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 6054 } 6055 } 6056 /* Handle discretization */ 6057 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 6058 ierr = PetscMalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr); 6059 for (f = 0; f < numFields; ++f) { 6060 PetscFE fe; 6061 const PetscInt *numFieldDof; 6062 PetscInt d; 6063 6064 ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr); 6065 ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr); 6066 ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr); 6067 for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d]; 6068 } 6069 for (f = 0; f < numFields; ++f) { 6070 PetscInt d; 6071 for (d = 1; d < dim; ++d) { 6072 if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces."); 6073 } 6074 } 6075 ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcPoints, NULL, §ion);CHKERRQ(ierr); 6076 for (f = 0; f < numFields; ++f) { 6077 PetscFE fe; 6078 const char *name; 6079 6080 ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr); 6081 ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr); 6082 ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr); 6083 } 6084 ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr); 6085 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 6086 for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);} 6087 ierr = PetscFree2(bcFields,bcPoints);CHKERRQ(ierr); 6088 ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr); 6089 PetscFunctionReturn(0); 6090 } 6091 6092 #undef __FUNCT__ 6093 #define __FUNCT__ "DMPlexGetCoarseDM" 6094 /*@ 6095 DMPlexGetCoarseDM - Get the coarse mesh from which this was obtained by refinement 6096 6097 Input Parameter: 6098 . dm - The DMPlex object 6099 6100 Output Parameter: 6101 . cdm - The coarse DM 6102 6103 Level: intermediate 6104 6105 .seealso: DMPlexSetCoarseDM() 6106 @*/ 6107 PetscErrorCode DMPlexGetCoarseDM(DM dm, DM *cdm) 6108 { 6109 PetscFunctionBegin; 6110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6111 PetscValidPointer(cdm, 2); 6112 *cdm = ((DM_Plex *) dm->data)->coarseMesh; 6113 PetscFunctionReturn(0); 6114 } 6115 6116 #undef __FUNCT__ 6117 #define __FUNCT__ "DMPlexSetCoarseDM" 6118 /*@ 6119 DMPlexSetCoarseDM - Set the coarse mesh from which this was obtained by refinement 6120 6121 Input Parameters: 6122 + dm - The DMPlex object 6123 - cdm - The coarse DM 6124 6125 Level: intermediate 6126 6127 .seealso: DMPlexGetCoarseDM() 6128 @*/ 6129 PetscErrorCode DMPlexSetCoarseDM(DM dm, DM cdm) 6130 { 6131 DM_Plex *mesh; 6132 PetscErrorCode ierr; 6133 6134 PetscFunctionBegin; 6135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6136 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 6137 mesh = (DM_Plex *) dm->data; 6138 ierr = DMDestroy(&mesh->coarseMesh);CHKERRQ(ierr); 6139 mesh->coarseMesh = cdm; 6140 ierr = PetscObjectReference((PetscObject) mesh->coarseMesh);CHKERRQ(ierr); 6141 PetscFunctionReturn(0); 6142 } 6143