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