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_DistributeLabels, DMPLEX_DistributeSF, 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 /* Setup face recognition */ 2264 if (faceDepth == 1) { 2265 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 */ 2266 2267 for (c = cStart; c < cEnd; ++c) { 2268 PetscInt corners; 2269 2270 ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr); 2271 if (!cornersSeen[corners]) { 2272 PetscInt nFV; 2273 2274 if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases"); 2275 cornersSeen[corners] = 1; 2276 2277 ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr); 2278 2279 numFaceVertices[numFaceCases++] = nFV; 2280 } 2281 } 2282 } 2283 maxClosure = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1)); 2284 maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1); 2285 ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr); 2286 ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr); 2287 ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr); 2288 /* Count neighboring cells */ 2289 for (cell = cStart; cell < cEnd; ++cell) { 2290 PetscInt numNeighbors = maxNeighbors, n; 2291 2292 ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr); 2293 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 2294 for (n = 0; n < numNeighbors; ++n) { 2295 PetscInt cellPair[2]; 2296 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 2297 PetscInt meetSize = 0; 2298 const PetscInt *meet = NULL; 2299 2300 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 2301 if (cellPair[0] == cellPair[1]) continue; 2302 if (!found) { 2303 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 2304 if (meetSize) { 2305 PetscInt f; 2306 2307 for (f = 0; f < numFaceCases; ++f) { 2308 if (numFaceVertices[f] == meetSize) { 2309 found = PETSC_TRUE; 2310 break; 2311 } 2312 } 2313 } 2314 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 2315 } 2316 if (found) ++off[cell-cStart+1]; 2317 } 2318 } 2319 /* Prefix sum */ 2320 for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1]; 2321 2322 if (adjacency) { 2323 ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr); 2324 /* Get neighboring cells */ 2325 for (cell = cStart; cell < cEnd; ++cell) { 2326 PetscInt numNeighbors = maxNeighbors, n; 2327 PetscInt cellOffset = 0; 2328 2329 ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr); 2330 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 2331 for (n = 0; n < numNeighbors; ++n) { 2332 PetscInt cellPair[2]; 2333 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 2334 PetscInt meetSize = 0; 2335 const PetscInt *meet = NULL; 2336 2337 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 2338 if (cellPair[0] == cellPair[1]) continue; 2339 if (!found) { 2340 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 2341 if (meetSize) { 2342 PetscInt f; 2343 2344 for (f = 0; f < numFaceCases; ++f) { 2345 if (numFaceVertices[f] == meetSize) { 2346 found = PETSC_TRUE; 2347 break; 2348 } 2349 } 2350 } 2351 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 2352 } 2353 if (found) { 2354 adj[off[cell-cStart]+cellOffset] = neighborCells[n]; 2355 ++cellOffset; 2356 } 2357 } 2358 } 2359 } 2360 ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr); 2361 if (numVertices) *numVertices = numCells; 2362 if (offsets) *offsets = off; 2363 if (adjacency) *adjacency = adj; 2364 PetscFunctionReturn(0); 2365 } 2366 2367 #if defined(PETSC_HAVE_CHACO) 2368 #if defined(PETSC_HAVE_UNISTD_H) 2369 #include <unistd.h> 2370 #endif 2371 /* Chaco does not have an include file */ 2372 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts, 2373 float *ewgts, float *x, float *y, float *z, char *outassignname, 2374 char *outfilename, short *assignment, int architecture, int ndims_tot, 2375 int mesh_dims[3], double *goal, int global_method, int local_method, 2376 int rqi_flag, int vmax, int ndims, double eigtol, long seed); 2377 2378 extern int FREE_GRAPH; 2379 2380 #undef __FUNCT__ 2381 #define __FUNCT__ "DMPlexPartition_Chaco" 2382 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition) 2383 { 2384 enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3}; 2385 MPI_Comm comm; 2386 int nvtxs = numVertices; /* number of vertices in full graph */ 2387 int *vwgts = NULL; /* weights for all vertices */ 2388 float *ewgts = NULL; /* weights for all edges */ 2389 float *x = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */ 2390 char *outassignname = NULL; /* name of assignment output file */ 2391 char *outfilename = NULL; /* output file name */ 2392 int architecture = 1; /* 0 => hypercube, d => d-dimensional mesh */ 2393 int ndims_tot = 0; /* total number of cube dimensions to divide */ 2394 int mesh_dims[3]; /* dimensions of mesh of processors */ 2395 double *goal = NULL; /* desired set sizes for each set */ 2396 int global_method = 1; /* global partitioning algorithm */ 2397 int local_method = 1; /* local partitioning algorithm */ 2398 int rqi_flag = 0; /* should I use RQI/Symmlq eigensolver? */ 2399 int vmax = 200; /* how many vertices to coarsen down to? */ 2400 int ndims = 1; /* number of eigenvectors (2^d sets) */ 2401 double eigtol = 0.001; /* tolerance on eigenvectors */ 2402 long seed = 123636512; /* for random graph mutations */ 2403 short int *assignment; /* Output partition */ 2404 int fd_stdout, fd_pipe[2]; 2405 PetscInt *points; 2406 PetscMPIInt commSize; 2407 int i, v, p; 2408 PetscErrorCode ierr; 2409 2410 PetscFunctionBegin; 2411 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 2412 ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr); 2413 if (!numVertices) { 2414 ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr); 2415 ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr); 2416 ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr); 2417 ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2418 PetscFunctionReturn(0); 2419 } 2420 FREE_GRAPH = 0; /* Do not let Chaco free my memory */ 2421 for (i = 0; i < start[numVertices]; ++i) ++adjacency[i]; 2422 2423 if (global_method == INERTIAL_METHOD) { 2424 /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */ 2425 SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported"); 2426 } 2427 mesh_dims[0] = commSize; 2428 mesh_dims[1] = 1; 2429 mesh_dims[2] = 1; 2430 ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr); 2431 /* Chaco outputs to stdout. We redirect this to a buffer. */ 2432 /* TODO: check error codes for UNIX calls */ 2433 #if defined(PETSC_HAVE_UNISTD_H) 2434 { 2435 int piperet; 2436 piperet = pipe(fd_pipe); 2437 if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe"); 2438 fd_stdout = dup(1); 2439 close(1); 2440 dup2(fd_pipe[1], 1); 2441 } 2442 #endif 2443 ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename, 2444 assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag, 2445 vmax, ndims, eigtol, seed); 2446 #if defined(PETSC_HAVE_UNISTD_H) 2447 { 2448 char msgLog[10000]; 2449 int count; 2450 2451 fflush(stdout); 2452 count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char)); 2453 if (count < 0) count = 0; 2454 msgLog[count] = 0; 2455 close(1); 2456 dup2(fd_stdout, 1); 2457 close(fd_stdout); 2458 close(fd_pipe[0]); 2459 close(fd_pipe[1]); 2460 if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog); 2461 } 2462 #endif 2463 /* Convert to PetscSection+IS */ 2464 ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr); 2465 ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr); 2466 for (v = 0; v < nvtxs; ++v) { 2467 ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr); 2468 } 2469 ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr); 2470 ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr); 2471 for (p = 0, i = 0; p < commSize; ++p) { 2472 for (v = 0; v < nvtxs; ++v) { 2473 if (assignment[v] == p) points[i++] = v; 2474 } 2475 } 2476 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 2477 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2478 if (global_method == INERTIAL_METHOD) { 2479 /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */ 2480 } 2481 ierr = PetscFree(assignment);CHKERRQ(ierr); 2482 for (i = 0; i < start[numVertices]; ++i) --adjacency[i]; 2483 PetscFunctionReturn(0); 2484 } 2485 #endif 2486 2487 #if defined(PETSC_HAVE_PARMETIS) 2488 #include <parmetis.h> 2489 2490 #undef __FUNCT__ 2491 #define __FUNCT__ "DMPlexPartition_ParMetis" 2492 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition) 2493 { 2494 MPI_Comm comm; 2495 PetscInt nvtxs = numVertices; // The number of vertices in full graph 2496 PetscInt *vtxdist; // Distribution of vertices across processes 2497 PetscInt *xadj = start; // Start of edge list for each vertex 2498 PetscInt *adjncy = adjacency; // Edge lists for all vertices 2499 PetscInt *vwgt = NULL; // Vertex weights 2500 PetscInt *adjwgt = NULL; // Edge weights 2501 PetscInt wgtflag = 0; // Indicates which weights are present 2502 PetscInt numflag = 0; // Indicates initial offset (0 or 1) 2503 PetscInt ncon = 1; // The number of weights per vertex 2504 PetscInt nparts; // The number of partitions 2505 PetscReal *tpwgts; // The fraction of vertex weights assigned to each partition 2506 PetscReal *ubvec; // The balance intolerance for vertex weights 2507 PetscInt options[5]; // Options 2508 // Outputs 2509 PetscInt edgeCut; // The number of edges cut by the partition 2510 PetscInt *assignment, *points; 2511 PetscMPIInt commSize, rank, p, v, i; 2512 PetscErrorCode ierr; 2513 2514 PetscFunctionBegin; 2515 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 2516 ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr); 2517 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 2518 nparts = commSize; 2519 options[0] = 0; /* Use all defaults */ 2520 /* Calculate vertex distribution */ 2521 ierr = PetscMalloc4(nparts+1,PetscInt,&vtxdist,nparts*ncon,PetscReal,&tpwgts,ncon,PetscReal,&ubvec,nvtxs,PetscInt,&assignment);CHKERRQ(ierr); 2522 vtxdist[0] = 0; 2523 ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr); 2524 for (p = 2; p <= nparts; ++p) { 2525 vtxdist[p] += vtxdist[p-1]; 2526 } 2527 /* Calculate weights */ 2528 for (p = 0; p < nparts; ++p) { 2529 tpwgts[p] = 1.0/nparts; 2530 } 2531 ubvec[0] = 1.05; 2532 2533 if (nparts == 1) { 2534 ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt)); 2535 } else { 2536 if (vtxdist[1] == vtxdist[nparts]) { 2537 if (!rank) { 2538 PetscStackPush("METIS_PartGraphKway"); 2539 ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment); 2540 PetscStackPop; 2541 if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()"); 2542 } 2543 } else { 2544 PetscStackPush("ParMETIS_V3_PartKway"); 2545 ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm); 2546 PetscStackPop; 2547 if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()"); 2548 } 2549 } 2550 /* Convert to PetscSection+IS */ 2551 ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr); 2552 ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr); 2553 for (v = 0; v < nvtxs; ++v) { 2554 ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr); 2555 } 2556 ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr); 2557 ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr); 2558 for (p = 0, i = 0; p < commSize; ++p) { 2559 for (v = 0; v < nvtxs; ++v) { 2560 if (assignment[v] == p) points[i++] = v; 2561 } 2562 } 2563 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 2564 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2565 ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr); 2566 PetscFunctionReturn(0); 2567 } 2568 #endif 2569 2570 #undef __FUNCT__ 2571 #define __FUNCT__ "DMPlexEnlargePartition" 2572 /* Expand the partition by BFS on the adjacency graph */ 2573 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition) 2574 { 2575 PetscHashI h; 2576 const PetscInt *points; 2577 PetscInt **tmpPoints, *newPoints, totPoints = 0; 2578 PetscInt pStart, pEnd, part, q; 2579 PetscErrorCode ierr; 2580 2581 PetscFunctionBegin; 2582 PetscHashICreate(h); 2583 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr); 2584 ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr); 2585 ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr); 2586 ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr); 2587 ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr); 2588 for (part = pStart; part < pEnd; ++part) { 2589 PetscInt numPoints, nP, numNewPoints, off, p, n = 0; 2590 2591 PetscHashIClear(h); 2592 ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr); 2593 ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr); 2594 /* Add all existing points to h */ 2595 for (p = 0; p < numPoints; ++p) { 2596 const PetscInt point = points[off+p]; 2597 PetscHashIAdd(h, point, 1); 2598 } 2599 PetscHashISize(h, nP); 2600 if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP); 2601 /* Add all points in next BFS level */ 2602 /* TODO We are brute forcing here, but could check the adjacency size to find the boundary */ 2603 for (p = 0; p < numPoints; ++p) { 2604 const PetscInt point = points[off+p]; 2605 PetscInt s = start[point], e = start[point+1], a; 2606 2607 for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1); 2608 } 2609 PetscHashISize(h, numNewPoints); 2610 ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr); 2611 ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr); 2612 if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */ 2613 totPoints += numNewPoints; 2614 } 2615 ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr); 2616 PetscHashIDestroy(h); 2617 ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr); 2618 ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr); 2619 for (part = pStart, q = 0; part < pEnd; ++part) { 2620 PetscInt numPoints, p; 2621 2622 ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr); 2623 for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p]; 2624 ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr); 2625 } 2626 ierr = PetscFree(tmpPoints);CHKERRQ(ierr); 2627 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2628 PetscFunctionReturn(0); 2629 } 2630 2631 #undef __FUNCT__ 2632 #define __FUNCT__ "DMPlexCreatePartition" 2633 /* 2634 DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height 2635 2636 Collective on DM 2637 2638 Input Parameters: 2639 + dm - The DM 2640 . height - The height for points in the partition 2641 - enlarge - Expand each partition with neighbors 2642 2643 Output Parameters: 2644 + partSection - The PetscSection giving the division of points by partition 2645 . partition - The list of points by partition 2646 . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL 2647 - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL 2648 2649 Level: developer 2650 2651 .seealso DMPlexDistribute() 2652 */ 2653 PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition) 2654 { 2655 char partname[1024]; 2656 PetscBool isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg; 2657 PetscMPIInt size; 2658 PetscErrorCode ierr; 2659 2660 PetscFunctionBegin; 2661 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 2662 2663 *origPartSection = NULL; 2664 *origPartition = NULL; 2665 if (size == 1) { 2666 PetscInt *points; 2667 PetscInt cStart, cEnd, c; 2668 2669 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 2670 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr); 2671 ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr); 2672 ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr); 2673 ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr); 2674 ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr); 2675 for (c = cStart; c < cEnd; ++c) points[c] = c; 2676 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2677 PetscFunctionReturn(0); 2678 } 2679 ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);CHKERRQ(ierr); 2680 if (flg) name = partname; 2681 if (name) { 2682 ierr = PetscStrcmp(name, "chaco", &isChaco);CHKERRQ(ierr); 2683 ierr = PetscStrcmp(name, "metis", &isMetis);CHKERRQ(ierr); 2684 } 2685 if (height == 0) { 2686 PetscInt numVertices; 2687 PetscInt *start = NULL; 2688 PetscInt *adjacency = NULL; 2689 2690 ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr); 2691 if (!name || isChaco) { 2692 #if defined(PETSC_HAVE_CHACO) 2693 ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr); 2694 #else 2695 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco."); 2696 #endif 2697 } else if (isMetis) { 2698 #if defined(PETSC_HAVE_PARMETIS) 2699 ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr); 2700 #endif 2701 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name); 2702 if (enlarge) { 2703 *origPartSection = *partSection; 2704 *origPartition = *partition; 2705 2706 ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr); 2707 } 2708 ierr = PetscFree(start);CHKERRQ(ierr); 2709 ierr = PetscFree(adjacency);CHKERRQ(ierr); 2710 # if 0 2711 } else if (height == 1) { 2712 /* Build the dual graph for faces and partition the hypergraph */ 2713 PetscInt numEdges; 2714 2715 buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase()); 2716 GraphPartitioner().partition(numEdges, start, adjacency, partition, manager); 2717 destroyCSR(numEdges, start, adjacency); 2718 #endif 2719 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height); 2720 PetscFunctionReturn(0); 2721 } 2722 2723 #undef __FUNCT__ 2724 #define __FUNCT__ "DMPlexCreatePartitionClosure" 2725 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) 2726 { 2727 /* const PetscInt height = 0; */ 2728 const PetscInt *partArray; 2729 PetscInt *allPoints, *packPoints; 2730 PetscInt rStart, rEnd, rank, pStart, pEnd, newSize; 2731 PetscErrorCode ierr; 2732 PetscBT bt; 2733 PetscSegBuffer segpack,segpart; 2734 2735 PetscFunctionBegin; 2736 ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr); 2737 ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr); 2738 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); 2739 ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr); 2740 ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); 2741 ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr); 2742 ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr); 2743 ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr); 2744 for (rank = rStart; rank < rEnd; ++rank) { 2745 PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints; 2746 2747 ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr); 2748 ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr); 2749 for (p = 0; p < numPoints; ++p) { 2750 PetscInt point = partArray[offset+p], closureSize, c; 2751 PetscInt *closure = NULL; 2752 2753 /* TODO Include support for height > 0 case */ 2754 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 2755 for (c=0; c<closureSize; c++) { 2756 PetscInt cpoint = closure[c*2]; 2757 if (!PetscBTLookupSet(bt,cpoint-pStart)) { 2758 PetscInt *PETSC_RESTRICT pt; 2759 partSize++; 2760 ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr); 2761 *pt = cpoint; 2762 } 2763 } 2764 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 2765 } 2766 ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr); 2767 ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr); 2768 ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr); 2769 ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr); 2770 for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);} 2771 } 2772 ierr = PetscBTDestroy(&bt);CHKERRQ(ierr); 2773 ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr); 2774 2775 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 2776 ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr); 2777 ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr); 2778 2779 ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr); 2780 for (rank = rStart; rank < rEnd; ++rank) { 2781 PetscInt numPoints, offset; 2782 2783 ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr); 2784 ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr); 2785 ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr); 2786 packPoints += numPoints; 2787 } 2788 2789 ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr); 2790 ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr); 2791 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 2792 PetscFunctionReturn(0); 2793 } 2794 2795 #undef __FUNCT__ 2796 #define __FUNCT__ "DMPlexDistributeField" 2797 /*@ 2798 DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution 2799 2800 Collective on DM 2801 2802 Input Parameters: 2803 + dm - The DMPlex object 2804 . pointSF - The PetscSF describing the communication pattern 2805 . originalSection - The PetscSection for existing data layout 2806 - originalVec - The existing data 2807 2808 Output Parameters: 2809 + newSection - The PetscSF describing the new data layout 2810 - newVec - The new data 2811 2812 Level: developer 2813 2814 .seealso: DMPlexDistribute(), DMPlexDistributeData() 2815 @*/ 2816 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec) 2817 { 2818 PetscSF fieldSF; 2819 PetscInt *remoteOffsets, fieldSize; 2820 PetscScalar *originalValues, *newValues; 2821 PetscErrorCode ierr; 2822 2823 PetscFunctionBegin; 2824 ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr); 2825 2826 ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr); 2827 ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr); 2828 ierr = VecSetType(newVec,dm->vectype);CHKERRQ(ierr); 2829 2830 ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr); 2831 ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr); 2832 ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr); 2833 ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr); 2834 ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr); 2835 ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr); 2836 ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr); 2837 ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr); 2838 PetscFunctionReturn(0); 2839 } 2840 2841 #undef __FUNCT__ 2842 #define __FUNCT__ "DMPlexDistributeData" 2843 /*@ 2844 DMPlexDistributeData - 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 . datatype - The type of data 2853 - originalData - The existing data 2854 2855 Output Parameters: 2856 + newSection - The PetscSF describing the new data layout 2857 - newData - The new data 2858 2859 Level: developer 2860 2861 .seealso: DMPlexDistribute(), DMPlexDistributeField() 2862 @*/ 2863 PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData) 2864 { 2865 PetscSF fieldSF; 2866 PetscInt *remoteOffsets, fieldSize; 2867 PetscMPIInt dataSize; 2868 PetscErrorCode ierr; 2869 2870 PetscFunctionBegin; 2871 ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr); 2872 2873 ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr); 2874 ierr = MPI_Type_size(datatype, &dataSize);CHKERRQ(ierr); 2875 ierr = PetscMalloc(fieldSize * dataSize, newData);CHKERRQ(ierr); 2876 2877 ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr); 2878 ierr = PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr); 2879 ierr = PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr); 2880 ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr); 2881 PetscFunctionReturn(0); 2882 } 2883 2884 #undef __FUNCT__ 2885 #define __FUNCT__ "DMPlexDistribute" 2886 /*@C 2887 DMPlexDistribute - Distributes the mesh and any associated sections. 2888 2889 Not Collective 2890 2891 Input Parameter: 2892 + dm - The original DMPlex object 2893 . partitioner - The partitioning package, or NULL for the default 2894 - overlap - The overlap of partitions, 0 is the default 2895 2896 Output Parameter: 2897 + sf - The PetscSF used for point distribution 2898 - parallelMesh - The distributed DMPlex object, or NULL 2899 2900 Note: If the mesh was not distributed, the return value is NULL 2901 2902 Level: intermediate 2903 2904 .keywords: mesh, elements 2905 .seealso: DMPlexCreate(), DMPlexDistributeByFace() 2906 @*/ 2907 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel) 2908 { 2909 DM_Plex *mesh = (DM_Plex*) dm->data, *pmesh; 2910 MPI_Comm comm; 2911 const PetscInt height = 0; 2912 PetscInt dim, numRemoteRanks; 2913 IS origCellPart, cellPart, part; 2914 PetscSection origCellPartSection, cellPartSection, partSection; 2915 PetscSFNode *remoteRanks; 2916 PetscSF partSF, pointSF, coneSF; 2917 ISLocalToGlobalMapping renumbering; 2918 PetscSection originalConeSection, newConeSection; 2919 PetscInt *remoteOffsets; 2920 PetscInt *cones, *newCones, newConesSize; 2921 PetscBool flg; 2922 PetscMPIInt rank, numProcs, p; 2923 PetscErrorCode ierr; 2924 2925 PetscFunctionBegin; 2926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2927 if (sf) PetscValidPointer(sf,4); 2928 PetscValidPointer(dmParallel,5); 2929 2930 ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr); 2931 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 2932 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 2933 ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr); 2934 2935 *dmParallel = NULL; 2936 if (numProcs == 1) PetscFunctionReturn(0); 2937 2938 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 2939 /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */ 2940 ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr); 2941 if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented"); 2942 ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr); 2943 /* Create SF assuming a serial partition for all processes: Could check for IS length here */ 2944 if (!rank) numRemoteRanks = numProcs; 2945 else numRemoteRanks = 0; 2946 ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr); 2947 for (p = 0; p < numRemoteRanks; ++p) { 2948 remoteRanks[p].rank = p; 2949 remoteRanks[p].index = 0; 2950 } 2951 ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr); 2952 ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr); 2953 ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr); 2954 if (flg) { 2955 ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr); 2956 ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 2957 ierr = ISView(cellPart, NULL);CHKERRQ(ierr); 2958 if (origCellPart) { 2959 ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr); 2960 ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 2961 ierr = ISView(origCellPart, NULL);CHKERRQ(ierr); 2962 } 2963 ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr); 2964 } 2965 /* Close the partition over the mesh */ 2966 ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr); 2967 ierr = ISDestroy(&cellPart);CHKERRQ(ierr); 2968 ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr); 2969 /* Create new mesh */ 2970 ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr); 2971 ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr); 2972 ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr); 2973 pmesh = (DM_Plex*) (*dmParallel)->data; 2974 /* Distribute sieve points and the global point numbering (replaces creating remote bases) */ 2975 ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr); 2976 if (flg) { 2977 ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr); 2978 ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 2979 ierr = ISView(part, NULL);CHKERRQ(ierr); 2980 ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr); 2981 ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr); 2982 ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr); 2983 } 2984 ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr); 2985 /* Distribute cone section */ 2986 ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr); 2987 ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr); 2988 ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr); 2989 ierr = DMSetUp(*dmParallel);CHKERRQ(ierr); 2990 { 2991 PetscInt pStart, pEnd, p; 2992 2993 ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr); 2994 for (p = pStart; p < pEnd; ++p) { 2995 PetscInt coneSize; 2996 ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr); 2997 pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize); 2998 } 2999 } 3000 /* Communicate and renumber cones */ 3001 ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr); 3002 ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr); 3003 ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr); 3004 ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); 3005 ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); 3006 ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr); 3007 ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr); 3008 ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr); 3009 if (flg) { 3010 ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr); 3011 ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 3012 ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr); 3013 ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 3014 ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr); 3015 } 3016 ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr); 3017 ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr); 3018 ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); 3019 ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr); 3020 ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr); 3021 /* Create supports and stratify sieve */ 3022 { 3023 PetscInt pStart, pEnd; 3024 3025 ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 3026 ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 3027 } 3028 ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr); 3029 ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr); 3030 /* Distribute Coordinates */ 3031 { 3032 PetscSection originalCoordSection, newCoordSection; 3033 Vec originalCoordinates, newCoordinates; 3034 const char *name; 3035 3036 ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr); 3037 ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr); 3038 ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr); 3039 ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr); 3040 ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr); 3041 ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr); 3042 3043 ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr); 3044 ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr); 3045 ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr); 3046 } 3047 /* Distribute labels */ 3048 ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr); 3049 { 3050 DMLabel next = mesh->labels, newNext = pmesh->labels; 3051 PetscInt numLabels = 0, l; 3052 3053 /* Bcast number of labels */ 3054 while (next) {++numLabels; next = next->next;} 3055 ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 3056 next = mesh->labels; 3057 for (l = 0; l < numLabels; ++l) { 3058 DMLabel labelNew; 3059 PetscBool isdepth; 3060 3061 /* Skip "depth" because it is recreated */ 3062 if (!rank) {ierr = PetscStrcmp(next->name, "depth", &isdepth);CHKERRQ(ierr);} 3063 ierr = MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr); 3064 if (isdepth) {if (!rank) next = next->next; continue;} 3065 ierr = DMLabelDistribute(next, partSection, part, renumbering, &labelNew);CHKERRQ(ierr); 3066 /* Insert into list */ 3067 if (newNext) newNext->next = labelNew; 3068 else pmesh->labels = labelNew; 3069 newNext = labelNew; 3070 if (!rank) next = next->next; 3071 } 3072 } 3073 ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr); 3074 /* Setup hybrid structure */ 3075 { 3076 const PetscInt *gpoints; 3077 PetscInt depth, n, d; 3078 3079 for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];} 3080 ierr = MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);CHKERRQ(ierr); 3081 ierr = ISLocalToGlobalMappingGetSize(renumbering, &n);CHKERRQ(ierr); 3082 ierr = ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);CHKERRQ(ierr); 3083 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3084 for (d = 0; d <= dim; ++d) { 3085 PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p; 3086 3087 if (pmax < 0) continue; 3088 ierr = DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);CHKERRQ(ierr); 3089 ierr = DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);CHKERRQ(ierr); 3090 ierr = MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);CHKERRQ(ierr); 3091 for (p = 0; p < n; ++p) { 3092 const PetscInt point = gpoints[p]; 3093 3094 if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax; 3095 } 3096 if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax; 3097 else pmesh->hybridPointMax[d] = -1; 3098 } 3099 ierr = ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);CHKERRQ(ierr); 3100 } 3101 /* Cleanup Partition */ 3102 ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr); 3103 ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr); 3104 ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr); 3105 ierr = ISDestroy(&part);CHKERRQ(ierr); 3106 /* Create point SF for parallel mesh */ 3107 ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr); 3108 { 3109 const PetscInt *leaves; 3110 PetscSFNode *remotePoints, *rowners, *lowners; 3111 PetscInt numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints; 3112 PetscInt pStart, pEnd; 3113 3114 ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr); 3115 ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr); 3116 ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr); 3117 for (p=0; p<numRoots; p++) { 3118 rowners[p].rank = -1; 3119 rowners[p].index = -1; 3120 } 3121 if (origCellPart) { 3122 /* Make sure cells in the original partition are not assigned to other procs */ 3123 const PetscInt *origCells; 3124 3125 ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr); 3126 for (p = 0; p < numProcs; ++p) { 3127 PetscInt dof, off, d; 3128 3129 ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr); 3130 ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr); 3131 for (d = off; d < off+dof; ++d) { 3132 rowners[origCells[d]].rank = p; 3133 } 3134 } 3135 ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr); 3136 } 3137 ierr = ISDestroy(&origCellPart);CHKERRQ(ierr); 3138 ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr); 3139 3140 ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); 3141 ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); 3142 for (p = 0; p < numLeaves; ++p) { 3143 if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */ 3144 lowners[p].rank = rank; 3145 lowners[p].index = leaves ? leaves[p] : p; 3146 } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */ 3147 lowners[p].rank = -2; 3148 lowners[p].index = -2; 3149 } 3150 } 3151 for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */ 3152 rowners[p].rank = -3; 3153 rowners[p].index = -3; 3154 } 3155 ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr); 3156 ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr); 3157 ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); 3158 ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr); 3159 for (p = 0; p < numLeaves; ++p) { 3160 if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed"); 3161 if (lowners[p].rank != rank) ++numGhostPoints; 3162 } 3163 ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt), &ghostPoints);CHKERRQ(ierr); 3164 ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr); 3165 for (p = 0, gp = 0; p < numLeaves; ++p) { 3166 if (lowners[p].rank != rank) { 3167 ghostPoints[gp] = leaves ? leaves[p] : p; 3168 remotePoints[gp].rank = lowners[p].rank; 3169 remotePoints[gp].index = lowners[p].index; 3170 ++gp; 3171 } 3172 } 3173 ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr); 3174 ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr); 3175 ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr); 3176 } 3177 ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr); 3178 /* Cleanup */ 3179 if (sf) {*sf = pointSF;} 3180 else {ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);} 3181 ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr); 3182 ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr); 3183 PetscFunctionReturn(0); 3184 } 3185 3186 #undef __FUNCT__ 3187 #define __FUNCT__ "DMPlexInvertCell" 3188 /*@C 3189 DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched. 3190 3191 Input Parameters: 3192 + numCorners - The number of vertices in a cell 3193 - cone - The incoming cone 3194 3195 Output Parameter: 3196 . cone - The inverted cone (in-place) 3197 3198 Level: developer 3199 3200 .seealso: DMPlexGenerate() 3201 @*/ 3202 PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[]) 3203 { 3204 int tmpc; 3205 3206 PetscFunctionBegin; 3207 if (dim != 3) PetscFunctionReturn(0); 3208 switch (numCorners) { 3209 case 4: 3210 tmpc = cone[0]; 3211 cone[0] = cone[1]; 3212 cone[1] = tmpc; 3213 break; 3214 case 8: 3215 tmpc = cone[1]; 3216 cone[1] = cone[3]; 3217 cone[3] = tmpc; 3218 break; 3219 default: break; 3220 } 3221 PetscFunctionReturn(0); 3222 } 3223 3224 #undef __FUNCT__ 3225 #define __FUNCT__ "DMPlexInvertCells_Internal" 3226 /* This is to fix the tetrahedron orientation from TetGen */ 3227 PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[]) 3228 { 3229 PetscInt bound = numCells*numCorners, coff; 3230 PetscErrorCode ierr; 3231 3232 PetscFunctionBegin; 3233 for (coff = 0; coff < bound; coff += numCorners) { 3234 ierr = DMPlexInvertCell(dim, numCorners, &cells[coff]);CHKERRQ(ierr); 3235 } 3236 PetscFunctionReturn(0); 3237 } 3238 3239 #if defined(PETSC_HAVE_TRIANGLE) 3240 #include <triangle.h> 3241 3242 #undef __FUNCT__ 3243 #define __FUNCT__ "InitInput_Triangle" 3244 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) 3245 { 3246 PetscFunctionBegin; 3247 inputCtx->numberofpoints = 0; 3248 inputCtx->numberofpointattributes = 0; 3249 inputCtx->pointlist = NULL; 3250 inputCtx->pointattributelist = NULL; 3251 inputCtx->pointmarkerlist = NULL; 3252 inputCtx->numberofsegments = 0; 3253 inputCtx->segmentlist = NULL; 3254 inputCtx->segmentmarkerlist = NULL; 3255 inputCtx->numberoftriangleattributes = 0; 3256 inputCtx->trianglelist = NULL; 3257 inputCtx->numberofholes = 0; 3258 inputCtx->holelist = NULL; 3259 inputCtx->numberofregions = 0; 3260 inputCtx->regionlist = NULL; 3261 PetscFunctionReturn(0); 3262 } 3263 3264 #undef __FUNCT__ 3265 #define __FUNCT__ "InitOutput_Triangle" 3266 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) 3267 { 3268 PetscFunctionBegin; 3269 outputCtx->numberofpoints = 0; 3270 outputCtx->pointlist = NULL; 3271 outputCtx->pointattributelist = NULL; 3272 outputCtx->pointmarkerlist = NULL; 3273 outputCtx->numberoftriangles = 0; 3274 outputCtx->trianglelist = NULL; 3275 outputCtx->triangleattributelist = NULL; 3276 outputCtx->neighborlist = NULL; 3277 outputCtx->segmentlist = NULL; 3278 outputCtx->segmentmarkerlist = NULL; 3279 outputCtx->numberofedges = 0; 3280 outputCtx->edgelist = NULL; 3281 outputCtx->edgemarkerlist = NULL; 3282 PetscFunctionReturn(0); 3283 } 3284 3285 #undef __FUNCT__ 3286 #define __FUNCT__ "FiniOutput_Triangle" 3287 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) 3288 { 3289 PetscFunctionBegin; 3290 free(outputCtx->pointmarkerlist); 3291 free(outputCtx->edgelist); 3292 free(outputCtx->edgemarkerlist); 3293 free(outputCtx->trianglelist); 3294 free(outputCtx->neighborlist); 3295 PetscFunctionReturn(0); 3296 } 3297 3298 #undef __FUNCT__ 3299 #define __FUNCT__ "DMPlexGenerate_Triangle" 3300 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm) 3301 { 3302 MPI_Comm comm; 3303 PetscInt dim = 2; 3304 const PetscBool createConvexHull = PETSC_FALSE; 3305 const PetscBool constrained = PETSC_FALSE; 3306 struct triangulateio in; 3307 struct triangulateio out; 3308 PetscInt vStart, vEnd, v, eStart, eEnd, e; 3309 PetscMPIInt rank; 3310 PetscErrorCode ierr; 3311 3312 PetscFunctionBegin; 3313 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 3314 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3315 ierr = InitInput_Triangle(&in);CHKERRQ(ierr); 3316 ierr = InitOutput_Triangle(&out);CHKERRQ(ierr); 3317 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 3318 3319 in.numberofpoints = vEnd - vStart; 3320 if (in.numberofpoints > 0) { 3321 PetscSection coordSection; 3322 Vec coordinates; 3323 PetscScalar *array; 3324 3325 ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr); 3326 ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr); 3327 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 3328 ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 3329 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3330 for (v = vStart; v < vEnd; ++v) { 3331 const PetscInt idx = v - vStart; 3332 PetscInt off, d; 3333 3334 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3335 for (d = 0; d < dim; ++d) { 3336 in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 3337 } 3338 ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3339 } 3340 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3341 } 3342 ierr = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr); 3343 in.numberofsegments = eEnd - eStart; 3344 if (in.numberofsegments > 0) { 3345 ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr); 3346 ierr = PetscMalloc(in.numberofsegments * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr); 3347 for (e = eStart; e < eEnd; ++e) { 3348 const PetscInt idx = e - eStart; 3349 const PetscInt *cone; 3350 3351 ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr); 3352 3353 in.segmentlist[idx*2+0] = cone[0] - vStart; 3354 in.segmentlist[idx*2+1] = cone[1] - vStart; 3355 3356 ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr); 3357 } 3358 } 3359 #if 0 /* Do not currently support holes */ 3360 PetscReal *holeCoords; 3361 PetscInt h, d; 3362 3363 ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr); 3364 if (in.numberofholes > 0) { 3365 ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr); 3366 for (h = 0; h < in.numberofholes; ++h) { 3367 for (d = 0; d < dim; ++d) { 3368 in.holelist[h*dim+d] = holeCoords[h*dim+d]; 3369 } 3370 } 3371 } 3372 #endif 3373 if (!rank) { 3374 char args[32]; 3375 3376 /* Take away 'Q' for verbose output */ 3377 ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr); 3378 if (createConvexHull) { 3379 ierr = PetscStrcat(args, "c");CHKERRQ(ierr); 3380 } 3381 if (constrained) { 3382 ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr); 3383 } 3384 triangulate(args, &in, &out, NULL); 3385 } 3386 ierr = PetscFree(in.pointlist);CHKERRQ(ierr); 3387 ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr); 3388 ierr = PetscFree(in.segmentlist);CHKERRQ(ierr); 3389 ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr); 3390 ierr = PetscFree(in.holelist);CHKERRQ(ierr); 3391 3392 { 3393 const PetscInt numCorners = 3; 3394 const PetscInt numCells = out.numberoftriangles; 3395 const PetscInt numVertices = out.numberofpoints; 3396 const int *cells = out.trianglelist; 3397 const double *meshCoords = out.pointlist; 3398 3399 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 3400 /* Set labels */ 3401 for (v = 0; v < numVertices; ++v) { 3402 if (out.pointmarkerlist[v]) { 3403 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3404 } 3405 } 3406 if (interpolate) { 3407 for (e = 0; e < out.numberofedges; e++) { 3408 if (out.edgemarkerlist[e]) { 3409 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3410 const PetscInt *edges; 3411 PetscInt numEdges; 3412 3413 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3414 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3415 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3416 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3417 } 3418 } 3419 } 3420 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 3421 } 3422 #if 0 /* Do not currently support holes */ 3423 ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr); 3424 #endif 3425 ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr); 3426 PetscFunctionReturn(0); 3427 } 3428 3429 #undef __FUNCT__ 3430 #define __FUNCT__ "DMPlexRefine_Triangle" 3431 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined) 3432 { 3433 MPI_Comm comm; 3434 PetscInt dim = 2; 3435 struct triangulateio in; 3436 struct triangulateio out; 3437 PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 3438 PetscMPIInt rank; 3439 PetscErrorCode ierr; 3440 3441 PetscFunctionBegin; 3442 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3443 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3444 ierr = InitInput_Triangle(&in);CHKERRQ(ierr); 3445 ierr = InitOutput_Triangle(&out);CHKERRQ(ierr); 3446 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3447 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 3448 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3449 3450 in.numberofpoints = vEnd - vStart; 3451 if (in.numberofpoints > 0) { 3452 PetscSection coordSection; 3453 Vec coordinates; 3454 PetscScalar *array; 3455 3456 ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr); 3457 ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr); 3458 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3459 ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3460 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3461 for (v = vStart; v < vEnd; ++v) { 3462 const PetscInt idx = v - vStart; 3463 PetscInt off, d; 3464 3465 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3466 for (d = 0; d < dim; ++d) { 3467 in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 3468 } 3469 ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3470 } 3471 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3472 } 3473 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3474 3475 in.numberofcorners = 3; 3476 in.numberoftriangles = cEnd - cStart; 3477 3478 in.trianglearealist = (double*) maxVolumes; 3479 if (in.numberoftriangles > 0) { 3480 ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr); 3481 for (c = cStart; c < cEnd; ++c) { 3482 const PetscInt idx = c - cStart; 3483 PetscInt *closure = NULL; 3484 PetscInt closureSize; 3485 3486 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3487 if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize); 3488 for (v = 0; v < 3; ++v) { 3489 in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart; 3490 } 3491 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3492 } 3493 } 3494 /* TODO: Segment markers are missing on input */ 3495 #if 0 /* Do not currently support holes */ 3496 PetscReal *holeCoords; 3497 PetscInt h, d; 3498 3499 ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr); 3500 if (in.numberofholes > 0) { 3501 ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr); 3502 for (h = 0; h < in.numberofholes; ++h) { 3503 for (d = 0; d < dim; ++d) { 3504 in.holelist[h*dim+d] = holeCoords[h*dim+d]; 3505 } 3506 } 3507 } 3508 #endif 3509 if (!rank) { 3510 char args[32]; 3511 3512 /* Take away 'Q' for verbose output */ 3513 ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr); 3514 triangulate(args, &in, &out, NULL); 3515 } 3516 ierr = PetscFree(in.pointlist);CHKERRQ(ierr); 3517 ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr); 3518 ierr = PetscFree(in.segmentlist);CHKERRQ(ierr); 3519 ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr); 3520 ierr = PetscFree(in.trianglelist);CHKERRQ(ierr); 3521 3522 { 3523 const PetscInt numCorners = 3; 3524 const PetscInt numCells = out.numberoftriangles; 3525 const PetscInt numVertices = out.numberofpoints; 3526 const int *cells = out.trianglelist; 3527 const double *meshCoords = out.pointlist; 3528 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 3529 3530 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 3531 /* Set labels */ 3532 for (v = 0; v < numVertices; ++v) { 3533 if (out.pointmarkerlist[v]) { 3534 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3535 } 3536 } 3537 if (interpolate) { 3538 PetscInt e; 3539 3540 for (e = 0; e < out.numberofedges; e++) { 3541 if (out.edgemarkerlist[e]) { 3542 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3543 const PetscInt *edges; 3544 PetscInt numEdges; 3545 3546 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3547 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3548 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3549 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3550 } 3551 } 3552 } 3553 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 3554 } 3555 #if 0 /* Do not currently support holes */ 3556 ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr); 3557 #endif 3558 ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr); 3559 PetscFunctionReturn(0); 3560 } 3561 #endif 3562 3563 #if defined(PETSC_HAVE_TETGEN) 3564 #include <tetgen.h> 3565 #undef __FUNCT__ 3566 #define __FUNCT__ "DMPlexGenerate_Tetgen" 3567 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm) 3568 { 3569 MPI_Comm comm; 3570 const PetscInt dim = 3; 3571 ::tetgenio in; 3572 ::tetgenio out; 3573 PetscInt vStart, vEnd, v, fStart, fEnd, f; 3574 PetscMPIInt rank; 3575 PetscErrorCode ierr; 3576 3577 PetscFunctionBegin; 3578 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 3579 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3580 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 3581 in.numberofpoints = vEnd - vStart; 3582 if (in.numberofpoints > 0) { 3583 PetscSection coordSection; 3584 Vec coordinates; 3585 PetscScalar *array; 3586 3587 in.pointlist = new double[in.numberofpoints*dim]; 3588 in.pointmarkerlist = new int[in.numberofpoints]; 3589 3590 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 3591 ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 3592 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3593 for (v = vStart; v < vEnd; ++v) { 3594 const PetscInt idx = v - vStart; 3595 PetscInt off, d; 3596 3597 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3598 for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d]; 3599 ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3600 } 3601 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3602 } 3603 ierr = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr); 3604 3605 in.numberoffacets = fEnd - fStart; 3606 if (in.numberoffacets > 0) { 3607 in.facetlist = new tetgenio::facet[in.numberoffacets]; 3608 in.facetmarkerlist = new int[in.numberoffacets]; 3609 for (f = fStart; f < fEnd; ++f) { 3610 const PetscInt idx = f - fStart; 3611 PetscInt *points = NULL, numPoints, p, numVertices = 0, v; 3612 3613 in.facetlist[idx].numberofpolygons = 1; 3614 in.facetlist[idx].polygonlist = new tetgenio::polygon[in.facetlist[idx].numberofpolygons]; 3615 in.facetlist[idx].numberofholes = 0; 3616 in.facetlist[idx].holelist = NULL; 3617 3618 ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3619 for (p = 0; p < numPoints*2; p += 2) { 3620 const PetscInt point = points[p]; 3621 if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point; 3622 } 3623 3624 tetgenio::polygon *poly = in.facetlist[idx].polygonlist; 3625 poly->numberofvertices = numVertices; 3626 poly->vertexlist = new int[poly->numberofvertices]; 3627 for (v = 0; v < numVertices; ++v) { 3628 const PetscInt vIdx = points[v] - vStart; 3629 poly->vertexlist[v] = vIdx; 3630 } 3631 ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr); 3632 ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3633 } 3634 } 3635 if (!rank) { 3636 char args[32]; 3637 3638 /* Take away 'Q' for verbose output */ 3639 ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr); 3640 ::tetrahedralize(args, &in, &out); 3641 } 3642 { 3643 const PetscInt numCorners = 4; 3644 const PetscInt numCells = out.numberoftetrahedra; 3645 const PetscInt numVertices = out.numberofpoints; 3646 const double *meshCoords = out.pointlist; 3647 int *cells = out.tetrahedronlist; 3648 3649 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3650 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 3651 /* Set labels */ 3652 for (v = 0; v < numVertices; ++v) { 3653 if (out.pointmarkerlist[v]) { 3654 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3655 } 3656 } 3657 if (interpolate) { 3658 PetscInt e; 3659 3660 for (e = 0; e < out.numberofedges; e++) { 3661 if (out.edgemarkerlist[e]) { 3662 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3663 const PetscInt *edges; 3664 PetscInt numEdges; 3665 3666 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3667 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3668 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3669 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3670 } 3671 } 3672 for (f = 0; f < out.numberoftrifaces; f++) { 3673 if (out.trifacemarkerlist[f]) { 3674 const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells}; 3675 const PetscInt *faces; 3676 PetscInt numFaces; 3677 3678 ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3679 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3680 ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr); 3681 ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3682 } 3683 } 3684 } 3685 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 3686 } 3687 PetscFunctionReturn(0); 3688 } 3689 3690 #undef __FUNCT__ 3691 #define __FUNCT__ "DMPlexRefine_Tetgen" 3692 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined) 3693 { 3694 MPI_Comm comm; 3695 const PetscInt dim = 3; 3696 ::tetgenio in; 3697 ::tetgenio out; 3698 PetscInt vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 3699 PetscMPIInt rank; 3700 PetscErrorCode ierr; 3701 3702 PetscFunctionBegin; 3703 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3704 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3705 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3706 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 3707 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3708 3709 in.numberofpoints = vEnd - vStart; 3710 if (in.numberofpoints > 0) { 3711 PetscSection coordSection; 3712 Vec coordinates; 3713 PetscScalar *array; 3714 3715 in.pointlist = new double[in.numberofpoints*dim]; 3716 in.pointmarkerlist = new int[in.numberofpoints]; 3717 3718 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3719 ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3720 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3721 for (v = vStart; v < vEnd; ++v) { 3722 const PetscInt idx = v - vStart; 3723 PetscInt off, d; 3724 3725 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3726 for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d]; 3727 ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr); 3728 } 3729 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3730 } 3731 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 3732 3733 in.numberofcorners = 4; 3734 in.numberoftetrahedra = cEnd - cStart; 3735 in.tetrahedronvolumelist = (double*) maxVolumes; 3736 if (in.numberoftetrahedra > 0) { 3737 in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners]; 3738 for (c = cStart; c < cEnd; ++c) { 3739 const PetscInt idx = c - cStart; 3740 PetscInt *closure = NULL; 3741 PetscInt closureSize; 3742 3743 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3744 if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize); 3745 for (v = 0; v < 4; ++v) { 3746 in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart; 3747 } 3748 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 3749 } 3750 } 3751 /* TODO: Put in boundary faces with markers */ 3752 if (!rank) { 3753 char args[32]; 3754 3755 /* Take away 'Q' for verbose output */ 3756 /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */ 3757 ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr); 3758 ::tetrahedralize(args, &in, &out); 3759 } 3760 in.tetrahedronvolumelist = NULL; 3761 3762 { 3763 const PetscInt numCorners = 4; 3764 const PetscInt numCells = out.numberoftetrahedra; 3765 const PetscInt numVertices = out.numberofpoints; 3766 const double *meshCoords = out.pointlist; 3767 int *cells = out.tetrahedronlist; 3768 3769 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 3770 3771 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3772 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 3773 /* Set labels */ 3774 for (v = 0; v < numVertices; ++v) { 3775 if (out.pointmarkerlist[v]) { 3776 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr); 3777 } 3778 } 3779 if (interpolate) { 3780 PetscInt e, f; 3781 3782 for (e = 0; e < out.numberofedges; e++) { 3783 if (out.edgemarkerlist[e]) { 3784 const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells}; 3785 const PetscInt *edges; 3786 PetscInt numEdges; 3787 3788 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3789 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3790 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr); 3791 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3792 } 3793 } 3794 for (f = 0; f < out.numberoftrifaces; f++) { 3795 if (out.trifacemarkerlist[f]) { 3796 const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells}; 3797 const PetscInt *faces; 3798 PetscInt numFaces; 3799 3800 ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3801 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3802 ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr); 3803 ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3804 } 3805 } 3806 } 3807 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 3808 } 3809 PetscFunctionReturn(0); 3810 } 3811 #endif 3812 3813 #if defined(PETSC_HAVE_CTETGEN) 3814 #include "ctetgen.h" 3815 3816 #undef __FUNCT__ 3817 #define __FUNCT__ "DMPlexGenerate_CTetgen" 3818 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm) 3819 { 3820 MPI_Comm comm; 3821 const PetscInt dim = 3; 3822 PLC *in, *out; 3823 PetscInt verbose = 0, vStart, vEnd, v, fStart, fEnd, f; 3824 PetscMPIInt rank; 3825 PetscErrorCode ierr; 3826 3827 PetscFunctionBegin; 3828 ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr); 3829 ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr); 3830 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3831 ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr); 3832 ierr = PLCCreate(&in);CHKERRQ(ierr); 3833 ierr = PLCCreate(&out);CHKERRQ(ierr); 3834 3835 in->numberofpoints = vEnd - vStart; 3836 if (in->numberofpoints > 0) { 3837 PetscSection coordSection; 3838 Vec coordinates; 3839 PetscScalar *array; 3840 3841 ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr); 3842 ierr = PetscMalloc(in->numberofpoints * sizeof(int), &in->pointmarkerlist);CHKERRQ(ierr); 3843 ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr); 3844 ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr); 3845 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3846 for (v = vStart; v < vEnd; ++v) { 3847 const PetscInt idx = v - vStart; 3848 PetscInt off, d, m; 3849 3850 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3851 for (d = 0; d < dim; ++d) { 3852 in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 3853 } 3854 ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr); 3855 3856 in->pointmarkerlist[idx] = (int) m; 3857 } 3858 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 3859 } 3860 ierr = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr); 3861 3862 in->numberoffacets = fEnd - fStart; 3863 if (in->numberoffacets > 0) { 3864 ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr); 3865 ierr = PetscMalloc(in->numberoffacets * sizeof(int), &in->facetmarkerlist);CHKERRQ(ierr); 3866 for (f = fStart; f < fEnd; ++f) { 3867 const PetscInt idx = f - fStart; 3868 PetscInt *points = NULL, numPoints, p, numVertices = 0, v, m; 3869 polygon *poly; 3870 3871 in->facetlist[idx].numberofpolygons = 1; 3872 3873 ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr); 3874 3875 in->facetlist[idx].numberofholes = 0; 3876 in->facetlist[idx].holelist = NULL; 3877 3878 ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3879 for (p = 0; p < numPoints*2; p += 2) { 3880 const PetscInt point = points[p]; 3881 if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point; 3882 } 3883 3884 poly = in->facetlist[idx].polygonlist; 3885 poly->numberofvertices = numVertices; 3886 ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr); 3887 for (v = 0; v < numVertices; ++v) { 3888 const PetscInt vIdx = points[v] - vStart; 3889 poly->vertexlist[v] = vIdx; 3890 } 3891 ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr); 3892 in->facetmarkerlist[idx] = (int) m; 3893 ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 3894 } 3895 } 3896 if (!rank) { 3897 TetGenOpts t; 3898 3899 ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr); 3900 t.in = boundary; /* Should go away */ 3901 t.plc = 1; 3902 t.quality = 1; 3903 t.edgesout = 1; 3904 t.zeroindex = 1; 3905 t.quiet = 1; 3906 t.verbose = verbose; 3907 ierr = TetGenCheckOpts(&t);CHKERRQ(ierr); 3908 ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr); 3909 } 3910 { 3911 const PetscInt numCorners = 4; 3912 const PetscInt numCells = out->numberoftetrahedra; 3913 const PetscInt numVertices = out->numberofpoints; 3914 const double *meshCoords = out->pointlist; 3915 int *cells = out->tetrahedronlist; 3916 3917 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 3918 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr); 3919 /* Set labels */ 3920 for (v = 0; v < numVertices; ++v) { 3921 if (out->pointmarkerlist[v]) { 3922 ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr); 3923 } 3924 } 3925 if (interpolate) { 3926 PetscInt e; 3927 3928 for (e = 0; e < out->numberofedges; e++) { 3929 if (out->edgemarkerlist[e]) { 3930 const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells}; 3931 const PetscInt *edges; 3932 PetscInt numEdges; 3933 3934 ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3935 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 3936 ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr); 3937 ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 3938 } 3939 } 3940 for (f = 0; f < out->numberoftrifaces; f++) { 3941 if (out->trifacemarkerlist[f]) { 3942 const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells}; 3943 const PetscInt *faces; 3944 PetscInt numFaces; 3945 3946 ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3947 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 3948 ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr); 3949 ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 3950 } 3951 } 3952 } 3953 ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr); 3954 } 3955 3956 ierr = PLCDestroy(&in);CHKERRQ(ierr); 3957 ierr = PLCDestroy(&out);CHKERRQ(ierr); 3958 PetscFunctionReturn(0); 3959 } 3960 3961 #undef __FUNCT__ 3962 #define __FUNCT__ "DMPlexRefine_CTetgen" 3963 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined) 3964 { 3965 MPI_Comm comm; 3966 const PetscInt dim = 3; 3967 PLC *in, *out; 3968 PetscInt verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal; 3969 PetscMPIInt rank; 3970 PetscErrorCode ierr; 3971 3972 PetscFunctionBegin; 3973 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 3974 ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr); 3975 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 3976 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3977 ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 3978 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 3979 ierr = PLCCreate(&in);CHKERRQ(ierr); 3980 ierr = PLCCreate(&out);CHKERRQ(ierr); 3981 3982 in->numberofpoints = vEnd - vStart; 3983 if (in->numberofpoints > 0) { 3984 PetscSection coordSection; 3985 Vec coordinates; 3986 PetscScalar *array; 3987 3988 ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr); 3989 ierr = PetscMalloc(in->numberofpoints * sizeof(int), &in->pointmarkerlist);CHKERRQ(ierr); 3990 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 3991 ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 3992 ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr); 3993 for (v = vStart; v < vEnd; ++v) { 3994 const PetscInt idx = v - vStart; 3995 PetscInt off, d, m; 3996 3997 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 3998 for (d = 0; d < dim; ++d) { 3999 in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]); 4000 } 4001 ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr); 4002 4003 in->pointmarkerlist[idx] = (int) m; 4004 } 4005 ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr); 4006 } 4007 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 4008 4009 in->numberofcorners = 4; 4010 in->numberoftetrahedra = cEnd - cStart; 4011 in->tetrahedronvolumelist = maxVolumes; 4012 if (in->numberoftetrahedra > 0) { 4013 ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr); 4014 for (c = cStart; c < cEnd; ++c) { 4015 const PetscInt idx = c - cStart; 4016 PetscInt *closure = NULL; 4017 PetscInt closureSize; 4018 4019 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 4020 if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize); 4021 for (v = 0; v < 4; ++v) { 4022 in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart; 4023 } 4024 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 4025 } 4026 } 4027 if (!rank) { 4028 TetGenOpts t; 4029 4030 ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr); 4031 4032 t.in = dm; /* Should go away */ 4033 t.refine = 1; 4034 t.varvolume = 1; 4035 t.quality = 1; 4036 t.edgesout = 1; 4037 t.zeroindex = 1; 4038 t.quiet = 1; 4039 t.verbose = verbose; /* Change this */ 4040 4041 ierr = TetGenCheckOpts(&t);CHKERRQ(ierr); 4042 ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr); 4043 } 4044 { 4045 const PetscInt numCorners = 4; 4046 const PetscInt numCells = out->numberoftetrahedra; 4047 const PetscInt numVertices = out->numberofpoints; 4048 const double *meshCoords = out->pointlist; 4049 int *cells = out->tetrahedronlist; 4050 PetscBool interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE; 4051 4052 ierr = DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);CHKERRQ(ierr); 4053 ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr); 4054 /* Set labels */ 4055 for (v = 0; v < numVertices; ++v) { 4056 if (out->pointmarkerlist[v]) { 4057 ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr); 4058 } 4059 } 4060 if (interpolate) { 4061 PetscInt e, f; 4062 4063 for (e = 0; e < out->numberofedges; e++) { 4064 if (out->edgemarkerlist[e]) { 4065 const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells}; 4066 const PetscInt *edges; 4067 PetscInt numEdges; 4068 4069 ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 4070 if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges); 4071 ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr); 4072 ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr); 4073 } 4074 } 4075 for (f = 0; f < out->numberoftrifaces; f++) { 4076 if (out->trifacemarkerlist[f]) { 4077 const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells}; 4078 const PetscInt *faces; 4079 PetscInt numFaces; 4080 4081 ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 4082 if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces); 4083 ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr); 4084 ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr); 4085 } 4086 } 4087 } 4088 ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr); 4089 } 4090 ierr = PLCDestroy(&in);CHKERRQ(ierr); 4091 ierr = PLCDestroy(&out);CHKERRQ(ierr); 4092 PetscFunctionReturn(0); 4093 } 4094 #endif 4095 4096 #undef __FUNCT__ 4097 #define __FUNCT__ "DMPlexGenerate" 4098 /*@C 4099 DMPlexGenerate - Generates a mesh. 4100 4101 Not Collective 4102 4103 Input Parameters: 4104 + boundary - The DMPlex boundary object 4105 . name - The mesh generation package name 4106 - interpolate - Flag to create intermediate mesh elements 4107 4108 Output Parameter: 4109 . mesh - The DMPlex object 4110 4111 Level: intermediate 4112 4113 .keywords: mesh, elements 4114 .seealso: DMPlexCreate(), DMRefine() 4115 @*/ 4116 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh) 4117 { 4118 PetscInt dim; 4119 char genname[1024]; 4120 PetscBool isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg; 4121 PetscErrorCode ierr; 4122 4123 PetscFunctionBegin; 4124 PetscValidHeaderSpecific(boundary, DM_CLASSID, 1); 4125 PetscValidLogicalCollectiveBool(boundary, interpolate, 2); 4126 ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr); 4127 ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr); 4128 if (flg) name = genname; 4129 if (name) { 4130 ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr); 4131 ierr = PetscStrcmp(name, "tetgen", &isTetgen);CHKERRQ(ierr); 4132 ierr = PetscStrcmp(name, "ctetgen", &isCTetgen);CHKERRQ(ierr); 4133 } 4134 switch (dim) { 4135 case 1: 4136 if (!name || isTriangle) { 4137 #if defined(PETSC_HAVE_TRIANGLE) 4138 ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr); 4139 #else 4140 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle."); 4141 #endif 4142 } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name); 4143 break; 4144 case 2: 4145 if (!name || isCTetgen) { 4146 #if defined(PETSC_HAVE_CTETGEN) 4147 ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr); 4148 #else 4149 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen."); 4150 #endif 4151 } else if (isTetgen) { 4152 #if defined(PETSC_HAVE_TETGEN) 4153 ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr); 4154 #else 4155 SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen."); 4156 #endif 4157 } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name); 4158 break; 4159 default: 4160 SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim); 4161 } 4162 PetscFunctionReturn(0); 4163 } 4164 4165 #undef __FUNCT__ 4166 #define __FUNCT__ "DMRefine_Plex" 4167 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined) 4168 { 4169 PetscReal refinementLimit; 4170 PetscInt dim, cStart, cEnd; 4171 char genname[1024], *name = NULL; 4172 PetscBool isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg; 4173 PetscErrorCode ierr; 4174 4175 PetscFunctionBegin; 4176 ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr); 4177 if (isUniform) { 4178 CellRefiner cellRefiner; 4179 4180 ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr); 4181 ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr); 4182 PetscFunctionReturn(0); 4183 } 4184 ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr); 4185 if (refinementLimit == 0.0) PetscFunctionReturn(0); 4186 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 4187 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 4188 ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr); 4189 if (flg) name = genname; 4190 if (name) { 4191 ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr); 4192 ierr = PetscStrcmp(name, "tetgen", &isTetgen);CHKERRQ(ierr); 4193 ierr = PetscStrcmp(name, "ctetgen", &isCTetgen);CHKERRQ(ierr); 4194 } 4195 switch (dim) { 4196 case 2: 4197 if (!name || isTriangle) { 4198 #if defined(PETSC_HAVE_TRIANGLE) 4199 double *maxVolumes; 4200 PetscInt c; 4201 4202 ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr); 4203 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 4204 ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 4205 ierr = PetscFree(maxVolumes);CHKERRQ(ierr); 4206 #else 4207 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle."); 4208 #endif 4209 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name); 4210 break; 4211 case 3: 4212 if (!name || isCTetgen) { 4213 #if defined(PETSC_HAVE_CTETGEN) 4214 PetscReal *maxVolumes; 4215 PetscInt c; 4216 4217 ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr); 4218 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 4219 ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 4220 #else 4221 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen."); 4222 #endif 4223 } else if (isTetgen) { 4224 #if defined(PETSC_HAVE_TETGEN) 4225 double *maxVolumes; 4226 PetscInt c; 4227 4228 ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr); 4229 for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit; 4230 ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr); 4231 #else 4232 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen."); 4233 #endif 4234 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name); 4235 break; 4236 default: 4237 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim); 4238 } 4239 PetscFunctionReturn(0); 4240 } 4241 4242 #undef __FUNCT__ 4243 #define __FUNCT__ "DMPlexGetDepthLabel" 4244 /*@ 4245 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 4246 4247 Not Collective 4248 4249 Input Parameter: 4250 . dm - The DMPlex object 4251 4252 Output Parameter: 4253 . depthLabel - The DMLabel recording point depth 4254 4255 Level: developer 4256 4257 .keywords: mesh, points 4258 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 4259 @*/ 4260 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 4261 { 4262 DM_Plex *mesh = (DM_Plex*) dm->data; 4263 PetscErrorCode ierr; 4264 4265 PetscFunctionBegin; 4266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4267 PetscValidPointer(depthLabel, 2); 4268 if (!mesh->depthLabel) {ierr = DMPlexGetLabel(dm, "depth", &mesh->depthLabel);CHKERRQ(ierr);} 4269 *depthLabel = mesh->depthLabel; 4270 PetscFunctionReturn(0); 4271 } 4272 4273 #undef __FUNCT__ 4274 #define __FUNCT__ "DMPlexGetDepth" 4275 /*@ 4276 DMPlexGetDepth - Get the depth of the DAG representing this mesh 4277 4278 Not Collective 4279 4280 Input Parameter: 4281 . dm - The DMPlex object 4282 4283 Output Parameter: 4284 . depth - The number of strata (breadth first levels) in the DAG 4285 4286 Level: developer 4287 4288 .keywords: mesh, points 4289 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 4290 @*/ 4291 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 4292 { 4293 DMLabel label; 4294 PetscInt d = 0; 4295 PetscErrorCode ierr; 4296 4297 PetscFunctionBegin; 4298 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4299 PetscValidPointer(depth, 2); 4300 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4301 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 4302 *depth = d-1; 4303 PetscFunctionReturn(0); 4304 } 4305 4306 #undef __FUNCT__ 4307 #define __FUNCT__ "DMPlexGetDepthStratum" 4308 /*@ 4309 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 4310 4311 Not Collective 4312 4313 Input Parameters: 4314 + dm - The DMPlex object 4315 - stratumValue - The requested depth 4316 4317 Output Parameters: 4318 + start - The first point at this depth 4319 - end - One beyond the last point at this depth 4320 4321 Level: developer 4322 4323 .keywords: mesh, points 4324 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth() 4325 @*/ 4326 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4327 { 4328 DMLabel label; 4329 PetscInt pStart, pEnd; 4330 PetscErrorCode ierr; 4331 4332 PetscFunctionBegin; 4333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4334 if (start) {PetscValidPointer(start, 3); *start = 0;} 4335 if (end) {PetscValidPointer(end, 4); *end = 0;} 4336 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4337 if (pStart == pEnd) PetscFunctionReturn(0); 4338 if (stratumValue < 0) { 4339 if (start) *start = pStart; 4340 if (end) *end = pEnd; 4341 PetscFunctionReturn(0); 4342 } 4343 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4344 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 4345 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 4346 PetscFunctionReturn(0); 4347 } 4348 4349 #undef __FUNCT__ 4350 #define __FUNCT__ "DMPlexGetHeightStratum" 4351 /*@ 4352 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 4353 4354 Not Collective 4355 4356 Input Parameters: 4357 + dm - The DMPlex object 4358 - stratumValue - The requested height 4359 4360 Output Parameters: 4361 + start - The first point at this height 4362 - end - One beyond the last point at this height 4363 4364 Level: developer 4365 4366 .keywords: mesh, points 4367 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth() 4368 @*/ 4369 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 4370 { 4371 DMLabel label; 4372 PetscInt depth, pStart, pEnd; 4373 PetscErrorCode ierr; 4374 4375 PetscFunctionBegin; 4376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4377 if (start) {PetscValidPointer(start, 3); *start = 0;} 4378 if (end) {PetscValidPointer(end, 4); *end = 0;} 4379 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4380 if (pStart == pEnd) PetscFunctionReturn(0); 4381 if (stratumValue < 0) { 4382 if (start) *start = pStart; 4383 if (end) *end = pEnd; 4384 PetscFunctionReturn(0); 4385 } 4386 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 4387 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr); 4388 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 4389 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 4390 PetscFunctionReturn(0); 4391 } 4392 4393 #undef __FUNCT__ 4394 #define __FUNCT__ "DMPlexCreateSectionInitial" 4395 /* Set the number of dof on each point and separate by fields */ 4396 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) 4397 { 4398 PetscInt *numDofTot; 4399 PetscInt pStart = 0, pEnd = 0; 4400 PetscInt p, d, f; 4401 PetscErrorCode ierr; 4402 4403 PetscFunctionBegin; 4404 ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr); 4405 for (d = 0; d <= dim; ++d) { 4406 numDofTot[d] = 0; 4407 for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d]; 4408 } 4409 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); 4410 if (numFields > 0) { 4411 ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr); 4412 if (numComp) { 4413 for (f = 0; f < numFields; ++f) { 4414 ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr); 4415 } 4416 } 4417 } 4418 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 4419 ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr); 4420 for (d = 0; d <= dim; ++d) { 4421 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 4422 for (p = pStart; p < pEnd; ++p) { 4423 for (f = 0; f < numFields; ++f) { 4424 ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr); 4425 } 4426 ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr); 4427 } 4428 } 4429 ierr = PetscFree(numDofTot);CHKERRQ(ierr); 4430 PetscFunctionReturn(0); 4431 } 4432 4433 #undef __FUNCT__ 4434 #define __FUNCT__ "DMPlexCreateSectionBCDof" 4435 /* Set the number of dof on each point and separate by fields 4436 If constDof is PETSC_DETERMINE, constrain every dof on the point 4437 */ 4438 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) 4439 { 4440 PetscInt numFields; 4441 PetscInt bc; 4442 PetscErrorCode ierr; 4443 4444 PetscFunctionBegin; 4445 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4446 for (bc = 0; bc < numBC; ++bc) { 4447 PetscInt field = 0; 4448 const PetscInt *idx; 4449 PetscInt n, i; 4450 4451 if (numFields) field = bcField[bc]; 4452 ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr); 4453 ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 4454 for (i = 0; i < n; ++i) { 4455 const PetscInt p = idx[i]; 4456 PetscInt numConst = constDof; 4457 4458 /* Constrain every dof on the point */ 4459 if (numConst < 0) { 4460 if (numFields) { 4461 ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr); 4462 } else { 4463 ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr); 4464 } 4465 } 4466 if (numFields) { 4467 ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr); 4468 } 4469 ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr); 4470 } 4471 ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 4472 } 4473 PetscFunctionReturn(0); 4474 } 4475 4476 #undef __FUNCT__ 4477 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll" 4478 /* Set the constrained indices on each point and separate by fields */ 4479 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) 4480 { 4481 PetscInt *maxConstraints; 4482 PetscInt numFields, f, pStart = 0, pEnd = 0, p; 4483 PetscErrorCode ierr; 4484 4485 PetscFunctionBegin; 4486 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4487 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4488 ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr); 4489 for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0; 4490 for (p = pStart; p < pEnd; ++p) { 4491 PetscInt cdof; 4492 4493 if (numFields) { 4494 for (f = 0; f < numFields; ++f) { 4495 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr); 4496 maxConstraints[f] = PetscMax(maxConstraints[f], cdof); 4497 } 4498 } else { 4499 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4500 maxConstraints[0] = PetscMax(maxConstraints[0], cdof); 4501 } 4502 } 4503 for (f = 0; f < numFields; ++f) { 4504 maxConstraints[numFields] += maxConstraints[f]; 4505 } 4506 if (maxConstraints[numFields]) { 4507 PetscInt *indices; 4508 4509 ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr); 4510 for (p = pStart; p < pEnd; ++p) { 4511 PetscInt cdof, d; 4512 4513 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4514 if (cdof) { 4515 if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]); 4516 if (numFields) { 4517 PetscInt numConst = 0, foff = 0; 4518 4519 for (f = 0; f < numFields; ++f) { 4520 PetscInt cfdof, fdof; 4521 4522 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 4523 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr); 4524 /* Change constraint numbering from absolute local dof number to field relative local dof number */ 4525 for (d = 0; d < cfdof; ++d) indices[numConst+d] = d; 4526 ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr); 4527 for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff; 4528 numConst += cfdof; 4529 foff += fdof; 4530 } 4531 if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof); 4532 } else { 4533 for (d = 0; d < cdof; ++d) indices[d] = d; 4534 } 4535 ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr); 4536 } 4537 } 4538 ierr = PetscFree(indices);CHKERRQ(ierr); 4539 } 4540 ierr = PetscFree(maxConstraints);CHKERRQ(ierr); 4541 PetscFunctionReturn(0); 4542 } 4543 4544 #undef __FUNCT__ 4545 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField" 4546 /* Set the constrained field indices on each point */ 4547 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) 4548 { 4549 const PetscInt *points, *indices; 4550 PetscInt numFields, maxDof, numPoints, p, numConstraints; 4551 PetscErrorCode ierr; 4552 4553 PetscFunctionBegin; 4554 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4555 if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields); 4556 4557 ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr); 4558 ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr); 4559 if (!constraintIndices) { 4560 PetscInt *idx, i; 4561 4562 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 4563 ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr); 4564 for (i = 0; i < maxDof; ++i) idx[i] = i; 4565 for (p = 0; p < numPoints; ++p) { 4566 ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr); 4567 } 4568 ierr = PetscFree(idx);CHKERRQ(ierr); 4569 } else { 4570 ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr); 4571 ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr); 4572 for (p = 0; p < numPoints; ++p) { 4573 PetscInt fcdof; 4574 4575 ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr); 4576 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); 4577 ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr); 4578 } 4579 ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr); 4580 } 4581 ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr); 4582 PetscFunctionReturn(0); 4583 } 4584 4585 #undef __FUNCT__ 4586 #define __FUNCT__ "DMPlexCreateSectionBCIndices" 4587 /* Set the constrained indices on each point and separate by fields */ 4588 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) 4589 { 4590 PetscInt *indices; 4591 PetscInt numFields, maxDof, f, pStart = 0, pEnd = 0, p; 4592 PetscErrorCode ierr; 4593 4594 PetscFunctionBegin; 4595 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 4596 ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr); 4597 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4598 if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices."); 4599 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4600 for (p = pStart; p < pEnd; ++p) { 4601 PetscInt cdof, d; 4602 4603 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 4604 if (cdof) { 4605 PetscInt numConst = 0, foff = 0; 4606 4607 for (f = 0; f < numFields; ++f) { 4608 const PetscInt *fcind; 4609 PetscInt fdof, fcdof; 4610 4611 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 4612 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 4613 if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);} 4614 /* Change constraint numbering from field relative local dof number to absolute local dof number */ 4615 for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff; 4616 foff += fdof; 4617 numConst += fcdof; 4618 } 4619 if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof); 4620 ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr); 4621 } 4622 } 4623 ierr = PetscFree(indices);CHKERRQ(ierr); 4624 PetscFunctionReturn(0); 4625 } 4626 4627 #undef __FUNCT__ 4628 #define __FUNCT__ "DMPlexCreateSection" 4629 /*@C 4630 DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided. 4631 4632 Not Collective 4633 4634 Input Parameters: 4635 + dm - The DMPlex object 4636 . dim - The spatial dimension of the problem 4637 . numFields - The number of fields in the problem 4638 . numComp - An array of size numFields that holds the number of components for each field 4639 . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d 4640 . numBC - The number of boundary conditions 4641 . bcField - An array of size numBC giving the field number for each boundry condition 4642 - bcPoints - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies 4643 4644 Output Parameter: 4645 . section - The PetscSection object 4646 4647 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 4648 nubmer of dof for field 0 on each edge. 4649 4650 Level: developer 4651 4652 Fortran Notes: 4653 A Fortran 90 version is available as DMPlexCreateSectionF90() 4654 4655 .keywords: mesh, elements 4656 .seealso: DMPlexCreate(), PetscSectionCreate() 4657 @*/ 4658 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section) 4659 { 4660 PetscErrorCode ierr; 4661 4662 PetscFunctionBegin; 4663 ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr); 4664 ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr); 4665 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 4666 if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);} 4667 { 4668 PetscBool view = PETSC_FALSE; 4669 4670 ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr); 4671 if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);} 4672 } 4673 PetscFunctionReturn(0); 4674 } 4675 4676 #undef __FUNCT__ 4677 #define __FUNCT__ "DMCreateCoordinateDM_Plex" 4678 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 4679 { 4680 PetscSection section; 4681 PetscErrorCode ierr; 4682 4683 PetscFunctionBegin; 4684 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 4685 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 4686 ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr); 4687 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 4688 PetscFunctionReturn(0); 4689 } 4690 4691 #undef __FUNCT__ 4692 #define __FUNCT__ "DMPlexGetCoordinateSection" 4693 /*@ 4694 DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh. 4695 4696 Not Collective 4697 4698 Input Parameter: 4699 . dm - The DMPlex object 4700 4701 Output Parameter: 4702 . section - The PetscSection object 4703 4704 Level: intermediate 4705 4706 .keywords: mesh, coordinates 4707 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection() 4708 @*/ 4709 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section) 4710 { 4711 DM cdm; 4712 PetscErrorCode ierr; 4713 4714 PetscFunctionBegin; 4715 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4716 PetscValidPointer(section, 2); 4717 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 4718 ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr); 4719 PetscFunctionReturn(0); 4720 } 4721 4722 #undef __FUNCT__ 4723 #define __FUNCT__ "DMPlexSetCoordinateSection" 4724 /*@ 4725 DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh. 4726 4727 Not Collective 4728 4729 Input Parameters: 4730 + dm - The DMPlex object 4731 - section - The PetscSection object 4732 4733 Level: intermediate 4734 4735 .keywords: mesh, coordinates 4736 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection() 4737 @*/ 4738 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section) 4739 { 4740 DM cdm; 4741 PetscErrorCode ierr; 4742 4743 PetscFunctionBegin; 4744 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4745 PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2); 4746 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 4747 ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr); 4748 PetscFunctionReturn(0); 4749 } 4750 4751 #undef __FUNCT__ 4752 #define __FUNCT__ "DMPlexGetConeSection" 4753 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 4754 { 4755 DM_Plex *mesh = (DM_Plex*) dm->data; 4756 4757 PetscFunctionBegin; 4758 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4759 if (section) *section = mesh->coneSection; 4760 PetscFunctionReturn(0); 4761 } 4762 4763 #undef __FUNCT__ 4764 #define __FUNCT__ "DMPlexGetSupportSection" 4765 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 4766 { 4767 DM_Plex *mesh = (DM_Plex*) dm->data; 4768 4769 PetscFunctionBegin; 4770 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4771 if (section) *section = mesh->supportSection; 4772 PetscFunctionReturn(0); 4773 } 4774 4775 #undef __FUNCT__ 4776 #define __FUNCT__ "DMPlexGetCones" 4777 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 4778 { 4779 DM_Plex *mesh = (DM_Plex*) dm->data; 4780 4781 PetscFunctionBegin; 4782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4783 if (cones) *cones = mesh->cones; 4784 PetscFunctionReturn(0); 4785 } 4786 4787 #undef __FUNCT__ 4788 #define __FUNCT__ "DMPlexGetConeOrientations" 4789 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 4790 { 4791 DM_Plex *mesh = (DM_Plex*) dm->data; 4792 4793 PetscFunctionBegin; 4794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4795 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 4796 PetscFunctionReturn(0); 4797 } 4798 4799 /******************************** FEM Support **********************************/ 4800 4801 #undef __FUNCT__ 4802 #define __FUNCT__ "DMPlexVecGetClosure" 4803 /*@C 4804 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 4805 4806 Not collective 4807 4808 Input Parameters: 4809 + dm - The DM 4810 . section - The section describing the layout in v, or NULL to use the default section 4811 . v - The local vector 4812 - point - The sieve point in the DM 4813 4814 Output Parameters: 4815 + csize - The number of values in the closure, or NULL 4816 - values - The array of values, which is a borrowed array and should not be freed 4817 4818 Fortran Notes: 4819 Since it returns an array, this routine is only available in Fortran 90, and you must 4820 include petsc.h90 in your code. 4821 4822 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 4823 4824 Level: intermediate 4825 4826 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 4827 @*/ 4828 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 4829 { 4830 PetscSection clSection; 4831 IS clIndices; 4832 PetscScalar *array, *vArray; 4833 PetscInt *points = NULL; 4834 PetscInt offsets[32]; 4835 PetscInt depth, numFields, size = 0, numPoints, pStart, pEnd, p, q, f; 4836 PetscErrorCode ierr; 4837 4838 PetscFunctionBegin; 4839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4840 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4841 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 4842 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clIndices);CHKERRQ(ierr); 4843 if (clSection) { 4844 const PetscInt *idx; 4845 PetscInt dof, off; 4846 4847 ierr = PetscSectionGetDof(clSection, point, &dof);CHKERRQ(ierr); 4848 if (csize) *csize = dof; 4849 if (values) { 4850 if (!*values) { 4851 ierr = DMGetWorkArray(dm, dof, PETSC_SCALAR, &array);CHKERRQ(ierr); 4852 *values = array; 4853 } else { 4854 array = *values; 4855 } 4856 ierr = PetscSectionGetOffset(clSection, point, &off);CHKERRQ(ierr); 4857 ierr = ISGetIndices(clIndices, &idx);CHKERRQ(ierr); 4858 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4859 for (p = 0; p < dof; ++p) array[p] = vArray[idx[off+p]]; 4860 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4861 ierr = ISRestoreIndices(clIndices, &idx);CHKERRQ(ierr); 4862 } 4863 PetscFunctionReturn(0); 4864 } 4865 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4866 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4867 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4868 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 4869 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 4870 if (depth == 1 && numFields < 2) { 4871 const PetscInt *cone, *coneO; 4872 4873 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4874 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4875 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4876 if (!values || !*values) { 4877 if ((point >= pStart) && (point < pEnd)) { 4878 PetscInt dof; 4879 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4880 size += dof; 4881 } 4882 for (p = 0; p < numPoints; ++p) { 4883 const PetscInt cp = cone[p]; 4884 PetscInt dof; 4885 4886 if ((cp < pStart) || (cp >= pEnd)) continue; 4887 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4888 size += dof; 4889 } 4890 if (!values) { 4891 if (csize) *csize = size; 4892 PetscFunctionReturn(0); 4893 } 4894 ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr); 4895 } else { 4896 array = *values; 4897 } 4898 size = 0; 4899 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4900 if ((point >= pStart) && (point < pEnd)) { 4901 PetscInt dof, off, d; 4902 PetscScalar *varr; 4903 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4904 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 4905 varr = &vArray[off]; 4906 for (d = 0; d < dof; ++d, ++offsets[0]) { 4907 array[offsets[0]] = varr[d]; 4908 } 4909 size += dof; 4910 } 4911 for (p = 0; p < numPoints; ++p) { 4912 const PetscInt cp = cone[p]; 4913 PetscInt o = coneO[p]; 4914 PetscInt dof, off, d; 4915 PetscScalar *varr; 4916 4917 if ((cp < pStart) || (cp >= pEnd)) continue; 4918 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4919 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 4920 varr = &vArray[off]; 4921 if (o >= 0) { 4922 for (d = 0; d < dof; ++d, ++offsets[0]) { 4923 array[offsets[0]] = varr[d]; 4924 } 4925 } else { 4926 for (d = dof-1; d >= 0; --d, ++offsets[0]) { 4927 array[offsets[0]] = varr[d]; 4928 } 4929 } 4930 size += dof; 4931 } 4932 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 4933 if (!*values) { 4934 if (csize) *csize = size; 4935 *values = array; 4936 } else { 4937 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size); 4938 *csize = size; 4939 } 4940 PetscFunctionReturn(0); 4941 } 4942 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 4943 /* Compress out points not in the section */ 4944 for (p = 0, q = 0; p < numPoints*2; p += 2) { 4945 if ((points[p] >= pStart) && (points[p] < pEnd)) { 4946 points[q*2] = points[p]; 4947 points[q*2+1] = points[p+1]; 4948 ++q; 4949 } 4950 } 4951 numPoints = q; 4952 if (!values || !*values) { 4953 for (p = 0, size = 0; p < numPoints*2; p += 2) { 4954 PetscInt dof, fdof; 4955 4956 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4957 for (f = 0; f < numFields; ++f) { 4958 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 4959 offsets[f+1] += fdof; 4960 } 4961 size += dof; 4962 } 4963 if (!values) { 4964 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 4965 if (csize) *csize = size; 4966 PetscFunctionReturn(0); 4967 } 4968 ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr); 4969 } else { 4970 array = *values; 4971 } 4972 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 4973 if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size); 4974 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 4975 for (p = 0; p < numPoints*2; p += 2) { 4976 PetscInt o = points[p+1]; 4977 PetscInt dof, off, d; 4978 PetscScalar *varr; 4979 4980 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4981 ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr); 4982 varr = &vArray[off]; 4983 if (numFields) { 4984 PetscInt fdof, foff, fcomp, f, c; 4985 4986 for (f = 0, foff = 0; f < numFields; ++f) { 4987 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 4988 if (o >= 0) { 4989 for (d = 0; d < fdof; ++d, ++offsets[f]) { 4990 array[offsets[f]] = varr[foff+d]; 4991 } 4992 } else { 4993 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4994 for (d = fdof/fcomp-1; d >= 0; --d) { 4995 for (c = 0; c < fcomp; ++c, ++offsets[f]) { 4996 array[offsets[f]] = varr[foff+d*fcomp+c]; 4997 } 4998 } 4999 } 5000 foff += fdof; 5001 } 5002 } else { 5003 if (o >= 0) { 5004 for (d = 0; d < dof; ++d, ++offsets[0]) { 5005 array[offsets[0]] = varr[d]; 5006 } 5007 } else { 5008 for (d = dof-1; d >= 0; --d, ++offsets[0]) { 5009 array[offsets[0]] = varr[d]; 5010 } 5011 } 5012 } 5013 } 5014 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5015 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 5016 if (!*values) { 5017 if (csize) *csize = size; 5018 *values = array; 5019 } else { 5020 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size); 5021 *csize = size; 5022 } 5023 PetscFunctionReturn(0); 5024 } 5025 5026 #undef __FUNCT__ 5027 #define __FUNCT__ "DMPlexVecRestoreClosure" 5028 /*@C 5029 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 5030 5031 Not collective 5032 5033 Input Parameters: 5034 + dm - The DM 5035 . section - The section describing the layout in v, or NULL to use the default section 5036 . v - The local vector 5037 . point - The sieve point in the DM 5038 . csize - The number of values in the closure, or NULL 5039 - values - The array of values, which is a borrowed array and should not be freed 5040 5041 Fortran Notes: 5042 Since it returns an array, this routine is only available in Fortran 90, and you must 5043 include petsc.h90 in your code. 5044 5045 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 5046 5047 Level: intermediate 5048 5049 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5050 @*/ 5051 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 5052 { 5053 PetscInt size = 0; 5054 PetscErrorCode ierr; 5055 5056 PetscFunctionBegin; 5057 /* Should work without recalculating size */ 5058 ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr); 5059 PetscFunctionReturn(0); 5060 } 5061 5062 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 5063 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 5064 5065 #undef __FUNCT__ 5066 #define __FUNCT__ "updatePoint_private" 5067 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 5068 { 5069 PetscInt cdof; /* The number of constraints on this point */ 5070 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5071 PetscScalar *a; 5072 PetscInt off, cind = 0, k; 5073 PetscErrorCode ierr; 5074 5075 PetscFunctionBegin; 5076 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5077 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5078 a = &array[off]; 5079 if (!cdof || setBC) { 5080 if (orientation >= 0) { 5081 for (k = 0; k < dof; ++k) { 5082 fuse(&a[k], values[k]); 5083 } 5084 } else { 5085 for (k = 0; k < dof; ++k) { 5086 fuse(&a[k], values[dof-k-1]); 5087 } 5088 } 5089 } else { 5090 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5091 if (orientation >= 0) { 5092 for (k = 0; k < dof; ++k) { 5093 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5094 fuse(&a[k], values[k]); 5095 } 5096 } else { 5097 for (k = 0; k < dof; ++k) { 5098 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5099 fuse(&a[k], values[dof-k-1]); 5100 } 5101 } 5102 } 5103 PetscFunctionReturn(0); 5104 } 5105 5106 #undef __FUNCT__ 5107 #define __FUNCT__ "updatePointBC_private" 5108 PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 5109 { 5110 PetscInt cdof; /* The number of constraints on this point */ 5111 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5112 PetscScalar *a; 5113 PetscInt off, cind = 0, k; 5114 PetscErrorCode ierr; 5115 5116 PetscFunctionBegin; 5117 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5118 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5119 a = &array[off]; 5120 if (cdof) { 5121 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5122 if (orientation >= 0) { 5123 for (k = 0; k < dof; ++k) { 5124 if ((cind < cdof) && (k == cdofs[cind])) { 5125 fuse(&a[k], values[k]); 5126 ++cind; 5127 } 5128 } 5129 } else { 5130 for (k = 0; k < dof; ++k) { 5131 if ((cind < cdof) && (k == cdofs[cind])) { 5132 fuse(&a[k], values[dof-k-1]); 5133 ++cind; 5134 } 5135 } 5136 } 5137 } 5138 PetscFunctionReturn(0); 5139 } 5140 5141 #undef __FUNCT__ 5142 #define __FUNCT__ "updatePointFields_private" 5143 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 5144 { 5145 PetscScalar *a; 5146 PetscInt numFields, off, foff, f; 5147 PetscErrorCode ierr; 5148 5149 PetscFunctionBegin; 5150 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5151 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5152 a = &array[off]; 5153 for (f = 0, foff = 0; f < numFields; ++f) { 5154 PetscInt fdof, fcomp, fcdof; 5155 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5156 PetscInt cind = 0, k, c; 5157 5158 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 5159 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5160 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 5161 if (!fcdof || setBC) { 5162 if (orientation >= 0) { 5163 for (k = 0; k < fdof; ++k) { 5164 fuse(&a[foff+k], values[foffs[f]+k]); 5165 } 5166 } else { 5167 for (k = fdof/fcomp-1; k >= 0; --k) { 5168 for (c = 0; c < fcomp; ++c) { 5169 fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]); 5170 } 5171 } 5172 } 5173 } else { 5174 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5175 if (orientation >= 0) { 5176 for (k = 0; k < fdof; ++k) { 5177 if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;} 5178 fuse(&a[foff+k], values[foffs[f]+k]); 5179 } 5180 } else { 5181 for (k = fdof/fcomp-1; k >= 0; --k) { 5182 for (c = 0; c < fcomp; ++c) { 5183 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;} 5184 fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]); 5185 } 5186 } 5187 } 5188 } 5189 foff += fdof; 5190 foffs[f] += fdof; 5191 } 5192 PetscFunctionReturn(0); 5193 } 5194 5195 #undef __FUNCT__ 5196 #define __FUNCT__ "updatePointFieldsBC_private" 5197 PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[]) 5198 { 5199 PetscScalar *a; 5200 PetscInt numFields, off, foff, f; 5201 PetscErrorCode ierr; 5202 5203 PetscFunctionBegin; 5204 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5205 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 5206 a = &array[off]; 5207 for (f = 0, foff = 0; f < numFields; ++f) { 5208 PetscInt fdof, fcomp, fcdof; 5209 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5210 PetscInt cind = 0, k, c; 5211 5212 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 5213 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5214 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 5215 if (fcdof) { 5216 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5217 if (orientation >= 0) { 5218 for (k = 0; k < fdof; ++k) { 5219 if ((cind < fcdof) && (k == fcdofs[cind])) { 5220 fuse(&a[foff+k], values[foffs[f]+k]); 5221 ++cind; 5222 } 5223 } 5224 } else { 5225 for (k = fdof/fcomp-1; k >= 0; --k) { 5226 for (c = 0; c < fcomp; ++c) { 5227 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) { 5228 fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]); 5229 ++cind; 5230 } 5231 } 5232 } 5233 } 5234 } 5235 foff += fdof; 5236 foffs[f] += fdof; 5237 } 5238 PetscFunctionReturn(0); 5239 } 5240 5241 #undef __FUNCT__ 5242 #define __FUNCT__ "DMPlexVecSetClosure" 5243 /*@C 5244 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 5245 5246 Not collective 5247 5248 Input Parameters: 5249 + dm - The DM 5250 . section - The section describing the layout in v, or NULL to use the default section 5251 . v - The local vector 5252 . point - The sieve point in the DM 5253 . values - The array of values 5254 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 5255 5256 Fortran Notes: 5257 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5258 5259 Level: intermediate 5260 5261 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 5262 @*/ 5263 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 5264 { 5265 PetscScalar *array; 5266 PetscInt *points = NULL; 5267 PetscInt offsets[32]; 5268 PetscInt depth, numFields, numPoints, off, dof, pStart, pEnd, p, q, f; 5269 PetscErrorCode ierr; 5270 5271 PetscFunctionBegin; 5272 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5273 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 5274 if (!section) { 5275 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 5276 } 5277 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5278 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5279 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5280 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5281 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5282 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 5283 const PetscInt *cone, *coneO; 5284 5285 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 5286 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 5287 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 5288 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5289 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 5290 const PetscInt cp = !p ? point : cone[p-1]; 5291 const PetscInt o = !p ? 0 : coneO[p-1]; 5292 5293 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 5294 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 5295 /* ADD_VALUES */ 5296 { 5297 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5298 PetscScalar *a; 5299 PetscInt cdof, coff, cind = 0, k; 5300 5301 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 5302 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 5303 a = &array[coff]; 5304 if (!cdof) { 5305 if (o >= 0) { 5306 for (k = 0; k < dof; ++k) { 5307 a[k] += values[off+k]; 5308 } 5309 } else { 5310 for (k = 0; k < dof; ++k) { 5311 a[k] += values[off+dof-k-1]; 5312 } 5313 } 5314 } else { 5315 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 5316 if (o >= 0) { 5317 for (k = 0; k < dof; ++k) { 5318 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5319 a[k] += values[off+k]; 5320 } 5321 } else { 5322 for (k = 0; k < dof; ++k) { 5323 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 5324 a[k] += values[off+dof-k-1]; 5325 } 5326 } 5327 } 5328 } 5329 } 5330 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5331 PetscFunctionReturn(0); 5332 } 5333 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5334 /* Compress out points not in the section */ 5335 for (p = 0, q = 0; p < numPoints*2; p += 2) { 5336 if ((points[p] >= pStart) && (points[p] < pEnd)) { 5337 points[q*2] = points[p]; 5338 points[q*2+1] = points[p+1]; 5339 ++q; 5340 } 5341 } 5342 numPoints = q; 5343 for (p = 0; p < numPoints*2; p += 2) { 5344 PetscInt fdof; 5345 5346 for (f = 0; f < numFields; ++f) { 5347 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5348 offsets[f+1] += fdof; 5349 } 5350 } 5351 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 5352 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 5353 if (numFields) { 5354 switch (mode) { 5355 case INSERT_VALUES: 5356 for (p = 0; p < numPoints*2; p += 2) { 5357 PetscInt o = points[p+1]; 5358 updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array); 5359 } break; 5360 case INSERT_ALL_VALUES: 5361 for (p = 0; p < numPoints*2; p += 2) { 5362 PetscInt o = points[p+1]; 5363 updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE, o, values, array); 5364 } break; 5365 case INSERT_BC_VALUES: 5366 for (p = 0; p < numPoints*2; p += 2) { 5367 PetscInt o = points[p+1]; 5368 updatePointFieldsBC_private(section, points[p], offsets, insert, o, values, array); 5369 } break; 5370 case ADD_VALUES: 5371 for (p = 0; p < numPoints*2; p += 2) { 5372 PetscInt o = points[p+1]; 5373 updatePointFields_private(section, points[p], offsets, add, PETSC_FALSE, o, values, array); 5374 } break; 5375 case ADD_ALL_VALUES: 5376 for (p = 0; p < numPoints*2; p += 2) { 5377 PetscInt o = points[p+1]; 5378 updatePointFields_private(section, points[p], offsets, add, PETSC_TRUE, o, values, array); 5379 } break; 5380 default: 5381 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode); 5382 } 5383 } else { 5384 switch (mode) { 5385 case INSERT_VALUES: 5386 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5387 PetscInt o = points[p+1]; 5388 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5389 updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array); 5390 } break; 5391 case INSERT_ALL_VALUES: 5392 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5393 PetscInt o = points[p+1]; 5394 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5395 updatePoint_private(section, points[p], dof, insert, PETSC_TRUE, o, &values[off], array); 5396 } break; 5397 case INSERT_BC_VALUES: 5398 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5399 PetscInt o = points[p+1]; 5400 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5401 updatePointBC_private(section, points[p], dof, insert, o, &values[off], array); 5402 } break; 5403 case ADD_VALUES: 5404 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5405 PetscInt o = points[p+1]; 5406 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5407 updatePoint_private(section, points[p], dof, add, PETSC_FALSE, o, &values[off], array); 5408 } break; 5409 case ADD_ALL_VALUES: 5410 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 5411 PetscInt o = points[p+1]; 5412 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5413 updatePoint_private(section, points[p], dof, add, PETSC_TRUE, o, &values[off], array); 5414 } break; 5415 default: 5416 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode); 5417 } 5418 } 5419 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5420 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 5421 PetscFunctionReturn(0); 5422 } 5423 5424 #undef __FUNCT__ 5425 #define __FUNCT__ "DMPlexCreateClosureIndex" 5426 /*@ 5427 DMPlexCreateClosureIndex - Calculate an index for the given PetscSection for the closure operation on the DM 5428 5429 Not collective 5430 5431 Input Parameters: 5432 + dm - The DM 5433 - section - The section describing the layout in v, or NULL to use the default section 5434 5435 Note: 5436 This should greatly improve the performance of the closure operations, at the cost of additional memory. 5437 5438 Level: intermediate 5439 5440 .seealso DMPlexVecGetClosure(), DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 5441 @*/ 5442 PetscErrorCode DMPlexCreateClosureIndex(DM dm, PetscSection section) 5443 { 5444 PetscSection closureSection; 5445 IS closureIS; 5446 PetscInt offsets[32], *clIndices; 5447 PetscInt depth, numFields, pStart, pEnd, point, clSize; 5448 PetscErrorCode ierr; 5449 5450 PetscFunctionBegin; 5451 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5452 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 5453 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5454 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5455 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5456 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5457 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) section), &closureSection);CHKERRQ(ierr); 5458 ierr = PetscSectionSetChart(closureSection, pStart, pEnd);CHKERRQ(ierr); 5459 for (point = pStart; point < pEnd; ++point) { 5460 PetscInt *points = NULL, numPoints, p, dof, cldof = 0; 5461 5462 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5463 for (p = 0; p < numPoints*2; p += 2) { 5464 if ((points[p] >= pStart) && (points[p] < pEnd)) { 5465 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5466 cldof += dof; 5467 } 5468 } 5469 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5470 ierr = PetscSectionSetDof(closureSection, point, cldof);CHKERRQ(ierr); 5471 } 5472 ierr = PetscSectionSetUp(closureSection);CHKERRQ(ierr); 5473 ierr = PetscSectionGetStorageSize(closureSection, &clSize);CHKERRQ(ierr); 5474 ierr = PetscMalloc(clSize * sizeof(PetscInt), &clIndices);CHKERRQ(ierr); 5475 for (point = pStart; point < pEnd; ++point) { 5476 PetscInt *points = NULL, numPoints, p, q, cldof, cloff, fdof, f; 5477 5478 ierr = PetscSectionGetDof(closureSection, point, &cldof);CHKERRQ(ierr); 5479 ierr = PetscSectionGetOffset(closureSection, point, &cloff);CHKERRQ(ierr); 5480 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5481 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5482 /* Compress out points not in the section, and create field offsets */ 5483 for (p = 0, q = 0; p < numPoints*2; p += 2) { 5484 if ((points[p] >= pStart) && (points[p] < pEnd)) { 5485 points[q*2] = points[p]; 5486 points[q*2+1] = points[p+1]; 5487 for (f = 0; f < numFields; ++f) { 5488 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5489 offsets[f+1] += fdof; 5490 } 5491 ++q; 5492 } 5493 } 5494 numPoints = q; 5495 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 5496 if (numFields && offsets[numFields] != cldof) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], cldof); 5497 /* Create indices */ 5498 for (p = 0; p < numPoints*2; p += 2) { 5499 PetscInt o = points[p+1], dof, off, d; 5500 5501 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5502 ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr); 5503 if (numFields) { 5504 PetscInt fdof, foff, fcomp, f, c; 5505 5506 for (f = 0, foff = 0; f < numFields; ++f) { 5507 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5508 if (o >= 0) { 5509 for (d = 0; d < fdof; ++d, ++offsets[f]) clIndices[cloff+offsets[f]] = off+foff+d; 5510 } else { 5511 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 5512 for (d = fdof/fcomp-1; d >= 0; --d) { 5513 for (c = 0; c < fcomp; ++c, ++offsets[f]) clIndices[cloff+offsets[f]] = off+foff+d*fcomp+c; 5514 } 5515 } 5516 foff += fdof; 5517 } 5518 } else { 5519 if (o >= 0) for (d = 0; d < dof; ++d) clIndices[cloff+d] = off+d; 5520 else for (d = dof-1; d >= 0; --d) clIndices[cloff+d] = off+d; 5521 } 5522 } 5523 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5524 } 5525 ierr = ISCreateGeneral(PETSC_COMM_SELF, clSize, clIndices, PETSC_OWN_POINTER, &closureIS);CHKERRQ(ierr); 5526 ierr = PetscSectionSetClosureIndex(section, (PetscObject) dm, closureSection, closureIS); 5527 PetscFunctionReturn(0); 5528 } 5529 5530 #undef __FUNCT__ 5531 #define __FUNCT__ "DMPlexPrintMatSetValues" 5532 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[]) 5533 { 5534 PetscMPIInt rank; 5535 PetscInt i, j; 5536 PetscErrorCode ierr; 5537 5538 PetscFunctionBegin; 5539 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr); 5540 ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr); 5541 for (i = 0; i < numIndices; i++) { 5542 ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr); 5543 } 5544 for (i = 0; i < numIndices; i++) { 5545 ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr); 5546 for (j = 0; j < numIndices; j++) { 5547 #if defined(PETSC_USE_COMPLEX) 5548 ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr); 5549 #else 5550 ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr); 5551 #endif 5552 } 5553 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 5554 } 5555 PetscFunctionReturn(0); 5556 } 5557 5558 #undef __FUNCT__ 5559 #define __FUNCT__ "indicesPoint_private" 5560 /* . off - The global offset of this point */ 5561 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[]) 5562 { 5563 PetscInt dof; /* The number of unknowns on this point */ 5564 PetscInt cdof; /* The number of constraints on this point */ 5565 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 5566 PetscInt cind = 0, k; 5567 PetscErrorCode ierr; 5568 5569 PetscFunctionBegin; 5570 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 5571 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 5572 if (!cdof || setBC) { 5573 if (orientation >= 0) { 5574 for (k = 0; k < dof; ++k) indices[*loff+k] = off+k; 5575 } else { 5576 for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k; 5577 } 5578 } else { 5579 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 5580 if (orientation >= 0) { 5581 for (k = 0; k < dof; ++k) { 5582 if ((cind < cdof) && (k == cdofs[cind])) { 5583 /* Insert check for returning constrained indices */ 5584 indices[*loff+k] = -(off+k+1); 5585 ++cind; 5586 } else { 5587 indices[*loff+k] = off+k-cind; 5588 } 5589 } 5590 } else { 5591 for (k = 0; k < dof; ++k) { 5592 if ((cind < cdof) && (k == cdofs[cind])) { 5593 /* Insert check for returning constrained indices */ 5594 indices[*loff+dof-k-1] = -(off+k+1); 5595 ++cind; 5596 } else { 5597 indices[*loff+dof-k-1] = off+k-cind; 5598 } 5599 } 5600 } 5601 } 5602 *loff += dof; 5603 PetscFunctionReturn(0); 5604 } 5605 5606 #undef __FUNCT__ 5607 #define __FUNCT__ "indicesPointFields_private" 5608 /* . off - The global offset of this point */ 5609 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) 5610 { 5611 PetscInt numFields, foff, f; 5612 PetscErrorCode ierr; 5613 5614 PetscFunctionBegin; 5615 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5616 for (f = 0, foff = 0; f < numFields; ++f) { 5617 PetscInt fdof, fcomp, cfdof; 5618 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 5619 PetscInt cind = 0, k, c; 5620 5621 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 5622 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 5623 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 5624 if (!cfdof || setBC) { 5625 if (orientation >= 0) { 5626 for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k; 5627 } else { 5628 for (k = fdof/fcomp-1; k >= 0; --k) { 5629 for (c = 0; c < fcomp; ++c) { 5630 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c; 5631 } 5632 } 5633 } 5634 } else { 5635 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 5636 if (orientation >= 0) { 5637 for (k = 0; k < fdof; ++k) { 5638 if ((cind < cfdof) && (k == fcdofs[cind])) { 5639 indices[foffs[f]+k] = -(off+foff+k+1); 5640 ++cind; 5641 } else { 5642 indices[foffs[f]+k] = off+foff+k-cind; 5643 } 5644 } 5645 } else { 5646 for (k = fdof/fcomp-1; k >= 0; --k) { 5647 for (c = 0; c < fcomp; ++c) { 5648 if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) { 5649 indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1); 5650 ++cind; 5651 } else { 5652 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind; 5653 } 5654 } 5655 } 5656 } 5657 } 5658 foff += fdof - cfdof; 5659 foffs[f] += fdof; 5660 } 5661 PetscFunctionReturn(0); 5662 } 5663 5664 #undef __FUNCT__ 5665 #define __FUNCT__ "DMPlexMatSetClosure" 5666 /*@C 5667 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 5668 5669 Not collective 5670 5671 Input Parameters: 5672 + dm - The DM 5673 . section - The section describing the layout in v 5674 . globalSection - The section describing the layout in v 5675 . A - The matrix 5676 . point - The sieve point in the DM 5677 . values - The array of values 5678 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 5679 5680 Fortran Notes: 5681 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5682 5683 Level: intermediate 5684 5685 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure() 5686 @*/ 5687 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 5688 { 5689 DM_Plex *mesh = (DM_Plex*) dm->data; 5690 PetscInt *points = NULL; 5691 PetscInt *indices; 5692 PetscInt offsets[32]; 5693 PetscInt numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f; 5694 PetscErrorCode ierr; 5695 5696 PetscFunctionBegin; 5697 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5698 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5699 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 5700 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 5701 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5702 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5703 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5704 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5705 /* Compress out points not in the section */ 5706 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 5707 for (p = 0, q = 0; p < numPoints*2; p += 2) { 5708 if ((points[p] >= pStart) && (points[p] < pEnd)) { 5709 points[q*2] = points[p]; 5710 points[q*2+1] = points[p+1]; 5711 ++q; 5712 } 5713 } 5714 numPoints = q; 5715 for (p = 0, numIndices = 0; p < numPoints*2; p += 2) { 5716 PetscInt fdof; 5717 5718 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5719 for (f = 0; f < numFields; ++f) { 5720 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5721 offsets[f+1] += fdof; 5722 } 5723 numIndices += dof; 5724 } 5725 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 5726 5727 if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices); 5728 ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5729 if (numFields) { 5730 for (p = 0; p < numPoints*2; p += 2) { 5731 PetscInt o = points[p+1]; 5732 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5733 indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices); 5734 } 5735 } else { 5736 for (p = 0, off = 0; p < numPoints*2; p += 2) { 5737 PetscInt o = points[p+1]; 5738 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5739 indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices); 5740 } 5741 } 5742 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);} 5743 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 5744 if (ierr) { 5745 PetscMPIInt rank; 5746 PetscErrorCode ierr2; 5747 5748 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 5749 ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 5750 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2); 5751 ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2); 5752 CHKERRQ(ierr); 5753 } 5754 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr); 5755 ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5756 PetscFunctionReturn(0); 5757 } 5758 5759 #undef __FUNCT__ 5760 #define __FUNCT__ "DMPlexGetHybridBounds" 5761 /*@ 5762 DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid 5763 5764 Input Parameter: 5765 . dm - The DMPlex object 5766 5767 Output Parameters: 5768 + cMax - The first hybrid cell 5769 . cMax - The first hybrid face 5770 . cMax - The first hybrid edge 5771 - cMax - The first hybrid vertex 5772 5773 Level: developer 5774 5775 .seealso DMPlexCreateHybridMesh() 5776 @*/ 5777 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax) 5778 { 5779 DM_Plex *mesh = (DM_Plex*) dm->data; 5780 PetscInt dim; 5781 PetscErrorCode ierr; 5782 5783 PetscFunctionBegin; 5784 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5785 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5786 if (cMax) *cMax = mesh->hybridPointMax[dim]; 5787 if (fMax) *fMax = mesh->hybridPointMax[dim-1]; 5788 if (eMax) *eMax = mesh->hybridPointMax[1]; 5789 if (vMax) *vMax = mesh->hybridPointMax[0]; 5790 PetscFunctionReturn(0); 5791 } 5792 5793 #undef __FUNCT__ 5794 #define __FUNCT__ "DMPlexSetHybridBounds" 5795 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax) 5796 { 5797 DM_Plex *mesh = (DM_Plex*) dm->data; 5798 PetscInt dim; 5799 PetscErrorCode ierr; 5800 5801 PetscFunctionBegin; 5802 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5803 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 5804 if (cMax >= 0) mesh->hybridPointMax[dim] = cMax; 5805 if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax; 5806 if (eMax >= 0) mesh->hybridPointMax[1] = eMax; 5807 if (vMax >= 0) mesh->hybridPointMax[0] = vMax; 5808 PetscFunctionReturn(0); 5809 } 5810 5811 #undef __FUNCT__ 5812 #define __FUNCT__ "DMPlexGetVTKCellHeight" 5813 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 5814 { 5815 DM_Plex *mesh = (DM_Plex*) dm->data; 5816 5817 PetscFunctionBegin; 5818 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5819 PetscValidPointer(cellHeight, 2); 5820 *cellHeight = mesh->vtkCellHeight; 5821 PetscFunctionReturn(0); 5822 } 5823 5824 #undef __FUNCT__ 5825 #define __FUNCT__ "DMPlexSetVTKCellHeight" 5826 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 5827 { 5828 DM_Plex *mesh = (DM_Plex*) dm->data; 5829 5830 PetscFunctionBegin; 5831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5832 mesh->vtkCellHeight = cellHeight; 5833 PetscFunctionReturn(0); 5834 } 5835 5836 #undef __FUNCT__ 5837 #define __FUNCT__ "DMPlexCreateNumbering_Private" 5838 /* We can easily have a form that takes an IS instead */ 5839 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering) 5840 { 5841 PetscSection section, globalSection; 5842 PetscInt *numbers, p; 5843 PetscErrorCode ierr; 5844 5845 PetscFunctionBegin; 5846 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 5847 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 5848 for (p = pStart; p < pEnd; ++p) { 5849 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 5850 } 5851 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 5852 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 5853 ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr); 5854 for (p = pStart; p < pEnd; ++p) { 5855 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 5856 } 5857 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 5858 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 5859 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 5860 PetscFunctionReturn(0); 5861 } 5862 5863 #undef __FUNCT__ 5864 #define __FUNCT__ "DMPlexGetCellNumbering" 5865 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 5866 { 5867 DM_Plex *mesh = (DM_Plex*) dm->data; 5868 PetscInt cellHeight, cStart, cEnd, cMax; 5869 PetscErrorCode ierr; 5870 5871 PetscFunctionBegin; 5872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5873 if (!mesh->globalCellNumbers) { 5874 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 5875 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 5876 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 5877 if (cMax >= 0) cEnd = PetscMin(cEnd, cMax); 5878 ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr); 5879 } 5880 *globalCellNumbers = mesh->globalCellNumbers; 5881 PetscFunctionReturn(0); 5882 } 5883 5884 #undef __FUNCT__ 5885 #define __FUNCT__ "DMPlexGetVertexNumbering" 5886 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 5887 { 5888 DM_Plex *mesh = (DM_Plex*) dm->data; 5889 PetscInt vStart, vEnd, vMax; 5890 PetscErrorCode ierr; 5891 5892 PetscFunctionBegin; 5893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5894 if (!mesh->globalVertexNumbers) { 5895 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5896 ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); 5897 if (vMax >= 0) vEnd = PetscMin(vEnd, vMax); 5898 ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr); 5899 } 5900 *globalVertexNumbers = mesh->globalVertexNumbers; 5901 PetscFunctionReturn(0); 5902 } 5903 5904 5905 #undef __FUNCT__ 5906 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel" 5907 /*@C 5908 PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using 5909 the local section and an SF describing the section point overlap. 5910 5911 Input Parameters: 5912 + s - The PetscSection for the local field layout 5913 . sf - The SF describing parallel layout of the section points 5914 . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs 5915 . label - The label specifying the points 5916 - labelValue - The label stratum specifying the points 5917 5918 Output Parameter: 5919 . gsection - The PetscSection for the global field layout 5920 5921 Note: This gives negative sizes and offsets to points not owned by this process 5922 5923 Level: developer 5924 5925 .seealso: PetscSectionCreate() 5926 @*/ 5927 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection) 5928 { 5929 PetscInt *neg = NULL, *tmpOff = NULL; 5930 PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots; 5931 PetscErrorCode ierr; 5932 5933 PetscFunctionBegin; 5934 ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr); 5935 ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr); 5936 ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr); 5937 ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 5938 if (nroots >= 0) { 5939 if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart); 5940 ierr = PetscMalloc(nroots * sizeof(PetscInt), &neg);CHKERRQ(ierr); 5941 ierr = PetscMemzero(neg, nroots * sizeof(PetscInt));CHKERRQ(ierr); 5942 if (nroots > pEnd-pStart) { 5943 ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr); 5944 ierr = PetscMemzero(tmpOff, nroots * sizeof(PetscInt));CHKERRQ(ierr); 5945 } else { 5946 tmpOff = &(*gsection)->atlasDof[-pStart]; 5947 } 5948 } 5949 /* Mark ghost points with negative dof */ 5950 for (p = pStart; p < pEnd; ++p) { 5951 PetscInt value; 5952 5953 ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr); 5954 if (value != labelValue) continue; 5955 ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr); 5956 ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr); 5957 ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr); 5958 if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);} 5959 if (neg) neg[p] = -(dof+1); 5960 } 5961 ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr); 5962 if (nroots >= 0) { 5963 ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5964 ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5965 if (nroots > pEnd-pStart) { 5966 for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];} 5967 } 5968 } 5969 /* Calculate new sizes, get proccess offset, and calculate point offsets */ 5970 for (p = 0, off = 0; p < pEnd-pStart; ++p) { 5971 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0; 5972 (*gsection)->atlasOff[p] = off; 5973 off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0; 5974 } 5975 ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr); 5976 globalOff -= off; 5977 for (p = 0, off = 0; p < pEnd-pStart; ++p) { 5978 (*gsection)->atlasOff[p] += globalOff; 5979 if (neg) neg[p] = -((*gsection)->atlasOff[p]+1); 5980 } 5981 /* Put in negative offsets for ghost points */ 5982 if (nroots >= 0) { 5983 ierr = PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5984 ierr = PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);CHKERRQ(ierr); 5985 if (nroots > pEnd-pStart) { 5986 for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];} 5987 } 5988 } 5989 if (nroots >= 0 && nroots > pEnd-pStart) {ierr = PetscFree(tmpOff);CHKERRQ(ierr);} 5990 ierr = PetscFree(neg);CHKERRQ(ierr); 5991 PetscFunctionReturn(0); 5992 } 5993 5994 #undef __FUNCT__ 5995 #define __FUNCT__ "DMPlexCheckSymmetry" 5996 /*@ 5997 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 5998 5999 Input Parameters: 6000 + dm - The DMPlex object 6001 6002 Note: This is a useful diagnostic when creating meshes programmatically. 6003 6004 Level: developer 6005 6006 .seealso: DMCreate() 6007 @*/ 6008 PetscErrorCode DMPlexCheckSymmetry(DM dm) 6009 { 6010 PetscSection coneSection, supportSection; 6011 const PetscInt *cone, *support; 6012 PetscInt coneSize, c, supportSize, s; 6013 PetscInt pStart, pEnd, p, csize, ssize; 6014 PetscErrorCode ierr; 6015 6016 PetscFunctionBegin; 6017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6018 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 6019 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 6020 /* Check that point p is found in the support of its cone points, and vice versa */ 6021 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 6022 for (p = pStart; p < pEnd; ++p) { 6023 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 6024 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 6025 for (c = 0; c < coneSize; ++c) { 6026 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 6027 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 6028 for (s = 0; s < supportSize; ++s) { 6029 if (support[s] == p) break; 6030 } 6031 if (s >= supportSize) { 6032 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p); 6033 for (s = 0; s < coneSize; ++s) { 6034 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]); 6035 } 6036 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 6037 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]); 6038 for (s = 0; s < supportSize; ++s) { 6039 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]); 6040 } 6041 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 6042 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]); 6043 } 6044 } 6045 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 6046 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 6047 for (s = 0; s < supportSize; ++s) { 6048 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 6049 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 6050 for (c = 0; c < coneSize; ++c) { 6051 if (cone[c] == p) break; 6052 } 6053 if (c >= coneSize) { 6054 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p); 6055 for (c = 0; c < supportSize; ++c) { 6056 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]); 6057 } 6058 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 6059 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]); 6060 for (c = 0; c < coneSize; ++c) { 6061 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]); 6062 } 6063 ierr = PetscPrintf(PETSC_COMM_SELF, "\n"); 6064 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]); 6065 } 6066 } 6067 } 6068 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 6069 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 6070 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize); 6071 PetscFunctionReturn(0); 6072 } 6073 6074 #undef __FUNCT__ 6075 #define __FUNCT__ "DMPlexCheckSkeleton" 6076 /*@ 6077 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 6078 6079 Input Parameters: 6080 + dm - The DMPlex object 6081 6082 Note: This is a useful diagnostic when creating meshes programmatically. 6083 6084 Level: developer 6085 6086 .seealso: DMCreate() 6087 @*/ 6088 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex) 6089 { 6090 DM udm; 6091 PetscInt dim, numCorners, coneSize, cStart, cEnd, cMax, c; 6092 PetscErrorCode ierr; 6093 6094 PetscFunctionBegin; 6095 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6096 ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); 6097 switch (dim) { 6098 case 2: numCorners = isSimplex ? 3 : 4; break; 6099 case 3: numCorners = isSimplex ? 4 : 8; break; 6100 default: 6101 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim); 6102 } 6103 ierr = DMPlexUninterpolate(dm, &udm);CHKERRQ(ierr); 6104 ierr = PetscObjectSetOptionsPrefix((PetscObject) udm, "un_");CHKERRQ(ierr); 6105 ierr = DMSetFromOptions(udm);CHKERRQ(ierr); 6106 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 6107 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 6108 cMax = cMax >= 0 ? cMax : cEnd; 6109 for (c = cStart; c < cMax; ++c) { 6110 ierr = DMPlexGetConeSize(udm, c, &coneSize);CHKERRQ(ierr); 6111 if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d vertices != %d", c, coneSize, numCorners); 6112 } 6113 ierr = DMDestroy(&udm);CHKERRQ(ierr); 6114 PetscFunctionReturn(0); 6115 } 6116