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