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