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