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