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