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