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