Actual source code: plex.c

petsc-dev 2014-02-02
Report Typos and Errors
  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>

  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;

  9: PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
 10: PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);

 14: PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
 15: {
 16:   DM             dm;
 17:   PetscBool      isvtk;

 21:   VecGetDM(v, &dm);
 22:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
 23:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
 24:   if (isvtk) {
 25:     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
 26:     PetscSection            section;
 27:     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;

 29:     DMPlexGetDimension(dm, &dim);
 30:     DMGetDefaultSection(dm, &section);
 31:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
 32:     DMPlexGetHeightStratum(dm, 1, &fStart, NULL);
 33:     DMPlexGetDepthStratum(dm, 0, &vStart, NULL);
 34:     PetscSectionGetChart(section, &pStart, &pEnd);
 35:     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
 36:     if ((cStart >= pStart) && (cStart < pEnd)) {PetscSectionGetDof(section, cStart, &cdof);}
 37:     if ((fStart >= pStart) && (fStart < pEnd)) {PetscSectionGetDof(section, fStart, &fdof);}
 38:     if ((vStart >= pStart) && (vStart < pEnd)) {PetscSectionGetDof(section, vStart, &vdof);}
 39:     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
 40:       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
 41:     } else if (cdof && vdof) {
 42:       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
 43:     } else if (cdof) {
 44:       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
 45:        * vector or just happens to have the same number of dofs as the dimension. */
 46:       if (cdof == dim) {
 47:         ft = PETSC_VTK_CELL_VECTOR_FIELD;
 48:       } else {
 49:         ft = PETSC_VTK_CELL_FIELD;
 50:       }
 51:     } else if (vdof) {
 52:       if (vdof == dim) {
 53:         ft = PETSC_VTK_POINT_VECTOR_FIELD;
 54:       } else {
 55:         ft = PETSC_VTK_POINT_FIELD;
 56:       }
 57:     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");

 59:     PetscObjectReference((PetscObject) dm); /* viewer drops reference */
 60:     PetscObjectReference((PetscObject) v);  /* viewer drops reference */
 61:     PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);
 62:   } else {
 63:     PetscBool isseq;

 65:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
 66:     if (isseq) {
 67:       VecView_Seq(v, viewer);
 68:     } else {
 69:       VecView_MPI(v, viewer);
 70:     }
 71:   }
 72:   return(0);
 73: }

 77: PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
 78: {
 79:   DM             dm;
 80:   PetscBool      isvtk;

 84:   VecGetDM(v, &dm);
 85:   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
 86:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);
 87:   if (isvtk) {
 88:     Vec         locv;
 89:     const char *name;

 91:     DMGetLocalVector(dm, &locv);
 92:     PetscObjectGetName((PetscObject) v, &name);
 93:     PetscObjectSetName((PetscObject) locv, name);
 94:     DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);
 95:     DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);
 96:     VecView_Plex_Local(locv, viewer);
 97:     DMRestoreLocalVector(dm, &locv);
 98:   } else {
 99:     PetscBool isseq;

101:     PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);
102:     if (isseq) {
103:       VecView_Seq(v, viewer);
104:     } else {
105:       VecView_MPI(v, viewer);
106:     }
107:   }
108:   return(0);
109: }

113: PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
114: {
115:   DM_Plex          *mesh = (DM_Plex*) dm->data;
116:   DM                cdm;
117:   DMLabel           markers;
118:   PetscSection      coordSection;
119:   Vec               coordinates;
120:   PetscViewerFormat format;
121:   PetscErrorCode    ierr;

124:   DMGetCoordinateDM(dm, &cdm);
125:   DMGetDefaultSection(cdm, &coordSection);
126:   DMGetCoordinatesLocal(dm, &coordinates);
127:   PetscViewerGetFormat(viewer, &format);
128:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
129:     const char *name;
130:     PetscInt    maxConeSize, maxSupportSize;
131:     PetscInt    pStart, pEnd, p;
132:     PetscMPIInt rank, size;

134:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
135:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
136:     PetscObjectGetName((PetscObject) dm, &name);
137:     DMPlexGetChart(dm, &pStart, &pEnd);
138:     DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
139:     PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
140:     PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);
141:     PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);
142:     PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);
143:     PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);
144:     for (p = pStart; p < pEnd; ++p) {
145:       PetscInt dof, off, s;

147:       PetscSectionGetDof(mesh->supportSection, p, &dof);
148:       PetscSectionGetOffset(mesh->supportSection, p, &off);
149:       for (s = off; s < off+dof; ++s) {
150:         PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);
151:       }
152:     }
153:     PetscViewerFlush(viewer);
154:     PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);
155:     for (p = pStart; p < pEnd; ++p) {
156:       PetscInt dof, off, c;

158:       PetscSectionGetDof(mesh->coneSection, p, &dof);
159:       PetscSectionGetOffset(mesh->coneSection, p, &off);
160:       for (c = off; c < off+dof; ++c) {
161:         PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);
162:       }
163:     }
164:     PetscViewerFlush(viewer);
165:     PetscSectionGetChart(coordSection, &pStart, NULL);
166:     if (pStart >= 0) {PetscSectionVecView(coordSection, coordinates, viewer);}
167:     DMPlexGetLabel(dm, "marker", &markers);
168:     DMLabelView(markers,viewer);
169:     if (size > 1) {
170:       PetscSF sf;

172:       DMGetPointSF(dm, &sf);
173:       PetscSFView(sf, viewer);
174:     }
175:     PetscViewerFlush(viewer);
176:   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177:     const char  *name;
178:     const char  *colors[3] = {"red", "blue", "green"};
179:     const int    numColors  = 3;
180:     PetscReal    scale      = 2.0;
181:     PetscScalar *coords;
182:     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183:     PetscMPIInt  rank, size;

185:     DMPlexGetDepth(dm, &depth);
186:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
187:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
188:     PetscObjectGetName((PetscObject) dm, &name);
189:     PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);
190:     PetscViewerASCIIPrintf(viewer, "\
191: \\documentclass[crop,multi=false]{standalone}\n\n\
192: \\usepackage{tikz}\n\
193: \\usepackage{pgflibraryshapes}\n\
194: \\usetikzlibrary{backgrounds}\n\
195: \\usetikzlibrary{arrows}\n\
196: \\begin{document}\n\
197: \\section{%s}\n\
198: \\begin{center}\n", name, 8.0/scale);
199:     PetscViewerASCIIPrintf(viewer, "Mesh for process ");
200:     for (p = 0; p < size; ++p) {
201:       if (p > 0 && p == size-1) {
202:         PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);
203:       } else if (p > 0) {
204:         PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);
205:       }
206:       PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);
207:     }
208:     PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209: \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");
210:     /* Plot vertices */
211:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
212:     VecGetArray(coordinates, &coords);
213:     PetscViewerASCIIPrintf(viewer, "\\path\n");
214:     for (v = vStart; v < vEnd; ++v) {
215:       PetscInt off, dof, d;

217:       PetscSectionGetDof(coordSection, v, &dof);
218:       PetscSectionGetOffset(coordSection, v, &off);
219:       PetscViewerASCIISynchronizedPrintf(viewer, "(");
220:       for (d = 0; d < dof; ++d) {
221:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
222:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*PetscRealPart(coords[off+d])));
223:       }
224:       PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);
225:     }
226:     VecRestoreArray(coordinates, &coords);
227:     PetscViewerFlush(viewer);
228:     PetscViewerASCIIPrintf(viewer, "(0,0);\n");
229:     /* Plot edges */
230:     VecGetArray(coordinates, &coords);
231:     PetscViewerASCIIPrintf(viewer, "\\path\n");
232:     if (depth > 1) {DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);}
233:     for (e = eStart; e < eEnd; ++e) {
234:       const PetscInt *cone;
235:       PetscInt        coneSize, offA, offB, dof, d;

237:       DMPlexGetConeSize(dm, e, &coneSize);
238:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239:       DMPlexGetCone(dm, e, &cone);
240:       PetscSectionGetDof(coordSection, cone[0], &dof);
241:       PetscSectionGetOffset(coordSection, cone[0], &offA);
242:       PetscSectionGetOffset(coordSection, cone[1], &offB);
243:       PetscViewerASCIISynchronizedPrintf(viewer, "(");
244:       for (d = 0; d < dof; ++d) {
245:         if (d > 0) {PetscViewerASCIISynchronizedPrintf(viewer, ",");}
246:         PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)(scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d])));
247:       }
248:       PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);
249:     }
250:     VecRestoreArray(coordinates, &coords);
251:     PetscViewerFlush(viewer);
252:     PetscViewerASCIIPrintf(viewer, "(0,0);\n");
253:     /* Plot cells */
254:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
255:     for (c = cStart; c < cEnd; ++c) {
256:       PetscInt *closure = NULL;
257:       PetscInt  closureSize, firstPoint = -1;

259:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
260:       PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);
261:       for (p = 0; p < closureSize*2; p += 2) {
262:         const PetscInt point = closure[p];

264:         if ((point < vStart) || (point >= vEnd)) continue;
265:         if (firstPoint >= 0) {PetscViewerASCIISynchronizedPrintf(viewer, " -- ");}
266:         PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);
267:         if (firstPoint < 0) firstPoint = point;
268:       }
269:       /* Why doesn't this work? PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n"); */
270:       PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);
271:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
272:     }
273:     PetscViewerFlush(viewer);
274:     PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");
275:     PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);
276:   } else {
277:     MPI_Comm    comm;
278:     PetscInt   *sizes, *hybsizes;
279:     PetscInt    locDepth, depth, dim, d, pMax[4];
280:     PetscInt    pStart, pEnd, p;
281:     PetscInt    numLabels, l;
282:     const char *name;
283:     PetscMPIInt size;

285:     PetscObjectGetComm((PetscObject)dm,&comm);
286:     MPI_Comm_size(comm, &size);
287:     DMPlexGetDimension(dm, &dim);
288:     PetscObjectGetName((PetscObject) dm, &name);
289:     if (name) {PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);}
290:     else      {PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);}
291:     DMPlexGetDepth(dm, &locDepth);
292:     MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);
293:     DMPlexGetHybridBounds(dm, &pMax[depth], &pMax[depth-1], &pMax[1], &pMax[0]);
294:     PetscMalloc2(size,&sizes,size,&hybsizes);
295:     if (depth == 1) {
296:       DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);
297:       pEnd = pEnd - pStart;
298:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
299:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);
300:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
301:       PetscViewerASCIIPrintf(viewer, "\n");
302:       DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);
303:       pEnd = pEnd - pStart;
304:       MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
305:       PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);
306:       for (p = 0; p < size; ++p) {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
307:       PetscViewerASCIIPrintf(viewer, "\n");
308:     } else {
309:       for (d = 0; d <= dim; d++) {
310:         DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
311:         pEnd    -= pStart;
312:         pMax[d] -= pStart;
313:         MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);
314:         MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);
315:         PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);
316:         for (p = 0; p < size; ++p) {
317:           if (hybsizes[p] >= 0) {PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);}
318:           else                  {PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);}
319:         }
320:         PetscViewerASCIIPrintf(viewer, "\n");
321:       }
322:     }
323:     PetscFree2(sizes,hybsizes);
324:     DMPlexGetNumLabels(dm, &numLabels);
325:     if (numLabels) {PetscViewerASCIIPrintf(viewer, "Labels:\n");}
326:     for (l = 0; l < numLabels; ++l) {
327:       DMLabel         label;
328:       const char     *name;
329:       IS              valueIS;
330:       const PetscInt *values;
331:       PetscInt        numValues, v;

333:       DMPlexGetLabelName(dm, l, &name);
334:       DMPlexGetLabel(dm, name, &label);
335:       DMLabelGetNumValues(label, &numValues);
336:       PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);
337:       DMLabelGetValueIS(label, &valueIS);
338:       ISGetIndices(valueIS, &values);
339:       for (v = 0; v < numValues; ++v) {
340:         PetscInt size;

342:         DMLabelGetStratumSize(label, values[v], &size);
343:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
344:         PetscViewerASCIIPrintf(viewer, "%d", size);
345:       }
346:       PetscViewerASCIIPrintf(viewer, ")\n");
347:       ISRestoreIndices(valueIS, &values);
348:       ISDestroy(&valueIS);
349:     }
350:   }
351:   return(0);
352: }

356: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
357: {
358:   PetscBool      iascii, isbinary;

364:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
365:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
366:   if (iascii) {
367:     DMPlexView_Ascii(dm, viewer);
368: #if 0
369:   } else if (isbinary) {
370:     DMPlexView_Binary(dm, viewer);
371: #endif
372:   }
373:   return(0);
374: }

378: PetscErrorCode DMDestroy_Plex(DM dm)
379: {
380:   DM_Plex       *mesh = (DM_Plex*) dm->data;
381:   DMLabel        next  = mesh->labels;

385:   if (--mesh->refct > 0) return(0);
386:   PetscSectionDestroy(&mesh->coneSection);
387:   PetscFree(mesh->cones);
388:   PetscFree(mesh->coneOrientations);
389:   PetscSectionDestroy(&mesh->supportSection);
390:   PetscFree(mesh->supports);
391:   PetscFree(mesh->facesTmp);
392:   while (next) {
393:     DMLabel tmp = next->next;

395:     DMLabelDestroy(&next);
396:     next = tmp;
397:   }
398:   DMLabelDestroy(&mesh->subpointMap);
399:   ISDestroy(&mesh->globalVertexNumbers);
400:   ISDestroy(&mesh->globalCellNumbers);
401:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
402:   PetscFree(mesh);
403:   return(0);
404: }

408: PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J)
409: {
410:   PetscSection   section, sectionGlobal;
411:   PetscInt       bs = -1;
412:   PetscInt       localSize;
413:   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock;
415:   MatType        mtype;

418:   MatInitializePackage();
419:   mtype = dm->mattype;
420:   DMGetDefaultSection(dm, &section);
421:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
422:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
423:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
424:   MatCreate(PetscObjectComm((PetscObject)dm), J);
425:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
426:   MatSetType(*J, mtype);
427:   MatSetFromOptions(*J);
428:   PetscStrcmp(mtype, MATSHELL, &isShell);
429:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
430:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
431:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
432:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
433:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
434:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
435:   if (!isShell) {
436:     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
437:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;

439:     if (bs < 0) {
440:       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
441:         PetscInt pStart, pEnd, p, dof, cdof;

443:         PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
444:         for (p = pStart; p < pEnd; ++p) {
445:           PetscSectionGetDof(sectionGlobal, p, &dof);
446:           PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);
447:           if (dof-cdof) {
448:             if (bs < 0) {
449:               bs = dof-cdof;
450:             } else if (bs != dof-cdof) {
451:               /* Layout does not admit a pointwise block size */
452:               bs = 1;
453:               break;
454:             }
455:           }
456:         }
457:         /* Must have same blocksize on all procs (some might have no points) */
458:         bsLocal = bs;
459:         MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
460:         bsLocal = bs < 0 ? bsMax : bs;
461:         MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
462:         if (bsMin != bsMax) {
463:           bs = 1;
464:         } else {
465:           bs = bsMax;
466:         }
467:       } else {
468:         bs = 1;
469:       }
470:     }
471:     PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);
472:     DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);
473:     PetscFree4(dnz, onz, dnzu, onzu);
474:   }
475:   return(0);
476: }

480: /*@
481:   DMPlexGetDimension - Return the topological mesh dimension

483:   Not collective

485:   Input Parameter:
486: . mesh - The DMPlex

488:   Output Parameter:
489: . dim - The topological mesh dimension

491:   Level: beginner

493: .seealso: DMPlexCreate()
494: @*/
495: PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
496: {
497:   DM_Plex *mesh = (DM_Plex*) dm->data;

502:   *dim = mesh->dim;
503:   return(0);
504: }

508: /*@
509:   DMPlexSetDimension - Set the topological mesh dimension

511:   Collective on mesh

513:   Input Parameters:
514: + mesh - The DMPlex
515: - dim - The topological mesh dimension

517:   Level: beginner

519: .seealso: DMPlexCreate()
520: @*/
521: PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
522: {
523:   DM_Plex *mesh = (DM_Plex*) dm->data;

528:   mesh->dim               = dim;
529:   mesh->preallocCenterDim = dim;
530:   return(0);
531: }

535: /*@
536:   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)

538:   Not collective

540:   Input Parameter:
541: . mesh - The DMPlex

543:   Output Parameters:
544: + pStart - The first mesh point
545: - pEnd   - The upper bound for mesh points

547:   Level: beginner

549: .seealso: DMPlexCreate(), DMPlexSetChart()
550: @*/
551: PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
552: {
553:   DM_Plex       *mesh = (DM_Plex*) dm->data;

558:   PetscSectionGetChart(mesh->coneSection, pStart, pEnd);
559:   return(0);
560: }

564: /*@
565:   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)

567:   Not collective

569:   Input Parameters:
570: + mesh - The DMPlex
571: . pStart - The first mesh point
572: - pEnd   - The upper bound for mesh points

574:   Output Parameters:

576:   Level: beginner

578: .seealso: DMPlexCreate(), DMPlexGetChart()
579: @*/
580: PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
581: {
582:   DM_Plex       *mesh = (DM_Plex*) dm->data;

587:   PetscSectionSetChart(mesh->coneSection, pStart, pEnd);
588:   PetscSectionSetChart(mesh->supportSection, pStart, pEnd);
589:   return(0);
590: }

594: /*@
595:   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG

597:   Not collective

599:   Input Parameters:
600: + mesh - The DMPlex
601: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

603:   Output Parameter:
604: . size - The cone size for point p

606:   Level: beginner

608: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
609: @*/
610: PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
611: {
612:   DM_Plex       *mesh = (DM_Plex*) dm->data;

618:   PetscSectionGetDof(mesh->coneSection, p, size);
619:   return(0);
620: }

624: /*@
625:   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG

627:   Not collective

629:   Input Parameters:
630: + mesh - The DMPlex
631: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
632: - size - The cone size for point p

634:   Output Parameter:

636:   Note:
637:   This should be called after DMPlexSetChart().

639:   Level: beginner

641: .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
642: @*/
643: PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
644: {
645:   DM_Plex       *mesh = (DM_Plex*) dm->data;

650:   PetscSectionSetDof(mesh->coneSection, p, size);

652:   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
653:   return(0);
654: }

658: /*@C
659:   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG

661:   Not collective

663:   Input Parameters:
664: + mesh - The DMPlex
665: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

667:   Output Parameter:
668: . cone - An array of points which are on the in-edges for point p

670:   Level: beginner

672:   Fortran Notes:
673:   Since it returns an array, this routine is only available in Fortran 90, and you must
674:   include petsc.h90 in your code.

676:   You must also call DMPlexRestoreCone() after you finish using the returned array.

678: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
679: @*/
680: PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
681: {
682:   DM_Plex       *mesh = (DM_Plex*) dm->data;
683:   PetscInt       off;

689:   PetscSectionGetOffset(mesh->coneSection, p, &off);
690:   *cone = &mesh->cones[off];
691:   return(0);
692: }

696: /*@
697:   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG

699:   Not collective

701:   Input Parameters:
702: + mesh - The DMPlex
703: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
704: - cone - An array of points which are on the in-edges for point p

706:   Output Parameter:

708:   Note:
709:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

711:   Level: beginner

713: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
714: @*/
715: PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
716: {
717:   DM_Plex       *mesh = (DM_Plex*) dm->data;
718:   PetscInt       pStart, pEnd;
719:   PetscInt       dof, off, c;

724:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
725:   PetscSectionGetDof(mesh->coneSection, p, &dof);
727:   PetscSectionGetOffset(mesh->coneSection, p, &off);
728:   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);
729:   for (c = 0; c < dof; ++c) {
730:     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);
731:     mesh->cones[off+c] = cone[c];
732:   }
733:   return(0);
734: }

738: /*@C
739:   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG

741:   Not collective

743:   Input Parameters:
744: + mesh - The DMPlex
745: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

747:   Output Parameter:
748: . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
749:                     integer giving the prescription for cone traversal. If it is negative, the cone is
750:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
751:                     the index of the cone point on which to start.

753:   Level: beginner

755:   Fortran Notes:
756:   Since it returns an array, this routine is only available in Fortran 90, and you must
757:   include petsc.h90 in your code.

759:   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.

761: .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
762: @*/
763: PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
764: {
765:   DM_Plex       *mesh = (DM_Plex*) dm->data;
766:   PetscInt       off;

771: #if defined(PETSC_USE_DEBUG)
772:   {
773:     PetscInt dof;
774:     PetscSectionGetDof(mesh->coneSection, p, &dof);
776:   }
777: #endif
778:   PetscSectionGetOffset(mesh->coneSection, p, &off);

780:   *coneOrientation = &mesh->coneOrientations[off];
781:   return(0);
782: }

786: /*@
787:   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG

789:   Not collective

791:   Input Parameters:
792: + mesh - The DMPlex
793: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
794: - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
795:                     integer giving the prescription for cone traversal. If it is negative, the cone is
796:                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
797:                     the index of the cone point on which to start.

799:   Output Parameter:

801:   Note:
802:   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().

804:   Level: beginner

806: .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
807: @*/
808: PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
809: {
810:   DM_Plex       *mesh = (DM_Plex*) dm->data;
811:   PetscInt       pStart, pEnd;
812:   PetscInt       dof, off, c;

817:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
818:   PetscSectionGetDof(mesh->coneSection, p, &dof);
820:   PetscSectionGetOffset(mesh->coneSection, p, &off);
821:   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);
822:   for (c = 0; c < dof; ++c) {
823:     PetscInt cdof, o = coneOrientation[c];

825:     PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);
826:     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);
827:     mesh->coneOrientations[off+c] = o;
828:   }
829:   return(0);
830: }

834: PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
835: {
836:   DM_Plex       *mesh = (DM_Plex*) dm->data;
837:   PetscInt       pStart, pEnd;
838:   PetscInt       dof, off;

843:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
844:   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);
845:   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);
846:   PetscSectionGetDof(mesh->coneSection, p, &dof);
847:   PetscSectionGetOffset(mesh->coneSection, p, &off);
848:   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);
849:   mesh->cones[off+conePos] = conePoint;
850:   return(0);
851: }

855: PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
856: {
857:   DM_Plex       *mesh = (DM_Plex*) dm->data;
858:   PetscInt       pStart, pEnd;
859:   PetscInt       dof, off;

864:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
865:   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);
866:   PetscSectionGetDof(mesh->coneSection, p, &dof);
867:   PetscSectionGetOffset(mesh->coneSection, p, &off);
868:   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);
869:   mesh->coneOrientations[off+conePos] = coneOrientation;
870:   return(0);
871: }

875: /*@
876:   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG

878:   Not collective

880:   Input Parameters:
881: + mesh - The DMPlex
882: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

884:   Output Parameter:
885: . size - The support size for point p

887:   Level: beginner

889: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
890: @*/
891: PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
892: {
893:   DM_Plex       *mesh = (DM_Plex*) dm->data;

899:   PetscSectionGetDof(mesh->supportSection, p, size);
900:   return(0);
901: }

905: /*@
906:   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG

908:   Not collective

910:   Input Parameters:
911: + mesh - The DMPlex
912: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
913: - size - The support size for point p

915:   Output Parameter:

917:   Note:
918:   This should be called after DMPlexSetChart().

920:   Level: beginner

922: .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
923: @*/
924: PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
925: {
926:   DM_Plex       *mesh = (DM_Plex*) dm->data;

931:   PetscSectionSetDof(mesh->supportSection, p, size);

933:   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
934:   return(0);
935: }

939: /*@C
940:   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG

942:   Not collective

944:   Input Parameters:
945: + mesh - The DMPlex
946: - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()

948:   Output Parameter:
949: . support - An array of points which are on the out-edges for point p

951:   Level: beginner

953:   Fortran Notes:
954:   Since it returns an array, this routine is only available in Fortran 90, and you must
955:   include petsc.h90 in your code.

957:   You must also call DMPlexRestoreSupport() after you finish using the returned array.

959: .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
960: @*/
961: PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
962: {
963:   DM_Plex       *mesh = (DM_Plex*) dm->data;
964:   PetscInt       off;

970:   PetscSectionGetOffset(mesh->supportSection, p, &off);
971:   *support = &mesh->supports[off];
972:   return(0);
973: }

977: /*@
978:   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG

980:   Not collective

982:   Input Parameters:
983: + mesh - The DMPlex
984: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
985: - support - An array of points which are on the in-edges for point p

987:   Output Parameter:

989:   Note:
990:   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().

992:   Level: beginner

994: .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
995: @*/
996: PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
997: {
998:   DM_Plex       *mesh = (DM_Plex*) dm->data;
999:   PetscInt       pStart, pEnd;
1000:   PetscInt       dof, off, c;

1005:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1006:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1008:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1009:   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);
1010:   for (c = 0; c < dof; ++c) {
1011:     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);
1012:     mesh->supports[off+c] = support[c];
1013:   }
1014:   return(0);
1015: }

1019: PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1020: {
1021:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1022:   PetscInt       pStart, pEnd;
1023:   PetscInt       dof, off;

1028:   PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);
1029:   PetscSectionGetDof(mesh->supportSection, p, &dof);
1030:   PetscSectionGetOffset(mesh->supportSection, p, &off);
1031:   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);
1032:   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);
1033:   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);
1034:   mesh->supports[off+supportPos] = supportPoint;
1035:   return(0);
1036: }

1040: /*@C
1041:   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1043:   Not collective

1045:   Input Parameters:
1046: + mesh - The DMPlex
1047: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1048: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1049: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1051:   Output Parameters:
1052: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1053: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

1055:   Note:
1056:   If using internal storage (points is NULL on input), each call overwrites the last output.

1058:   Fortran Notes:
1059:   Since it returns an array, this routine is only available in Fortran 90, and you must
1060:   include petsc.h90 in your code.

1062:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1064:   Level: beginner

1066: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1067: @*/
1068: PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1069: {
1070:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1071:   PetscInt       *closure, *fifo;
1072:   const PetscInt *tmp = NULL, *tmpO = NULL;
1073:   PetscInt        tmpSize, t;
1074:   PetscInt        depth       = 0, maxSize;
1075:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1076:   PetscErrorCode  ierr;

1080:   DMPlexGetDepth(dm, &depth);
1081:   /* This is only 1-level */
1082:   if (useCone) {
1083:     DMPlexGetConeSize(dm, p, &tmpSize);
1084:     DMPlexGetCone(dm, p, &tmp);
1085:     DMPlexGetConeOrientation(dm, p, &tmpO);
1086:   } else {
1087:     DMPlexGetSupportSize(dm, p, &tmpSize);
1088:     DMPlexGetSupport(dm, p, &tmp);
1089:   }
1090:   if (depth == 1) {
1091:     if (*points) {
1092:       closure = *points;
1093:     } else {
1094:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1095:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1096:     }
1097:     closure[0] = p; closure[1] = 0;
1098:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1099:       closure[closureSize]   = tmp[t];
1100:       closure[closureSize+1] = tmpO ? tmpO[t] : 0;
1101:     }
1102:     if (numPoints) *numPoints = closureSize/2;
1103:     if (points)    *points    = closure;
1104:     return(0);
1105:   }
1106:   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1107:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1108:   if (*points) {
1109:     closure = *points;
1110:   } else {
1111:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1112:   }
1113:   closure[0] = p; closure[1] = 0;
1114:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1115:     const PetscInt cp = tmp[t];
1116:     const PetscInt co = tmpO ? tmpO[t] : 0;

1118:     closure[closureSize]   = cp;
1119:     closure[closureSize+1] = co;
1120:     fifo[fifoSize]         = cp;
1121:     fifo[fifoSize+1]       = co;
1122:   }
1123:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1124:   while (fifoSize - fifoStart) {
1125:     const PetscInt q   = fifo[fifoStart];
1126:     const PetscInt o   = fifo[fifoStart+1];
1127:     const PetscInt rev = o >= 0 ? 0 : 1;
1128:     const PetscInt off = rev ? -(o+1) : o;

1130:     if (useCone) {
1131:       DMPlexGetConeSize(dm, q, &tmpSize);
1132:       DMPlexGetCone(dm, q, &tmp);
1133:       DMPlexGetConeOrientation(dm, q, &tmpO);
1134:     } else {
1135:       DMPlexGetSupportSize(dm, q, &tmpSize);
1136:       DMPlexGetSupport(dm, q, &tmp);
1137:       tmpO = NULL;
1138:     }
1139:     for (t = 0; t < tmpSize; ++t) {
1140:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1141:       const PetscInt cp = tmp[i];
1142:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1143:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1144:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1145:       PetscInt       co = tmpO ? tmpO[i] : 0;
1146:       PetscInt       c;

1148:       if (rev) {
1149:         PetscInt childSize, coff;
1150:         DMPlexGetConeSize(dm, cp, &childSize);
1151:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1152:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1153:       }
1154:       /* Check for duplicate */
1155:       for (c = 0; c < closureSize; c += 2) {
1156:         if (closure[c] == cp) break;
1157:       }
1158:       if (c == closureSize) {
1159:         closure[closureSize]   = cp;
1160:         closure[closureSize+1] = co;
1161:         fifo[fifoSize]         = cp;
1162:         fifo[fifoSize+1]       = co;
1163:         closureSize           += 2;
1164:         fifoSize              += 2;
1165:       }
1166:     }
1167:     fifoStart += 2;
1168:   }
1169:   if (numPoints) *numPoints = closureSize/2;
1170:   if (points)    *points    = closure;
1171:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1172:   return(0);
1173: }

1177: /*@C
1178:   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

1180:   Not collective

1182:   Input Parameters:
1183: + mesh - The DMPlex
1184: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1185: . orientation - The orientation of the point
1186: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1187: - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used

1189:   Output Parameters:
1190: + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1191: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]

1193:   Note:
1194:   If using internal storage (points is NULL on input), each call overwrites the last output.

1196:   Fortran Notes:
1197:   Since it returns an array, this routine is only available in Fortran 90, and you must
1198:   include petsc.h90 in your code.

1200:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1202:   Level: beginner

1204: .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1205: @*/
1206: PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1207: {
1208:   DM_Plex        *mesh = (DM_Plex*) dm->data;
1209:   PetscInt       *closure, *fifo;
1210:   const PetscInt *tmp = NULL, *tmpO = NULL;
1211:   PetscInt        tmpSize, t;
1212:   PetscInt        depth       = 0, maxSize;
1213:   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1214:   PetscErrorCode  ierr;

1218:   DMPlexGetDepth(dm, &depth);
1219:   /* This is only 1-level */
1220:   if (useCone) {
1221:     DMPlexGetConeSize(dm, p, &tmpSize);
1222:     DMPlexGetCone(dm, p, &tmp);
1223:     DMPlexGetConeOrientation(dm, p, &tmpO);
1224:   } else {
1225:     DMPlexGetSupportSize(dm, p, &tmpSize);
1226:     DMPlexGetSupport(dm, p, &tmp);
1227:   }
1228:   if (depth == 1) {
1229:     if (*points) {
1230:       closure = *points;
1231:     } else {
1232:       maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1);
1233:       DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1234:     }
1235:     closure[0] = p; closure[1] = ornt;
1236:     for (t = 0; t < tmpSize; ++t, closureSize += 2) {
1237:       const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1238:       closure[closureSize]   = tmp[i];
1239:       closure[closureSize+1] = tmpO ? tmpO[i] : 0;
1240:     }
1241:     if (numPoints) *numPoints = closureSize/2;
1242:     if (points)    *points    = closure;
1243:     return(0);
1244:   }
1245:   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth+1),PetscPowInt(mesh->maxSupportSize,depth+1)),depth+1);
1246:   DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);
1247:   if (*points) {
1248:     closure = *points;
1249:   } else {
1250:     DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);
1251:   }
1252:   closure[0] = p; closure[1] = ornt;
1253:   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1254:     const PetscInt i  = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize;
1255:     const PetscInt cp = tmp[i];
1256:     PetscInt       co = tmpO ? tmpO[i] : 0;

1258:     if (ornt < 0) {
1259:       PetscInt childSize, coff;
1260:       DMPlexGetConeSize(dm, cp, &childSize);
1261:       coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1262:       co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1263:     }
1264:     closure[closureSize]   = cp;
1265:     closure[closureSize+1] = co;
1266:     fifo[fifoSize]         = cp;
1267:     fifo[fifoSize+1]       = co;
1268:   }
1269:   /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */
1270:   while (fifoSize - fifoStart) {
1271:     const PetscInt q   = fifo[fifoStart];
1272:     const PetscInt o   = fifo[fifoStart+1];
1273:     const PetscInt rev = o >= 0 ? 0 : 1;
1274:     const PetscInt off = rev ? -(o+1) : o;

1276:     if (useCone) {
1277:       DMPlexGetConeSize(dm, q, &tmpSize);
1278:       DMPlexGetCone(dm, q, &tmp);
1279:       DMPlexGetConeOrientation(dm, q, &tmpO);
1280:     } else {
1281:       DMPlexGetSupportSize(dm, q, &tmpSize);
1282:       DMPlexGetSupport(dm, q, &tmp);
1283:       tmpO = NULL;
1284:     }
1285:     for (t = 0; t < tmpSize; ++t) {
1286:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1287:       const PetscInt cp = tmp[i];
1288:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1289:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1290:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1291:       PetscInt       co = tmpO ? tmpO[i] : 0;
1292:       PetscInt       c;

1294:       if (rev) {
1295:         PetscInt childSize, coff;
1296:         DMPlexGetConeSize(dm, cp, &childSize);
1297:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1298:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1299:       }
1300:       /* Check for duplicate */
1301:       for (c = 0; c < closureSize; c += 2) {
1302:         if (closure[c] == cp) break;
1303:       }
1304:       if (c == closureSize) {
1305:         closure[closureSize]   = cp;
1306:         closure[closureSize+1] = co;
1307:         fifo[fifoSize]         = cp;
1308:         fifo[fifoSize+1]       = co;
1309:         closureSize           += 2;
1310:         fifoSize              += 2;
1311:       }
1312:     }
1313:     fifoStart += 2;
1314:   }
1315:   if (numPoints) *numPoints = closureSize/2;
1316:   if (points)    *points    = closure;
1317:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1318:   return(0);
1319: }

1323: /*@C
1324:   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG

1326:   Not collective

1328:   Input Parameters:
1329: + mesh - The DMPlex
1330: . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1331: . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1332: . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit
1333: - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit

1335:   Note:
1336:   If not using internal storage (points is not NULL on input), this call is unnecessary

1338:   Fortran Notes:
1339:   Since it returns an array, this routine is only available in Fortran 90, and you must
1340:   include petsc.h90 in your code.

1342:   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1344:   Level: beginner

1346: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1347: @*/
1348: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1349: {

1356:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1357:   if (numPoints) *numPoints = 0;
1358:   return(0);
1359: }

1363: /*@
1364:   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG

1366:   Not collective

1368:   Input Parameter:
1369: . mesh - The DMPlex

1371:   Output Parameters:
1372: + maxConeSize - The maximum number of in-edges
1373: - maxSupportSize - The maximum number of out-edges

1375:   Level: beginner

1377: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1378: @*/
1379: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1380: {
1381:   DM_Plex *mesh = (DM_Plex*) dm->data;

1385:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1386:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1387:   return(0);
1388: }

1392: PetscErrorCode DMSetUp_Plex(DM dm)
1393: {
1394:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1395:   PetscInt       size;

1400:   PetscSectionSetUp(mesh->coneSection);
1401:   PetscSectionGetStorageSize(mesh->coneSection, &size);
1402:   PetscMalloc1(size, &mesh->cones);
1403:   PetscCalloc1(size, &mesh->coneOrientations);
1404:   if (mesh->maxSupportSize) {
1405:     PetscSectionSetUp(mesh->supportSection);
1406:     PetscSectionGetStorageSize(mesh->supportSection, &size);
1407:     PetscMalloc1(size, &mesh->supports);
1408:   }
1409:   return(0);
1410: }

1414: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1415: {

1419:   if (subdm) {DMClone(dm, subdm);}
1420:   DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);
1421:   return(0);
1422: }

1426: /*@
1427:   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation

1429:   Not collective

1431:   Input Parameter:
1432: . mesh - The DMPlex

1434:   Output Parameter:

1436:   Note:
1437:   This should be called after all calls to DMPlexSetCone()

1439:   Level: beginner

1441: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1442: @*/
1443: PetscErrorCode DMPlexSymmetrize(DM dm)
1444: {
1445:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1446:   PetscInt      *offsets;
1447:   PetscInt       supportSize;
1448:   PetscInt       pStart, pEnd, p;

1453:   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1454:   /* Calculate support sizes */
1455:   DMPlexGetChart(dm, &pStart, &pEnd);
1456:   for (p = pStart; p < pEnd; ++p) {
1457:     PetscInt dof, off, c;

1459:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1460:     PetscSectionGetOffset(mesh->coneSection, p, &off);
1461:     for (c = off; c < off+dof; ++c) {
1462:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
1463:     }
1464:   }
1465:   for (p = pStart; p < pEnd; ++p) {
1466:     PetscInt dof;

1468:     PetscSectionGetDof(mesh->supportSection, p, &dof);

1470:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1471:   }
1472:   PetscSectionSetUp(mesh->supportSection);
1473:   /* Calculate supports */
1474:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
1475:   PetscMalloc1(supportSize, &mesh->supports);
1476:   PetscCalloc1(pEnd - pStart, &offsets);
1477:   for (p = pStart; p < pEnd; ++p) {
1478:     PetscInt dof, off, c;

1480:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1481:     PetscSectionGetOffset(mesh->coneSection, p, &off);
1482:     for (c = off; c < off+dof; ++c) {
1483:       const PetscInt q = mesh->cones[c];
1484:       PetscInt       offS;

1486:       PetscSectionGetOffset(mesh->supportSection, q, &offS);

1488:       mesh->supports[offS+offsets[q]] = p;
1489:       ++offsets[q];
1490:     }
1491:   }
1492:   PetscFree(offsets);
1493:   return(0);
1494: }

1498: /*@
1499:   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1500:   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1501:   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1502:   the DAG.

1504:   Not collective

1506:   Input Parameter:
1507: . mesh - The DMPlex

1509:   Output Parameter:

1511:   Notes:
1512:   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1513:   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.

1515:   This should be called after all calls to DMPlexSymmetrize()

1517:   Level: beginner

1519: .seealso: DMPlexCreate(), DMPlexSymmetrize()
1520: @*/
1521: PetscErrorCode DMPlexStratify(DM dm)
1522: {
1523:   DMLabel        label;
1524:   PetscInt       pStart, pEnd, p;
1525:   PetscInt       numRoots = 0, numLeaves = 0;

1530:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
1531:   /* Calculate depth */
1532:   DMPlexGetChart(dm, &pStart, &pEnd);
1533:   DMPlexCreateLabel(dm, "depth");
1534:   DMPlexGetDepthLabel(dm, &label);
1535:   /* Initialize roots and count leaves */
1536:   for (p = pStart; p < pEnd; ++p) {
1537:     PetscInt coneSize, supportSize;

1539:     DMPlexGetConeSize(dm, p, &coneSize);
1540:     DMPlexGetSupportSize(dm, p, &supportSize);
1541:     if (!coneSize && supportSize) {
1542:       ++numRoots;
1543:       DMLabelSetValue(label, p, 0);
1544:     } else if (!supportSize && coneSize) {
1545:       ++numLeaves;
1546:     } else if (!supportSize && !coneSize) {
1547:       /* Isolated points */
1548:       DMLabelSetValue(label, p, 0);
1549:     }
1550:   }
1551:   if (numRoots + numLeaves == (pEnd - pStart)) {
1552:     for (p = pStart; p < pEnd; ++p) {
1553:       PetscInt coneSize, supportSize;

1555:       DMPlexGetConeSize(dm, p, &coneSize);
1556:       DMPlexGetSupportSize(dm, p, &supportSize);
1557:       if (!supportSize && coneSize) {
1558:         DMLabelSetValue(label, p, 1);
1559:       }
1560:     }
1561:   } else {
1562:     IS       pointIS;
1563:     PetscInt numPoints = 0, level = 0;

1565:     DMLabelGetStratumIS(label, level, &pointIS);
1566:     if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
1567:     while (numPoints) {
1568:       const PetscInt *points;
1569:       const PetscInt  newLevel = level+1;

1571:       ISGetIndices(pointIS, &points);
1572:       for (p = 0; p < numPoints; ++p) {
1573:         const PetscInt  point = points[p];
1574:         const PetscInt *support;
1575:         PetscInt        supportSize, s;

1577:         DMPlexGetSupportSize(dm, point, &supportSize);
1578:         DMPlexGetSupport(dm, point, &support);
1579:         for (s = 0; s < supportSize; ++s) {
1580:           DMLabelSetValue(label, support[s], newLevel);
1581:         }
1582:       }
1583:       ISRestoreIndices(pointIS, &points);
1584:       ++level;
1585:       ISDestroy(&pointIS);
1586:       DMLabelGetStratumIS(label, level, &pointIS);
1587:       if (pointIS) {ISGetLocalSize(pointIS, &numPoints);}
1588:       else         {numPoints = 0;}
1589:     }
1590:     ISDestroy(&pointIS);
1591:   }
1592:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
1593:   return(0);
1594: }

1598: /*@C
1599:   DMPlexGetJoin - Get an array for the join of the set of points

1601:   Not Collective

1603:   Input Parameters:
1604: + dm - The DMPlex object
1605: . numPoints - The number of input points for the join
1606: - points - The input points

1608:   Output Parameters:
1609: + numCoveredPoints - The number of points in the join
1610: - coveredPoints - The points in the join

1612:   Level: intermediate

1614:   Note: Currently, this is restricted to a single level join

1616:   Fortran Notes:
1617:   Since it returns an array, this routine is only available in Fortran 90, and you must
1618:   include petsc.h90 in your code.

1620:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1622: .keywords: mesh
1623: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1624: @*/
1625: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1626: {
1627:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1628:   PetscInt      *join[2];
1629:   PetscInt       joinSize, i = 0;
1630:   PetscInt       dof, off, p, c, m;

1638:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
1639:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
1640:   /* Copy in support of first point */
1641:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
1642:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
1643:   for (joinSize = 0; joinSize < dof; ++joinSize) {
1644:     join[i][joinSize] = mesh->supports[off+joinSize];
1645:   }
1646:   /* Check each successive support */
1647:   for (p = 1; p < numPoints; ++p) {
1648:     PetscInt newJoinSize = 0;

1650:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
1651:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
1652:     for (c = 0; c < dof; ++c) {
1653:       const PetscInt point = mesh->supports[off+c];

1655:       for (m = 0; m < joinSize; ++m) {
1656:         if (point == join[i][m]) {
1657:           join[1-i][newJoinSize++] = point;
1658:           break;
1659:         }
1660:       }
1661:     }
1662:     joinSize = newJoinSize;
1663:     i        = 1-i;
1664:   }
1665:   *numCoveredPoints = joinSize;
1666:   *coveredPoints    = join[i];
1667:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1668:   return(0);
1669: }

1673: /*@C
1674:   DMPlexRestoreJoin - Restore an array for the join of the set of points

1676:   Not Collective

1678:   Input Parameters:
1679: + dm - The DMPlex object
1680: . numPoints - The number of input points for the join
1681: - points - The input points

1683:   Output Parameters:
1684: + numCoveredPoints - The number of points in the join
1685: - coveredPoints - The points in the join

1687:   Fortran Notes:
1688:   Since it returns an array, this routine is only available in Fortran 90, and you must
1689:   include petsc.h90 in your code.

1691:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1693:   Level: intermediate

1695: .keywords: mesh
1696: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1697: @*/
1698: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1699: {

1707:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1708:   if (numCoveredPoints) *numCoveredPoints = 0;
1709:   return(0);
1710: }

1714: /*@C
1715:   DMPlexGetFullJoin - Get an array for the join of the set of points

1717:   Not Collective

1719:   Input Parameters:
1720: + dm - The DMPlex object
1721: . numPoints - The number of input points for the join
1722: - points - The input points

1724:   Output Parameters:
1725: + numCoveredPoints - The number of points in the join
1726: - coveredPoints - The points in the join

1728:   Fortran Notes:
1729:   Since it returns an array, this routine is only available in Fortran 90, and you must
1730:   include petsc.h90 in your code.

1732:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1734:   Level: intermediate

1736: .keywords: mesh
1737: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1738: @*/
1739: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1740: {
1741:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1742:   PetscInt      *offsets, **closures;
1743:   PetscInt      *join[2];
1744:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1745:   PetscInt       p, d, c, m;


1754:   DMPlexGetDepth(dm, &depth);
1755:   PetscCalloc1(numPoints, &closures);
1756:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1757:   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1758:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
1759:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

1761:   for (p = 0; p < numPoints; ++p) {
1762:     PetscInt closureSize;

1764:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);

1766:     offsets[p*(depth+2)+0] = 0;
1767:     for (d = 0; d < depth+1; ++d) {
1768:       PetscInt pStart, pEnd, i;

1770:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1771:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1772:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1773:           offsets[p*(depth+2)+d+1] = i;
1774:           break;
1775:         }
1776:       }
1777:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1778:     }
1779:     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);
1780:   }
1781:   for (d = 0; d < depth+1; ++d) {
1782:     PetscInt dof;

1784:     /* Copy in support of first point */
1785:     dof = offsets[d+1] - offsets[d];
1786:     for (joinSize = 0; joinSize < dof; ++joinSize) {
1787:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1788:     }
1789:     /* Check each successive cone */
1790:     for (p = 1; p < numPoints && joinSize; ++p) {
1791:       PetscInt newJoinSize = 0;

1793:       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1794:       for (c = 0; c < dof; ++c) {
1795:         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];

1797:         for (m = 0; m < joinSize; ++m) {
1798:           if (point == join[i][m]) {
1799:             join[1-i][newJoinSize++] = point;
1800:             break;
1801:           }
1802:         }
1803:       }
1804:       joinSize = newJoinSize;
1805:       i        = 1-i;
1806:     }
1807:     if (joinSize) break;
1808:   }
1809:   *numCoveredPoints = joinSize;
1810:   *coveredPoints    = join[i];
1811:   for (p = 0; p < numPoints; ++p) {
1812:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
1813:   }
1814:   PetscFree(closures);
1815:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1816:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1817:   return(0);
1818: }

1822: /*@C
1823:   DMPlexGetMeet - Get an array for the meet of the set of points

1825:   Not Collective

1827:   Input Parameters:
1828: + dm - The DMPlex object
1829: . numPoints - The number of input points for the meet
1830: - points - The input points

1832:   Output Parameters:
1833: + numCoveredPoints - The number of points in the meet
1834: - coveredPoints - The points in the meet

1836:   Level: intermediate

1838:   Note: Currently, this is restricted to a single level meet

1840:   Fortran Notes:
1841:   Since it returns an array, this routine is only available in Fortran 90, and you must
1842:   include petsc.h90 in your code.

1844:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1846: .keywords: mesh
1847: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1848: @*/
1849: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1850: {
1851:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1852:   PetscInt      *meet[2];
1853:   PetscInt       meetSize, i = 0;
1854:   PetscInt       dof, off, p, c, m;

1862:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
1863:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
1864:   /* Copy in cone of first point */
1865:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
1866:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
1867:   for (meetSize = 0; meetSize < dof; ++meetSize) {
1868:     meet[i][meetSize] = mesh->cones[off+meetSize];
1869:   }
1870:   /* Check each successive cone */
1871:   for (p = 1; p < numPoints; ++p) {
1872:     PetscInt newMeetSize = 0;

1874:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
1875:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
1876:     for (c = 0; c < dof; ++c) {
1877:       const PetscInt point = mesh->cones[off+c];

1879:       for (m = 0; m < meetSize; ++m) {
1880:         if (point == meet[i][m]) {
1881:           meet[1-i][newMeetSize++] = point;
1882:           break;
1883:         }
1884:       }
1885:     }
1886:     meetSize = newMeetSize;
1887:     i        = 1-i;
1888:   }
1889:   *numCoveringPoints = meetSize;
1890:   *coveringPoints    = meet[i];
1891:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
1892:   return(0);
1893: }

1897: /*@C
1898:   DMPlexRestoreMeet - Restore an array for the meet of the set of points

1900:   Not Collective

1902:   Input Parameters:
1903: + dm - The DMPlex object
1904: . numPoints - The number of input points for the meet
1905: - points - The input points

1907:   Output Parameters:
1908: + numCoveredPoints - The number of points in the meet
1909: - coveredPoints - The points in the meet

1911:   Level: intermediate

1913:   Fortran Notes:
1914:   Since it returns an array, this routine is only available in Fortran 90, and you must
1915:   include petsc.h90 in your code.

1917:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1919: .keywords: mesh
1920: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1921: @*/
1922: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1923: {

1931:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1932:   if (numCoveredPoints) *numCoveredPoints = 0;
1933:   return(0);
1934: }

1938: /*@C
1939:   DMPlexGetFullMeet - Get an array for the meet of the set of points

1941:   Not Collective

1943:   Input Parameters:
1944: + dm - The DMPlex object
1945: . numPoints - The number of input points for the meet
1946: - points - The input points

1948:   Output Parameters:
1949: + numCoveredPoints - The number of points in the meet
1950: - coveredPoints - The points in the meet

1952:   Level: intermediate

1954:   Fortran Notes:
1955:   Since it returns an array, this routine is only available in Fortran 90, and you must
1956:   include petsc.h90 in your code.

1958:   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.

1960: .keywords: mesh
1961: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1962: @*/
1963: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1964: {
1965:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1966:   PetscInt      *offsets, **closures;
1967:   PetscInt      *meet[2];
1968:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1969:   PetscInt       p, h, c, m;


1978:   DMPlexGetDepth(dm, &height);
1979:   PetscMalloc1(numPoints, &closures);
1980:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
1981:   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1982:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
1983:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

1985:   for (p = 0; p < numPoints; ++p) {
1986:     PetscInt closureSize;

1988:     DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);

1990:     offsets[p*(height+2)+0] = 0;
1991:     for (h = 0; h < height+1; ++h) {
1992:       PetscInt pStart, pEnd, i;

1994:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
1995:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1996:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1997:           offsets[p*(height+2)+h+1] = i;
1998:           break;
1999:         }
2000:       }
2001:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2002:     }
2003:     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);
2004:   }
2005:   for (h = 0; h < height+1; ++h) {
2006:     PetscInt dof;

2008:     /* Copy in cone of first point */
2009:     dof = offsets[h+1] - offsets[h];
2010:     for (meetSize = 0; meetSize < dof; ++meetSize) {
2011:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2012:     }
2013:     /* Check each successive cone */
2014:     for (p = 1; p < numPoints && meetSize; ++p) {
2015:       PetscInt newMeetSize = 0;

2017:       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2018:       for (c = 0; c < dof; ++c) {
2019:         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];

2021:         for (m = 0; m < meetSize; ++m) {
2022:           if (point == meet[i][m]) {
2023:             meet[1-i][newMeetSize++] = point;
2024:             break;
2025:           }
2026:         }
2027:       }
2028:       meetSize = newMeetSize;
2029:       i        = 1-i;
2030:     }
2031:     if (meetSize) break;
2032:   }
2033:   *numCoveredPoints = meetSize;
2034:   *coveredPoints    = meet[i];
2035:   for (p = 0; p < numPoints; ++p) {
2036:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
2037:   }
2038:   PetscFree(closures);
2039:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
2040:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
2041:   return(0);
2042: }

2046: /*@C
2047:   DMPlexEqual - Determine if two DMs have the same topology

2049:   Not Collective

2051:   Input Parameters:
2052: + dmA - A DMPlex object
2053: - dmB - A DMPlex object

2055:   Output Parameters:
2056: . equal - PETSC_TRUE if the topologies are identical

2058:   Level: intermediate

2060:   Notes:
2061:   We are not solving graph isomorphism, so we do not permutation.

2063: .keywords: mesh
2064: .seealso: DMPlexGetCone()
2065: @*/
2066: PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal)
2067: {
2068:   PetscInt       depth, depthB, pStart, pEnd, pStartB, pEndB, p;


2076:   *equal = PETSC_FALSE;
2077:   DMPlexGetDepth(dmA, &depth);
2078:   DMPlexGetDepth(dmB, &depthB);
2079:   if (depth != depthB) return(0);
2080:   DMPlexGetChart(dmA, &pStart,  &pEnd);
2081:   DMPlexGetChart(dmB, &pStartB, &pEndB);
2082:   if ((pStart != pStartB) || (pEnd != pEndB)) return(0);
2083:   for (p = pStart; p < pEnd; ++p) {
2084:     const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB;
2085:     PetscInt        coneSize, coneSizeB, c, supportSize, supportSizeB, s;

2087:     DMPlexGetConeSize(dmA, p, &coneSize);
2088:     DMPlexGetCone(dmA, p, &cone);
2089:     DMPlexGetConeOrientation(dmA, p, &ornt);
2090:     DMPlexGetConeSize(dmB, p, &coneSizeB);
2091:     DMPlexGetCone(dmB, p, &coneB);
2092:     DMPlexGetConeOrientation(dmB, p, &orntB);
2093:     if (coneSize != coneSizeB) return(0);
2094:     for (c = 0; c < coneSize; ++c) {
2095:       if (cone[c] != coneB[c]) return(0);
2096:       if (ornt[c] != orntB[c]) return(0);
2097:     }
2098:     DMPlexGetSupportSize(dmA, p, &supportSize);
2099:     DMPlexGetSupport(dmA, p, &support);
2100:     DMPlexGetSupportSize(dmB, p, &supportSizeB);
2101:     DMPlexGetSupport(dmB, p, &supportB);
2102:     if (supportSize != supportSizeB) return(0);
2103:     for (s = 0; s < supportSize; ++s) {
2104:       if (support[s] != supportB[s]) return(0);
2105:     }
2106:   }
2107:   *equal = PETSC_TRUE;
2108:   return(0);
2109: }

2113: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
2114: {
2115:   MPI_Comm       comm;

2119:   PetscObjectGetComm((PetscObject)dm,&comm);
2121:   switch (cellDim) {
2122:   case 0:
2123:     *numFaceVertices = 0;
2124:     break;
2125:   case 1:
2126:     *numFaceVertices = 1;
2127:     break;
2128:   case 2:
2129:     switch (numCorners) {
2130:     case 3: /* triangle */
2131:       *numFaceVertices = 2; /* Edge has 2 vertices */
2132:       break;
2133:     case 4: /* quadrilateral */
2134:       *numFaceVertices = 2; /* Edge has 2 vertices */
2135:       break;
2136:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2137:       *numFaceVertices = 3; /* Edge has 3 vertices */
2138:       break;
2139:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2140:       *numFaceVertices = 3; /* Edge has 3 vertices */
2141:       break;
2142:     default:
2143:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2144:     }
2145:     break;
2146:   case 3:
2147:     switch (numCorners) {
2148:     case 4: /* tetradehdron */
2149:       *numFaceVertices = 3; /* Face has 3 vertices */
2150:       break;
2151:     case 6: /* tet cohesive cells */
2152:       *numFaceVertices = 4; /* Face has 4 vertices */
2153:       break;
2154:     case 8: /* hexahedron */
2155:       *numFaceVertices = 4; /* Face has 4 vertices */
2156:       break;
2157:     case 9: /* tet cohesive Lagrange cells */
2158:       *numFaceVertices = 6; /* Face has 6 vertices */
2159:       break;
2160:     case 10: /* quadratic tetrahedron */
2161:       *numFaceVertices = 6; /* Face has 6 vertices */
2162:       break;
2163:     case 12: /* hex cohesive Lagrange cells */
2164:       *numFaceVertices = 6; /* Face has 6 vertices */
2165:       break;
2166:     case 18: /* quadratic tet cohesive Lagrange cells */
2167:       *numFaceVertices = 6; /* Face has 6 vertices */
2168:       break;
2169:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2170:       *numFaceVertices = 9; /* Face has 9 vertices */
2171:       break;
2172:     default:
2173:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2174:     }
2175:     break;
2176:   default:
2177:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2178:   }
2179:   return(0);
2180: }

2184: /* Trys to give the mesh a consistent orientation */
2185: PetscErrorCode DMPlexOrient(DM dm)
2186: {
2187:   PetscBT        seenCells, flippedCells, seenFaces;
2188:   PetscInt      *faceFIFO, fTop, fBottom;
2189:   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;

2193:   /* Truth Table
2194:      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2195:          F       0 flips     no         F             F           F
2196:          F       1 flip      yes        F             T           T
2197:          F       2 flips     no         T             F           T
2198:          T       0 flips     yes        T             T           F
2199:          T       1 flip      no
2200:          T       2 flips     yes
2201:   */
2202:   DMPlexGetDimension(dm, &dim);
2203:   DMPlexGetVTKCellHeight(dm, &h);
2204:   DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);
2205:   DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);
2206:   PetscBTCreate(cEnd - cStart, &seenCells);
2207:   PetscBTMemzero(cEnd - cStart, seenCells);
2208:   PetscBTCreate(cEnd - cStart, &flippedCells);
2209:   PetscBTMemzero(cEnd - cStart, flippedCells);
2210:   PetscBTCreate(fEnd - fStart, &seenFaces);
2211:   PetscBTMemzero(fEnd - fStart, seenFaces);
2212:   PetscMalloc1((fEnd - fStart), &faceFIFO);
2213:   fTop = fBottom = 0;
2214:   /* Initialize FIFO with first cell */
2215:   if (cEnd > cStart) {
2216:     const PetscInt *cone;
2217:     PetscInt        coneSize;

2219:     DMPlexGetConeSize(dm, cStart, &coneSize);
2220:     DMPlexGetCone(dm, cStart, &cone);
2221:     for (c = 0; c < coneSize; ++c) {
2222:       faceFIFO[fBottom++] = cone[c];
2223:       PetscBTSet(seenFaces, cone[c]-fStart);
2224:     }
2225:   }
2226:   /* Consider each face in FIFO */
2227:   while (fTop < fBottom) {
2228:     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2229:     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2230:     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;

2232:     face = faceFIFO[fTop++];
2233:     DMPlexGetSupportSize(dm, face, &supportSize);
2234:     DMPlexGetSupport(dm, face, &support);
2235:     if (supportSize < 2) continue;
2236:     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2237:     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2238:     flippedA = PetscBTLookup(flippedCells, support[0]-cStart) ? 1 : 0;
2239:     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2240:     flippedB = PetscBTLookup(flippedCells, support[1]-cStart) ? 1 : 0;

2242:     DMPlexGetConeSize(dm, support[0], &coneSizeA);
2243:     DMPlexGetConeSize(dm, support[1], &coneSizeB);
2244:     DMPlexGetCone(dm, support[0], &coneA);
2245:     DMPlexGetCone(dm, support[1], &coneB);
2246:     DMPlexGetConeOrientation(dm, support[0], &coneOA);
2247:     DMPlexGetConeOrientation(dm, support[1], &coneOB);
2248:     for (c = 0; c < coneSizeA; ++c) {
2249:       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2250:         faceFIFO[fBottom++] = coneA[c];
2251:         PetscBTSet(seenFaces, coneA[c]-fStart);
2252:       }
2253:       if (coneA[c] == face) posA = c;
2254:       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2255:     }
2256:     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2257:     for (c = 0; c < coneSizeB; ++c) {
2258:       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2259:         faceFIFO[fBottom++] = coneB[c];
2260:         PetscBTSet(seenFaces, coneB[c]-fStart);
2261:       }
2262:       if (coneB[c] == face) posB = c;
2263:       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2264:     }
2265:     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);

2267:     if (dim == 1) {
2268:       mismatch = posA == posB;
2269:     } else {
2270:       mismatch = coneOA[posA] == coneOB[posB];
2271:     }

2273:     if (mismatch ^ (flippedA ^ flippedB)) {
2274:       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]);
2275:       if (!seenA && !flippedA) {
2276:         PetscBTSet(flippedCells, support[0]-cStart);
2277:       } else if (!seenB && !flippedB) {
2278:         PetscBTSet(flippedCells, support[1]-cStart);
2279:       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2280:     } else if (mismatch && flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2281:     PetscBTSet(seenCells, support[0]-cStart);
2282:     PetscBTSet(seenCells, support[1]-cStart);
2283:   }

2285:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2286:   DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2287:   DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2288:   for (c = cStart; c < cEnd; ++c) {
2289:     const PetscInt *cone, *coneO, *support;
2290:     PetscInt        coneSize, supportSize, faceSize, cp, sp;

2292:     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2293:     DMPlexGetConeSize(dm, c, &coneSize);
2294:     DMPlexGetCone(dm, c, &cone);
2295:     DMPlexGetConeOrientation(dm, c, &coneO);
2296:     for (cp = 0; cp < coneSize; ++cp) {
2297:       const PetscInt rcp = coneSize-cp-1;

2299:       DMPlexGetConeSize(dm, cone[rcp], &faceSize);
2300:       revcone[cp]  = cone[rcp];
2301:       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2302:     }
2303:     DMPlexSetCone(dm, c, revcone);
2304:     DMPlexSetConeOrientation(dm, c, revconeO);
2305:     /* Reverse orientations of support */
2306:     faceSize = coneSize;
2307:     DMPlexGetSupportSize(dm, c, &supportSize);
2308:     DMPlexGetSupport(dm, c, &support);
2309:     for (sp = 0; sp < supportSize; ++sp) {
2310:       DMPlexGetConeSize(dm, support[sp], &coneSize);
2311:       DMPlexGetCone(dm, support[sp], &cone);
2312:       DMPlexGetConeOrientation(dm, support[sp], &coneO);
2313:       for (cp = 0; cp < coneSize; ++cp) {
2314:         if (cone[cp] != c) continue;
2315:         DMPlexInsertConeOrientation(dm, support[sp], cp, coneO[cp] >= 0 ? -(faceSize-coneO[cp]) : faceSize+coneO[cp]);
2316:       }
2317:     }
2318:   }
2319:   DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2320:   DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2321:   PetscBTDestroy(&seenCells);
2322:   PetscBTDestroy(&flippedCells);
2323:   PetscBTDestroy(&seenFaces);
2324:   PetscFree(faceFIFO);
2325:   return(0);
2326: }

2330: static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2331: {
2332:   const PetscInt *support = NULL;
2333:   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2334:   PetscErrorCode  ierr;

2337:   if (useClosure) {
2338:     DMPlexGetConeSize(dm, p, &supportSize);
2339:     DMPlexGetCone(dm, p, &support);
2340:     for (s = 0; s < supportSize; ++s) {
2341:       const PetscInt *cone = NULL;
2342:       PetscInt        coneSize, c, q;

2344:       DMPlexGetSupportSize(dm, support[s], &coneSize);
2345:       DMPlexGetSupport(dm, support[s], &cone);
2346:       for (c = 0; c < coneSize; ++c) {
2347:         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2348:           if (cone[c] == adj[q]) break;
2349:         }
2350:         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2351:       }
2352:     }
2353:   } else {
2354:     DMPlexGetSupportSize(dm, p, &supportSize);
2355:     DMPlexGetSupport(dm, p, &support);
2356:     for (s = 0; s < supportSize; ++s) {
2357:       const PetscInt *cone = NULL;
2358:       PetscInt        coneSize, c, q;

2360:       DMPlexGetConeSize(dm, support[s], &coneSize);
2361:       DMPlexGetCone(dm, support[s], &cone);
2362:       for (c = 0; c < coneSize; ++c) {
2363:         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2364:           if (cone[c] == adj[q]) break;
2365:         }
2366:         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2367:       }
2368:     }
2369:   }
2370:   *adjSize = numAdj;
2371:   return(0);
2372: }

2376: PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2377: {
2378:   const PetscInt maxFaceCases = 30;
2379:   PetscInt       numFaceCases = 0;
2380:   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2381:   PetscInt      *off, *adj;
2382:   PetscInt      *neighborCells, *tmpClosure;
2383:   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2384:   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;

2388:   /* For parallel partitioning, I think you have to communicate supports */
2389:   DMPlexGetDimension(dm, &dim);
2390:   cellDim = dim - cellHeight;
2391:   DMPlexGetDepth(dm, &depth);
2392:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
2393:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
2394:   if (cEnd - cStart == 0) {
2395:     if (numVertices) *numVertices = 0;
2396:     if (offsets)   *offsets   = NULL;
2397:     if (adjacency) *adjacency = NULL;
2398:     return(0);
2399:   }
2400:   numCells  = cEnd - cStart;
2401:   faceDepth = depth - cellHeight;
2402:   if (dim == depth) {
2403:     PetscInt f, fStart, fEnd;

2405:     PetscCalloc1(numCells+1, &off);
2406:     /* Count neighboring cells */
2407:     DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);
2408:     for (f = fStart; f < fEnd; ++f) {
2409:       const PetscInt *support;
2410:       PetscInt        supportSize;
2411:       DMPlexGetSupportSize(dm, f, &supportSize);
2412:       DMPlexGetSupport(dm, f, &support);
2413:       if (supportSize == 2) {
2414:         ++off[support[0]-cStart+1];
2415:         ++off[support[1]-cStart+1];
2416:       }
2417:     }
2418:     /* Prefix sum */
2419:     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
2420:     if (adjacency) {
2421:       PetscInt *tmp;

2423:       PetscMalloc1(off[numCells], &adj);
2424:       PetscMalloc1((numCells+1), &tmp);
2425:       PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));
2426:       /* Get neighboring cells */
2427:       for (f = fStart; f < fEnd; ++f) {
2428:         const PetscInt *support;
2429:         PetscInt        supportSize;
2430:         DMPlexGetSupportSize(dm, f, &supportSize);
2431:         DMPlexGetSupport(dm, f, &support);
2432:         if (supportSize == 2) {
2433:           adj[tmp[support[0]-cStart]++] = support[1];
2434:           adj[tmp[support[1]-cStart]++] = support[0];
2435:         }
2436:       }
2437: #if defined(PETSC_USE_DEBUG)
2438:       for (c = 0; c < cEnd-cStart; ++c) if (tmp[c] != off[c+1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
2439: #endif
2440:       PetscFree(tmp);
2441:     }
2442:     if (numVertices) *numVertices = numCells;
2443:     if (offsets)   *offsets   = off;
2444:     if (adjacency) *adjacency = adj;
2445:     return(0);
2446:   }
2447:   /* Setup face recognition */
2448:   if (faceDepth == 1) {
2449:     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */

2451:     for (c = cStart; c < cEnd; ++c) {
2452:       PetscInt corners;

2454:       DMPlexGetConeSize(dm, c, &corners);
2455:       if (!cornersSeen[corners]) {
2456:         PetscInt nFV;

2458:         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2459:         cornersSeen[corners] = 1;

2461:         DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);

2463:         numFaceVertices[numFaceCases++] = nFV;
2464:       }
2465:     }
2466:   }
2467:   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2468:   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2469:   PetscMalloc2(maxNeighbors,&neighborCells,maxClosure,&tmpClosure);
2470:   PetscCalloc1(numCells+1, &off);
2471:   /* Count neighboring cells */
2472:   for (cell = cStart; cell < cEnd; ++cell) {
2473:     PetscInt numNeighbors = maxNeighbors, n;

2475:     DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2476:     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2477:     for (n = 0; n < numNeighbors; ++n) {
2478:       PetscInt        cellPair[2];
2479:       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2480:       PetscInt        meetSize = 0;
2481:       const PetscInt *meet    = NULL;

2483:       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2484:       if (cellPair[0] == cellPair[1]) continue;
2485:       if (!found) {
2486:         DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2487:         if (meetSize) {
2488:           PetscInt f;

2490:           for (f = 0; f < numFaceCases; ++f) {
2491:             if (numFaceVertices[f] == meetSize) {
2492:               found = PETSC_TRUE;
2493:               break;
2494:             }
2495:           }
2496:         }
2497:         DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2498:       }
2499:       if (found) ++off[cell-cStart+1];
2500:     }
2501:   }
2502:   /* Prefix sum */
2503:   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];

2505:   if (adjacency) {
2506:     PetscMalloc1(off[numCells], &adj);
2507:     /* Get neighboring cells */
2508:     for (cell = cStart; cell < cEnd; ++cell) {
2509:       PetscInt numNeighbors = maxNeighbors, n;
2510:       PetscInt cellOffset   = 0;

2512:       DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2513:       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2514:       for (n = 0; n < numNeighbors; ++n) {
2515:         PetscInt        cellPair[2];
2516:         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2517:         PetscInt        meetSize = 0;
2518:         const PetscInt *meet    = NULL;

2520:         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2521:         if (cellPair[0] == cellPair[1]) continue;
2522:         if (!found) {
2523:           DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2524:           if (meetSize) {
2525:             PetscInt f;

2527:             for (f = 0; f < numFaceCases; ++f) {
2528:               if (numFaceVertices[f] == meetSize) {
2529:                 found = PETSC_TRUE;
2530:                 break;
2531:               }
2532:             }
2533:           }
2534:           DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2535:         }
2536:         if (found) {
2537:           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2538:           ++cellOffset;
2539:         }
2540:       }
2541:     }
2542:   }
2543:   PetscFree2(neighborCells,tmpClosure);
2544:   if (numVertices) *numVertices = numCells;
2545:   if (offsets)   *offsets   = off;
2546:   if (adjacency) *adjacency = adj;
2547:   return(0);
2548: }

2550: #if defined(PETSC_HAVE_CHACO)
2551: #if defined(PETSC_HAVE_UNISTD_H)
2552: #include <unistd.h>
2553: #endif
2554: /* Chaco does not have an include file */
2555: PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2556:                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2557:                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2558:                        int mesh_dims[3], double *goal, int global_method, int local_method,
2559:                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);

2561: extern int FREE_GRAPH;

2565: PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2566: {
2567:   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2568:   MPI_Comm       comm;
2569:   int            nvtxs          = numVertices; /* number of vertices in full graph */
2570:   int           *vwgts          = NULL;   /* weights for all vertices */
2571:   float         *ewgts          = NULL;   /* weights for all edges */
2572:   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2573:   char          *outassignname  = NULL;   /*  name of assignment output file */
2574:   char          *outfilename    = NULL;   /* output file name */
2575:   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2576:   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2577:   int            mesh_dims[3];            /* dimensions of mesh of processors */
2578:   double        *goal          = NULL;    /* desired set sizes for each set */
2579:   int            global_method = 1;       /* global partitioning algorithm */
2580:   int            local_method  = 1;       /* local partitioning algorithm */
2581:   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2582:   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2583:   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2584:   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2585:   long           seed          = 123636512; /* for random graph mutations */
2586:   short int     *assignment;              /* Output partition */
2587:   int            fd_stdout, fd_pipe[2];
2588:   PetscInt      *points;
2589:   PetscMPIInt    commSize;
2590:   int            i, v, p;

2594:   PetscObjectGetComm((PetscObject)dm,&comm);
2595:   MPI_Comm_size(comm, &commSize);
2596:   if (!numVertices) {
2597:     PetscSectionCreate(comm, partSection);
2598:     PetscSectionSetChart(*partSection, 0, commSize);
2599:     PetscSectionSetUp(*partSection);
2600:     ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);
2601:     return(0);
2602:   }
2603:   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2604:   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];

2606:   if (global_method == INERTIAL_METHOD) {
2607:     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2608:     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2609:   }
2610:   mesh_dims[0] = commSize;
2611:   mesh_dims[1] = 1;
2612:   mesh_dims[2] = 1;
2613:   PetscMalloc1(nvtxs, &assignment);
2614:   /* Chaco outputs to stdout. We redirect this to a buffer. */
2615:   /* TODO: check error codes for UNIX calls */
2616: #if defined(PETSC_HAVE_UNISTD_H)
2617:   {
2618:     int piperet;
2619:     piperet = pipe(fd_pipe);
2620:     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2621:     fd_stdout = dup(1);
2622:     close(1);
2623:     dup2(fd_pipe[1], 1);
2624:   }
2625: #endif
2626:   interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2627:                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2628:                    vmax, ndims, eigtol, seed);
2629: #if defined(PETSC_HAVE_UNISTD_H)
2630:   {
2631:     char msgLog[10000];
2632:     int  count;

2634:     fflush(stdout);
2635:     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2636:     if (count < 0) count = 0;
2637:     msgLog[count] = 0;
2638:     close(1);
2639:     dup2(fd_stdout, 1);
2640:     close(fd_stdout);
2641:     close(fd_pipe[0]);
2642:     close(fd_pipe[1]);
2643:     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2644:   }
2645: #endif
2646:   /* Convert to PetscSection+IS */
2647:   PetscSectionCreate(comm, partSection);
2648:   PetscSectionSetChart(*partSection, 0, commSize);
2649:   for (v = 0; v < nvtxs; ++v) {
2650:     PetscSectionAddDof(*partSection, assignment[v], 1);
2651:   }
2652:   PetscSectionSetUp(*partSection);
2653:   PetscMalloc1(nvtxs, &points);
2654:   for (p = 0, i = 0; p < commSize; ++p) {
2655:     for (v = 0; v < nvtxs; ++v) {
2656:       if (assignment[v] == p) points[i++] = v;
2657:     }
2658:   }
2659:   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2660:   ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);
2661:   if (global_method == INERTIAL_METHOD) {
2662:     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2663:   }
2664:   PetscFree(assignment);
2665:   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2666:   return(0);
2667: }
2668: #endif

2670: #if defined(PETSC_HAVE_PARMETIS)
2671: #include <parmetis.h>

2675: PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2676: {
2677:   MPI_Comm       comm;
2678:   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
2679:   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
2680:   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
2681:   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
2682:   PetscInt      *vwgt       = NULL;        /* Vertex weights */
2683:   PetscInt      *adjwgt     = NULL;        /* Edge weights */
2684:   PetscInt       wgtflag    = 0;           /* Indicates which weights are present */
2685:   PetscInt       numflag    = 0;           /* Indicates initial offset (0 or 1) */
2686:   PetscInt       ncon       = 1;           /* The number of weights per vertex */
2687:   PetscInt       nparts;                   /* The number of partitions */
2688:   PetscReal     *tpwgts;                   /* The fraction of vertex weights assigned to each partition */
2689:   PetscReal     *ubvec;                    /* The balance intolerance for vertex weights */
2690:   PetscInt       options[5];               /* Options */
2691:   /* Outputs */
2692:   PetscInt       edgeCut;                  /* The number of edges cut by the partition */
2693:   PetscInt      *assignment, *points;
2694:   PetscMPIInt    commSize, rank, p, v, i;

2698:   PetscObjectGetComm((PetscObject) dm, &comm);
2699:   MPI_Comm_size(comm, &commSize);
2700:   MPI_Comm_rank(comm, &rank);
2701:   nparts = commSize;
2702:   options[0] = 0; /* Use all defaults */
2703:   /* Calculate vertex distribution */
2704:   PetscMalloc4(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);
2705:   vtxdist[0] = 0;
2706:   MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);
2707:   for (p = 2; p <= nparts; ++p) {
2708:     vtxdist[p] += vtxdist[p-1];
2709:   }
2710:   /* Calculate weights */
2711:   for (p = 0; p < nparts; ++p) {
2712:     tpwgts[p] = 1.0/nparts;
2713:   }
2714:   ubvec[0] = 1.05;

2716:   if (nparts == 1) {
2717:     PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
2718:   } else {
2719:     if (vtxdist[1] == vtxdist[nparts]) {
2720:       if (!rank) {
2721:         PetscStackPush("METIS_PartGraphKway");
2722:         METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
2723:         PetscStackPop;
2724:         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
2725:       }
2726:     } else {
2727:       PetscStackPush("ParMETIS_V3_PartKway");
2728:       ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
2729:       PetscStackPop;
2730:       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
2731:     }
2732:   }
2733:   /* Convert to PetscSection+IS */
2734:   PetscSectionCreate(comm, partSection);
2735:   PetscSectionSetChart(*partSection, 0, commSize);
2736:   for (v = 0; v < nvtxs; ++v) {
2737:     PetscSectionAddDof(*partSection, assignment[v], 1);
2738:   }
2739:   PetscSectionSetUp(*partSection);
2740:   PetscMalloc1(nvtxs, &points);
2741:   for (p = 0, i = 0; p < commSize; ++p) {
2742:     for (v = 0; v < nvtxs; ++v) {
2743:       if (assignment[v] == p) points[i++] = v;
2744:     }
2745:   }
2746:   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2747:   ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);
2748:   PetscFree4(vtxdist,tpwgts,ubvec,assignment);
2749:   return(0);
2750: }
2751: #endif

2755: /* Expand the partition by BFS on the adjacency graph */
2756: PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2757: {
2758:   PetscHashI      h;
2759:   const PetscInt *points;
2760:   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2761:   PetscInt        pStart, pEnd, part, q;
2762:   PetscErrorCode  ierr;

2765:   PetscHashICreate(h);
2766:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2767:   PetscSectionGetChart(origPartSection, &pStart, &pEnd);
2768:   PetscSectionSetChart(*partSection, pStart, pEnd);
2769:   ISGetIndices(origPartition, &points);
2770:   PetscMalloc1((pEnd - pStart), &tmpPoints);
2771:   for (part = pStart; part < pEnd; ++part) {
2772:     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;

2774:     PetscHashIClear(h);
2775:     PetscSectionGetDof(origPartSection, part, &numPoints);
2776:     PetscSectionGetOffset(origPartSection, part, &off);
2777:     /* Add all existing points to h */
2778:     for (p = 0; p < numPoints; ++p) {
2779:       const PetscInt point = points[off+p];
2780:       PetscHashIAdd(h, point, 1);
2781:     }
2782:     PetscHashISize(h, nP);
2783:     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2784:     /* Add all points in next BFS level */
2785:     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2786:     for (p = 0; p < numPoints; ++p) {
2787:       const PetscInt point = points[off+p];
2788:       PetscInt       s     = start[point], e = start[point+1], a;

2790:       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2791:     }
2792:     PetscHashISize(h, numNewPoints);
2793:     PetscSectionSetDof(*partSection, part, numNewPoints);
2794:     PetscMalloc1(numNewPoints, &tmpPoints[part]);
2795:      PetscHashIGetKeys(h, &n, tmpPoints[part]);
2796:     totPoints += numNewPoints;
2797:   }
2798:   ISRestoreIndices(origPartition, &points);
2799:   PetscHashIDestroy(h);
2800:   PetscSectionSetUp(*partSection);
2801:   PetscMalloc1(totPoints, &newPoints);
2802:   for (part = pStart, q = 0; part < pEnd; ++part) {
2803:     PetscInt numPoints, p;

2805:     PetscSectionGetDof(*partSection, part, &numPoints);
2806:     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2807:     PetscFree(tmpPoints[part]);
2808:   }
2809:   PetscFree(tmpPoints);
2810:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);
2811:   return(0);
2812: }

2816: /*
2817:   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height

2819:   Collective on DM

2821:   Input Parameters:
2822:   + dm - The DM
2823:   . height - The height for points in the partition
2824:   - enlarge - Expand each partition with neighbors

2826:   Output Parameters:
2827:   + partSection - The PetscSection giving the division of points by partition
2828:   . partition - The list of points by partition
2829:   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2830:   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL

2832:   Level: developer

2834: .seealso DMPlexDistribute()
2835: */
2836: PetscErrorCode DMPlexCreatePartition(DM dm, const char name[], PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2837: {
2838:   char           partname[1024];
2839:   PetscBool      isChaco = PETSC_FALSE, isMetis = PETSC_FALSE, flg;
2840:   PetscMPIInt    size;

2844:   MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);

2846:   *origPartSection = NULL;
2847:   *origPartition   = NULL;
2848:   if (size == 1) {
2849:     PetscInt *points;
2850:     PetscInt  cStart, cEnd, c;

2852:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
2853:     PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2854:     PetscSectionSetChart(*partSection, 0, size);
2855:     PetscSectionSetDof(*partSection, 0, cEnd-cStart);
2856:     PetscSectionSetUp(*partSection);
2857:     PetscMalloc1((cEnd - cStart), &points);
2858:     for (c = cStart; c < cEnd; ++c) points[c] = c;
2859:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);
2860:     return(0);
2861:   }
2862:   PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_partitioner", partname, 1024, &flg);
2863:   if (flg) name = partname;
2864:   if (name) {
2865:     PetscStrcmp(name, "chaco", &isChaco);
2866:     PetscStrcmp(name, "metis", &isMetis);
2867:   }
2868:   if (height == 0) {
2869:     PetscInt  numVertices;
2870:     PetscInt *start     = NULL;
2871:     PetscInt *adjacency = NULL;

2873:     DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);
2874:     if (!name || isChaco) {
2875: #if defined(PETSC_HAVE_CHACO)
2876:       DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);
2877: #else
2878:       SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
2879: #endif
2880:     } else if (isMetis) {
2881: #if defined(PETSC_HAVE_PARMETIS)
2882:       DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);
2883: #endif
2884:     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Unknown mesh partitioning package %s", name);
2885:     if (enlarge) {
2886:       *origPartSection = *partSection;
2887:       *origPartition   = *partition;

2889:       DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);
2890:     }
2891:     PetscFree(start);
2892:     PetscFree(adjacency);
2893: # if 0
2894:   } else if (height == 1) {
2895:     /* Build the dual graph for faces and partition the hypergraph */
2896:     PetscInt numEdges;

2898:     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2899:     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2900:     destroyCSR(numEdges, start, adjacency);
2901: #endif
2902:   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2903:   return(0);
2904: }

2908: PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2909: {
2910:   /* const PetscInt  height = 0; */
2911:   const PetscInt *partArray;
2912:   PetscInt       *allPoints, *packPoints;
2913:   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2914:   PetscErrorCode  ierr;
2915:   PetscBT         bt;
2916:   PetscSegBuffer  segpack,segpart;

2919:   PetscSectionGetChart(pointSection, &rStart, &rEnd);
2920:   ISGetIndices(pointPartition, &partArray);
2921:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2922:   PetscSectionSetChart(*section, rStart, rEnd);
2923:   DMPlexGetChart(dm,&pStart,&pEnd);
2924:   PetscBTCreate(pEnd-pStart,&bt);
2925:   PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);
2926:   PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);
2927:   for (rank = rStart; rank < rEnd; ++rank) {
2928:     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;

2930:     PetscSectionGetDof(pointSection, rank, &numPoints);
2931:     PetscSectionGetOffset(pointSection, rank, &offset);
2932:     for (p = 0; p < numPoints; ++p) {
2933:       PetscInt  point   = partArray[offset+p], closureSize, c;
2934:       PetscInt *closure = NULL;

2936:       /* TODO Include support for height > 0 case */
2937:       DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2938:       for (c=0; c<closureSize; c++) {
2939:         PetscInt cpoint = closure[c*2];
2940:         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2941:           PetscInt *PETSC_RESTRICT pt;
2942:           partSize++;
2943:           PetscSegBufferGetInts(segpart,1,&pt);
2944:           *pt = cpoint;
2945:         }
2946:       }
2947:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2948:     }
2949:     PetscSectionSetDof(*section, rank, partSize);
2950:     PetscSegBufferGetInts(segpack,partSize,&placePoints);
2951:     PetscSegBufferExtractTo(segpart,placePoints);
2952:     PetscSortInt(partSize,placePoints);
2953:     for (p=0; p<partSize; p++) {PetscBTClear(bt,placePoints[p]-pStart);}
2954:   }
2955:   PetscBTDestroy(&bt);
2956:   PetscSegBufferDestroy(&segpart);

2958:   PetscSectionSetUp(*section);
2959:   PetscSectionGetStorageSize(*section, &newSize);
2960:   PetscMalloc1(newSize, &allPoints);

2962:   PetscSegBufferExtractInPlace(segpack,&packPoints);
2963:   for (rank = rStart; rank < rEnd; ++rank) {
2964:     PetscInt numPoints, offset;

2966:     PetscSectionGetDof(*section, rank, &numPoints);
2967:     PetscSectionGetOffset(*section, rank, &offset);
2968:     PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));
2969:     packPoints += numPoints;
2970:   }

2972:   PetscSegBufferDestroy(&segpack);
2973:   ISRestoreIndices(pointPartition, &partArray);
2974:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);
2975:   return(0);
2976: }

2980: /*@
2981:   DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution

2983:   Collective on DM

2985:   Input Parameters:
2986: + dm - The DMPlex object
2987: . pointSF - The PetscSF describing the communication pattern
2988: . originalSection - The PetscSection for existing data layout
2989: - originalVec - The existing data

2991:   Output Parameters:
2992: + newSection - The PetscSF describing the new data layout
2993: - newVec - The new data

2995:   Level: developer

2997: .seealso: DMPlexDistribute(), DMPlexDistributeData()
2998: @*/
2999: PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3000: {
3001:   PetscSF        fieldSF;
3002:   PetscInt      *remoteOffsets, fieldSize;
3003:   PetscScalar   *originalValues, *newValues;

3007:   PetscLogEventBegin(DMPLEX_DistributeField,dm,0,0,0);
3008:   PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);

3010:   PetscSectionGetStorageSize(newSection, &fieldSize);
3011:   VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);
3012:   VecSetType(newVec,dm->vectype);

3014:   VecGetArray(originalVec, &originalValues);
3015:   VecGetArray(newVec, &newValues);
3016:   PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);
3017:   PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);
3018:   PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);
3019:   PetscSFDestroy(&fieldSF);
3020:   VecRestoreArray(newVec, &newValues);
3021:   VecRestoreArray(originalVec, &originalValues);
3022:   PetscLogEventEnd(DMPLEX_DistributeField,dm,0,0,0);
3023:   return(0);
3024: }

3028: /*@
3029:   DMPlexDistributeData - Distribute field data to match a given PetscSF, usually the SF from mesh distribution

3031:   Collective on DM

3033:   Input Parameters:
3034: + dm - The DMPlex object
3035: . pointSF - The PetscSF describing the communication pattern
3036: . originalSection - The PetscSection for existing data layout
3037: . datatype - The type of data
3038: - originalData - The existing data

3040:   Output Parameters:
3041: + newSection - The PetscSF describing the new data layout
3042: - newData - The new data

3044:   Level: developer

3046: .seealso: DMPlexDistribute(), DMPlexDistributeField()
3047: @*/
3048: PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
3049: {
3050:   PetscSF        fieldSF;
3051:   PetscInt      *remoteOffsets, fieldSize;
3052:   PetscMPIInt    dataSize;

3056:   PetscLogEventBegin(DMPLEX_DistributeData,dm,0,0,0);
3057:   PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);

3059:   PetscSectionGetStorageSize(newSection, &fieldSize);
3060:   MPI_Type_size(datatype, &dataSize);
3061:   PetscMalloc(fieldSize * dataSize, newData);

3063:   PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);
3064:   PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);
3065:   PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);
3066:   PetscSFDestroy(&fieldSF);
3067:   PetscLogEventEnd(DMPLEX_DistributeData,dm,0,0,0);
3068:   return(0);
3069: }

3073: /*@C
3074:   DMPlexDistribute - Distributes the mesh and any associated sections.

3076:   Not Collective

3078:   Input Parameter:
3079: + dm  - The original DMPlex object
3080: . partitioner - The partitioning package, or NULL for the default
3081: - overlap - The overlap of partitions, 0 is the default

3083:   Output Parameter:
3084: + sf - The PetscSF used for point distribution
3085: - parallelMesh - The distributed DMPlex object, or NULL

3087:   Note: If the mesh was not distributed, the return value is NULL

3089:   Level: intermediate

3091: .keywords: mesh, elements
3092: .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3093: @*/
3094: PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel)
3095: {
3096:   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3097:   MPI_Comm               comm;
3098:   const PetscInt         height = 0;
3099:   PetscInt               dim, numRemoteRanks;
3100:   IS                     origCellPart,        origPart,        cellPart,        part;
3101:   PetscSection           origCellPartSection, origPartSection, cellPartSection, partSection;
3102:   PetscSFNode           *remoteRanks;
3103:   PetscSF                partSF, pointSF, coneSF;
3104:   ISLocalToGlobalMapping renumbering;
3105:   PetscSection           originalConeSection, newConeSection;
3106:   PetscInt              *remoteOffsets;
3107:   PetscInt              *cones, *newCones, newConesSize;
3108:   PetscBool              flg;
3109:   PetscMPIInt            rank, numProcs, p;
3110:   PetscErrorCode         ierr;


3117:   PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);
3118:   PetscObjectGetComm((PetscObject)dm,&comm);
3119:   MPI_Comm_rank(comm, &rank);
3120:   MPI_Comm_size(comm, &numProcs);

3122:   *dmParallel = NULL;
3123:   if (numProcs == 1) return(0);

3125:   DMPlexGetDimension(dm, &dim);
3126:   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3127:   PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);
3128:   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129:   DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);
3130:   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131:   if (!rank) numRemoteRanks = numProcs;
3132:   else       numRemoteRanks = 0;
3133:   PetscMalloc1(numRemoteRanks, &remoteRanks);
3134:   for (p = 0; p < numRemoteRanks; ++p) {
3135:     remoteRanks[p].rank  = p;
3136:     remoteRanks[p].index = 0;
3137:   }
3138:   PetscSFCreate(comm, &partSF);
3139:   PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);
3140:   PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);
3141:   if (flg) {
3142:     PetscPrintf(comm, "Cell Partition:\n");
3143:     PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);
3144:     ISView(cellPart, NULL);
3145:     if (origCellPart) {
3146:       PetscPrintf(comm, "Original Cell Partition:\n");
3147:       PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);
3148:       ISView(origCellPart, NULL);
3149:     }
3150:     PetscSFView(partSF, NULL);
3151:   }
3152:   /* Close the partition over the mesh */
3153:   DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);
3154:   ISDestroy(&cellPart);
3155:   PetscSectionDestroy(&cellPartSection);
3156:   /* Create new mesh */
3157:   DMPlexCreate(comm, dmParallel);
3158:   DMPlexSetDimension(*dmParallel, dim);
3159:   PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");
3160:   pmesh = (DM_Plex*) (*dmParallel)->data;
3161:   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3162:   PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);
3163:   if (flg) {
3164:     PetscPrintf(comm, "Point Partition:\n");
3165:     PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);
3166:     ISView(part, NULL);
3167:     PetscSFView(pointSF, NULL);
3168:     PetscPrintf(comm, "Point Renumbering after partition:\n");
3169:     ISLocalToGlobalMappingView(renumbering, NULL);
3170:   }
3171:   PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);
3172:   PetscLogEventBegin(DMPLEX_DistributeCones,dm,0,0,0);
3173:   /* Distribute cone section */
3174:   DMPlexGetConeSection(dm, &originalConeSection);
3175:   DMPlexGetConeSection(*dmParallel, &newConeSection);
3176:   PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);
3177:   DMSetUp(*dmParallel);
3178:   {
3179:     PetscInt pStart, pEnd, p;

3181:     PetscSectionGetChart(newConeSection, &pStart, &pEnd);
3182:     for (p = pStart; p < pEnd; ++p) {
3183:       PetscInt coneSize;
3184:       PetscSectionGetDof(newConeSection, p, &coneSize);
3185:       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3186:     }
3187:   }
3188:   /* Communicate and renumber cones */
3189:   PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);
3190:   DMPlexGetCones(dm, &cones);
3191:   DMPlexGetCones(*dmParallel, &newCones);
3192:   PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
3193:   PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
3194:   PetscSectionGetStorageSize(newConeSection, &newConesSize);
3195:   ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);
3196:   PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);
3197:   if (flg) {
3198:     PetscPrintf(comm, "Serial Cone Section:\n");
3199:     PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);
3200:     PetscPrintf(comm, "Parallel Cone Section:\n");
3201:     PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);
3202:     PetscSFView(coneSF, NULL);
3203:   }
3204:   DMPlexGetConeOrientations(dm, &cones);
3205:   DMPlexGetConeOrientations(*dmParallel, &newCones);
3206:   PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
3207:   PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
3208:   PetscSFDestroy(&coneSF);
3209:   PetscLogEventEnd(DMPLEX_DistributeCones,dm,0,0,0);
3210:   /* Create supports and stratify sieve */
3211:   {
3212:     PetscInt pStart, pEnd;

3214:     PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);
3215:     PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);
3216:   }
3217:   DMPlexSymmetrize(*dmParallel);
3218:   DMPlexStratify(*dmParallel);
3219:   /* Distribute Coordinates */
3220:   {
3221:     PetscSection originalCoordSection, newCoordSection;
3222:     Vec          originalCoordinates, newCoordinates;
3223:     const char  *name;

3225:     DMGetCoordinateSection(dm, &originalCoordSection);
3226:     DMGetCoordinateSection(*dmParallel, &newCoordSection);
3227:     DMGetCoordinatesLocal(dm, &originalCoordinates);
3228:     VecCreate(comm, &newCoordinates);
3229:     PetscObjectGetName((PetscObject) originalCoordinates, &name);
3230:     PetscObjectSetName((PetscObject) newCoordinates, name);

3232:     DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);
3233:     DMSetCoordinatesLocal(*dmParallel, newCoordinates);
3234:     VecDestroy(&newCoordinates);
3235:   }
3236:   /* Distribute labels */
3237:   PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);
3238:   {
3239:     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3240:     PetscInt numLabels = 0, l;

3242:     /* Bcast number of labels */
3243:     while (next) {++numLabels; next = next->next;}
3244:     MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);
3245:     next = mesh->labels;
3246:     for (l = 0; l < numLabels; ++l) {
3247:       DMLabel   labelNew;
3248:       PetscBool isdepth;

3250:       /* Skip "depth" because it is recreated */
3251:       if (!rank) {PetscStrcmp(next->name, "depth", &isdepth);}
3252:       MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);
3253:       if (isdepth) {if (!rank) next = next->next; continue;}
3254:       DMLabelDistribute(next, partSection, part, renumbering, &labelNew);
3255:       /* Insert into list */
3256:       if (newNext) newNext->next = labelNew;
3257:       else         pmesh->labels = labelNew;
3258:       newNext = labelNew;
3259:       if (!rank) next = next->next;
3260:     }
3261:   }
3262:   PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);
3263:   /* Setup hybrid structure */
3264:   {
3265:     const PetscInt *gpoints;
3266:     PetscInt        depth, n, d;

3268:     for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];}
3269:     MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);
3270:     ISLocalToGlobalMappingGetSize(renumbering, &n);
3271:     ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);
3272:     DMPlexGetDepth(dm, &depth);
3273:     for (d = 0; d <= dim; ++d) {
3274:       PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p;

3276:       if (pmax < 0) continue;
3277:       DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);
3278:       DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);
3279:       MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);
3280:       for (p = 0; p < n; ++p) {
3281:         const PetscInt point = gpoints[p];

3283:         if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax;
3284:       }
3285:       if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax;
3286:       else            pmesh->hybridPointMax[d] = -1;
3287:     }
3288:     ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);
3289:   }
3290:   /* Cleanup Partition */
3291:   ISLocalToGlobalMappingDestroy(&renumbering);
3292:   PetscSFDestroy(&partSF);
3293:   PetscSectionDestroy(&partSection);
3294:   ISDestroy(&part);
3295:   /* Create point SF for parallel mesh */
3296:   PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);
3297:   {
3298:     const PetscInt *leaves;
3299:     PetscSFNode    *remotePoints, *rowners, *lowners;
3300:     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3301:     PetscInt        pStart, pEnd;

3303:     DMPlexGetChart(*dmParallel, &pStart, &pEnd);
3304:     PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);
3305:     PetscMalloc2(numRoots,&rowners,numLeaves,&lowners);
3306:     for (p=0; p<numRoots; p++) {
3307:       rowners[p].rank  = -1;
3308:       rowners[p].index = -1;
3309:     }
3310:     if (origCellPart) {
3311:       /* Make sure points in the original partition are not assigned to other procs */
3312:       const PetscInt *origPoints;

3314:       DMPlexCreatePartitionClosure(dm, origCellPartSection, origCellPart, &origPartSection, &origPart);
3315:       ISGetIndices(origPart, &origPoints);
3316:       for (p = 0; p < numProcs; ++p) {
3317:         PetscInt dof, off, d;

3319:         PetscSectionGetDof(origPartSection, p, &dof);
3320:         PetscSectionGetOffset(origPartSection, p, &off);
3321:         for (d = off; d < off+dof; ++d) {
3322:           rowners[origPoints[d]].rank = p;
3323:         }
3324:       }
3325:       ISRestoreIndices(origPart, &origPoints);
3326:       ISDestroy(&origPart);
3327:       PetscSectionDestroy(&origPartSection);
3328:     }
3329:     ISDestroy(&origCellPart);
3330:     PetscSectionDestroy(&origCellPartSection);

3332:     PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3333:     PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3334:     for (p = 0; p < numLeaves; ++p) {
3335:       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3336:         lowners[p].rank  = rank;
3337:         lowners[p].index = leaves ? leaves[p] : p;
3338:       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3339:         lowners[p].rank  = -2;
3340:         lowners[p].index = -2;
3341:       }
3342:     }
3343:     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3344:       rowners[p].rank  = -3;
3345:       rowners[p].index = -3;
3346:     }
3347:     PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3348:     PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3349:     PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3350:     PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3351:     for (p = 0; p < numLeaves; ++p) {
3352:       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3353:       if (lowners[p].rank != rank) ++numGhostPoints;
3354:     }
3355:     PetscMalloc1(numGhostPoints,    &ghostPoints);
3356:     PetscMalloc1(numGhostPoints, &remotePoints);
3357:     for (p = 0, gp = 0; p < numLeaves; ++p) {
3358:       if (lowners[p].rank != rank) {
3359:         ghostPoints[gp]        = leaves ? leaves[p] : p;
3360:         remotePoints[gp].rank  = lowners[p].rank;
3361:         remotePoints[gp].index = lowners[p].index;
3362:         ++gp;
3363:       }
3364:     }
3365:     PetscFree2(rowners,lowners);
3366:     PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);
3367:     PetscSFSetFromOptions((*dmParallel)->sf);
3368:   }
3369:   PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);
3370:   /* Cleanup */
3371:   if (sf) {*sf = pointSF;}
3372:   else    {PetscSFDestroy(&pointSF);}
3373:   DMSetFromOptions(*dmParallel);
3374:   PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);
3375:   return(0);
3376: }

3380: /*@C
3381:   DMPlexInvertCell - This flips tetrahedron and hexahedron orientation since Plex stores them internally with outward normals. Other cells are left untouched.

3383:   Input Parameters:
3384: + numCorners - The number of vertices in a cell
3385: - cone - The incoming cone

3387:   Output Parameter:
3388: . cone - The inverted cone (in-place)

3390:   Level: developer

3392: .seealso: DMPlexGenerate()
3393: @*/
3394: PetscErrorCode DMPlexInvertCell(PetscInt dim, PetscInt numCorners, int cone[])
3395: {
3396:   int tmpc;

3399:   if (dim != 3) return(0);
3400:   switch (numCorners) {
3401:   case 4:
3402:     tmpc    = cone[0];
3403:     cone[0] = cone[1];
3404:     cone[1] = tmpc;
3405:     break;
3406:   case 8:
3407:     tmpc    = cone[1];
3408:     cone[1] = cone[3];
3409:     cone[3] = tmpc;
3410:     break;
3411:   default: break;
3412:   }
3413:   return(0);
3414: }

3418: /* This is to fix the tetrahedron orientation from TetGen */
3419: PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt dim, PetscInt numCells, PetscInt numCorners, int cells[])
3420: {
3421:   PetscInt       bound = numCells*numCorners, coff;

3425:   for (coff = 0; coff < bound; coff += numCorners) {
3426:     DMPlexInvertCell(dim, numCorners, &cells[coff]);
3427:   }
3428:   return(0);
3429: }

3431: #if defined(PETSC_HAVE_TRIANGLE)
3432: #include <triangle.h>

3436: PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3437: {
3439:   inputCtx->numberofpoints             = 0;
3440:   inputCtx->numberofpointattributes    = 0;
3441:   inputCtx->pointlist                  = NULL;
3442:   inputCtx->pointattributelist         = NULL;
3443:   inputCtx->pointmarkerlist            = NULL;
3444:   inputCtx->numberofsegments           = 0;
3445:   inputCtx->segmentlist                = NULL;
3446:   inputCtx->segmentmarkerlist          = NULL;
3447:   inputCtx->numberoftriangleattributes = 0;
3448:   inputCtx->trianglelist               = NULL;
3449:   inputCtx->numberofholes              = 0;
3450:   inputCtx->holelist                   = NULL;
3451:   inputCtx->numberofregions            = 0;
3452:   inputCtx->regionlist                 = NULL;
3453:   return(0);
3454: }

3458: PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3459: {
3461:   outputCtx->numberofpoints        = 0;
3462:   outputCtx->pointlist             = NULL;
3463:   outputCtx->pointattributelist    = NULL;
3464:   outputCtx->pointmarkerlist       = NULL;
3465:   outputCtx->numberoftriangles     = 0;
3466:   outputCtx->trianglelist          = NULL;
3467:   outputCtx->triangleattributelist = NULL;
3468:   outputCtx->neighborlist          = NULL;
3469:   outputCtx->segmentlist           = NULL;
3470:   outputCtx->segmentmarkerlist     = NULL;
3471:   outputCtx->numberofedges         = 0;
3472:   outputCtx->edgelist              = NULL;
3473:   outputCtx->edgemarkerlist        = NULL;
3474:   return(0);
3475: }

3479: PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3480: {
3482:   free(outputCtx->pointmarkerlist);
3483:   free(outputCtx->edgelist);
3484:   free(outputCtx->edgemarkerlist);
3485:   free(outputCtx->trianglelist);
3486:   free(outputCtx->neighborlist);
3487:   return(0);
3488: }

3492: PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3493: {
3494:   MPI_Comm             comm;
3495:   PetscInt             dim              = 2;
3496:   const PetscBool      createConvexHull = PETSC_FALSE;
3497:   const PetscBool      constrained      = PETSC_FALSE;
3498:   struct triangulateio in;
3499:   struct triangulateio out;
3500:   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3501:   PetscMPIInt          rank;
3502:   PetscErrorCode       ierr;

3505:   PetscObjectGetComm((PetscObject)boundary,&comm);
3506:   MPI_Comm_rank(comm, &rank);
3507:   InitInput_Triangle(&in);
3508:   InitOutput_Triangle(&out);
3509:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);

3511:   in.numberofpoints = vEnd - vStart;
3512:   if (in.numberofpoints > 0) {
3513:     PetscSection coordSection;
3514:     Vec          coordinates;
3515:     PetscScalar *array;

3517:     PetscMalloc1(in.numberofpoints*dim, &in.pointlist);
3518:     PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);
3519:     DMGetCoordinatesLocal(boundary, &coordinates);
3520:     DMGetCoordinateSection(boundary, &coordSection);
3521:     VecGetArray(coordinates, &array);
3522:     for (v = vStart; v < vEnd; ++v) {
3523:       const PetscInt idx = v - vStart;
3524:       PetscInt       off, d;

3526:       PetscSectionGetOffset(coordSection, v, &off);
3527:       for (d = 0; d < dim; ++d) {
3528:         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3529:       }
3530:       DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3531:     }
3532:     VecRestoreArray(coordinates, &array);
3533:   }
3534:   DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);
3535:   in.numberofsegments = eEnd - eStart;
3536:   if (in.numberofsegments > 0) {
3537:     PetscMalloc1(in.numberofsegments*2, &in.segmentlist);
3538:     PetscMalloc1(in.numberofsegments, &in.segmentmarkerlist);
3539:     for (e = eStart; e < eEnd; ++e) {
3540:       const PetscInt  idx = e - eStart;
3541:       const PetscInt *cone;

3543:       DMPlexGetCone(boundary, e, &cone);

3545:       in.segmentlist[idx*2+0] = cone[0] - vStart;
3546:       in.segmentlist[idx*2+1] = cone[1] - vStart;

3548:       DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);
3549:     }
3550:   }
3551: #if 0 /* Do not currently support holes */
3552:   PetscReal *holeCoords;
3553:   PetscInt   h, d;

3555:   DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3556:   if (in.numberofholes > 0) {
3557:     PetscMalloc1(in.numberofholes*dim, &in.holelist);
3558:     for (h = 0; h < in.numberofholes; ++h) {
3559:       for (d = 0; d < dim; ++d) {
3560:         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3561:       }
3562:     }
3563:   }
3564: #endif
3565:   if (!rank) {
3566:     char args[32];

3568:     /* Take away 'Q' for verbose output */
3569:     PetscStrcpy(args, "pqezQ");
3570:     if (createConvexHull) {
3571:       PetscStrcat(args, "c");
3572:     }
3573:     if (constrained) {
3574:       PetscStrcpy(args, "zepDQ");
3575:     }
3576:     triangulate(args, &in, &out, NULL);
3577:   }
3578:   PetscFree(in.pointlist);
3579:   PetscFree(in.pointmarkerlist);
3580:   PetscFree(in.segmentlist);
3581:   PetscFree(in.segmentmarkerlist);
3582:   PetscFree(in.holelist);

3584:   {
3585:     const PetscInt numCorners  = 3;
3586:     const PetscInt numCells    = out.numberoftriangles;
3587:     const PetscInt numVertices = out.numberofpoints;
3588:     const int     *cells      = out.trianglelist;
3589:     const double  *meshCoords = out.pointlist;

3591:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3592:     /* Set labels */
3593:     for (v = 0; v < numVertices; ++v) {
3594:       if (out.pointmarkerlist[v]) {
3595:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3596:       }
3597:     }
3598:     if (interpolate) {
3599:       for (e = 0; e < out.numberofedges; e++) {
3600:         if (out.edgemarkerlist[e]) {
3601:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3602:           const PetscInt *edges;
3603:           PetscInt        numEdges;

3605:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3606:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3607:           DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3608:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3609:         }
3610:       }
3611:     }
3612:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3613:   }
3614: #if 0 /* Do not currently support holes */
3615:   DMPlexCopyHoles(*dm, boundary);
3616: #endif
3617:   FiniOutput_Triangle(&out);
3618:   return(0);
3619: }

3623: PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3624: {
3625:   MPI_Comm             comm;
3626:   PetscInt             dim  = 2;
3627:   struct triangulateio in;
3628:   struct triangulateio out;
3629:   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3630:   PetscMPIInt          rank;
3631:   PetscErrorCode       ierr;

3634:   PetscObjectGetComm((PetscObject)dm,&comm);
3635:   MPI_Comm_rank(comm, &rank);
3636:   InitInput_Triangle(&in);
3637:   InitOutput_Triangle(&out);
3638:   DMPlexGetDepth(dm, &depth);
3639:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3640:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);

3642:   in.numberofpoints = vEnd - vStart;
3643:   if (in.numberofpoints > 0) {
3644:     PetscSection coordSection;
3645:     Vec          coordinates;
3646:     PetscScalar *array;

3648:     PetscMalloc1(in.numberofpoints*dim, &in.pointlist);
3649:     PetscMalloc1(in.numberofpoints, &in.pointmarkerlist);
3650:     DMGetCoordinatesLocal(dm, &coordinates);
3651:     DMGetCoordinateSection(dm, &coordSection);
3652:     VecGetArray(coordinates, &array);
3653:     for (v = vStart; v < vEnd; ++v) {
3654:       const PetscInt idx = v - vStart;
3655:       PetscInt       off, d;

3657:       PetscSectionGetOffset(coordSection, v, &off);
3658:       for (d = 0; d < dim; ++d) {
3659:         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3660:       }
3661:       DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3662:     }
3663:     VecRestoreArray(coordinates, &array);
3664:   }
3665:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

3667:   in.numberofcorners   = 3;
3668:   in.numberoftriangles = cEnd - cStart;

3670:   in.trianglearealist  = (double*) maxVolumes;
3671:   if (in.numberoftriangles > 0) {
3672:     PetscMalloc1(in.numberoftriangles*in.numberofcorners, &in.trianglelist);
3673:     for (c = cStart; c < cEnd; ++c) {
3674:       const PetscInt idx      = c - cStart;
3675:       PetscInt      *closure = NULL;
3676:       PetscInt       closureSize;

3678:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3679:       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3680:       for (v = 0; v < 3; ++v) {
3681:         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3682:       }
3683:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3684:     }
3685:   }
3686:   /* TODO: Segment markers are missing on input */
3687: #if 0 /* Do not currently support holes */
3688:   PetscReal *holeCoords;
3689:   PetscInt   h, d;

3691:   DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3692:   if (in.numberofholes > 0) {
3693:     PetscMalloc1(in.numberofholes*dim, &in.holelist);
3694:     for (h = 0; h < in.numberofholes; ++h) {
3695:       for (d = 0; d < dim; ++d) {
3696:         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3697:       }
3698:     }
3699:   }
3700: #endif
3701:   if (!rank) {
3702:     char args[32];

3704:     /* Take away 'Q' for verbose output */
3705:     PetscStrcpy(args, "pqezQra");
3706:     triangulate(args, &in, &out, NULL);
3707:   }
3708:   PetscFree(in.pointlist);
3709:   PetscFree(in.pointmarkerlist);
3710:   PetscFree(in.segmentlist);
3711:   PetscFree(in.segmentmarkerlist);
3712:   PetscFree(in.trianglelist);

3714:   {
3715:     const PetscInt numCorners  = 3;
3716:     const PetscInt numCells    = out.numberoftriangles;
3717:     const PetscInt numVertices = out.numberofpoints;
3718:     const int     *cells      = out.trianglelist;
3719:     const double  *meshCoords = out.pointlist;
3720:     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;

3722:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3723:     /* Set labels */
3724:     for (v = 0; v < numVertices; ++v) {
3725:       if (out.pointmarkerlist[v]) {
3726:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3727:       }
3728:     }
3729:     if (interpolate) {
3730:       PetscInt e;

3732:       for (e = 0; e < out.numberofedges; e++) {
3733:         if (out.edgemarkerlist[e]) {
3734:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3735:           const PetscInt *edges;
3736:           PetscInt        numEdges;

3738:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3739:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3740:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3741:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3742:         }
3743:       }
3744:     }
3745:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
3746:   }
3747: #if 0 /* Do not currently support holes */
3748:   DMPlexCopyHoles(*dm, boundary);
3749: #endif
3750:   FiniOutput_Triangle(&out);
3751:   return(0);
3752: }
3753: #endif

3755: #if defined(PETSC_HAVE_TETGEN)
3756: #include <tetgen.h>
3759: PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3760: {
3761:   MPI_Comm       comm;
3762:   const PetscInt dim  = 3;
3763:   ::tetgenio     in;
3764:   ::tetgenio     out;
3765:   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3766:   PetscMPIInt    rank;

3770:   PetscObjectGetComm((PetscObject)boundary,&comm);
3771:   MPI_Comm_rank(comm, &rank);
3772:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
3773:   in.numberofpoints = vEnd - vStart;
3774:   if (in.numberofpoints > 0) {
3775:     PetscSection coordSection;
3776:     Vec          coordinates;
3777:     PetscScalar *array;

3779:     in.pointlist       = new double[in.numberofpoints*dim];
3780:     in.pointmarkerlist = new int[in.numberofpoints];

3782:     DMGetCoordinatesLocal(boundary, &coordinates);
3783:     DMGetCoordinateSection(boundary, &coordSection);
3784:     VecGetArray(coordinates, &array);
3785:     for (v = vStart; v < vEnd; ++v) {
3786:       const PetscInt idx = v - vStart;
3787:       PetscInt       off, d;

3789:       PetscSectionGetOffset(coordSection, v, &off);
3790:       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3791:       DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3792:     }
3793:     VecRestoreArray(coordinates, &array);
3794:   }
3795:   DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);

3797:   in.numberoffacets = fEnd - fStart;
3798:   if (in.numberoffacets > 0) {
3799:     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3800:     in.facetmarkerlist = new int[in.numberoffacets];
3801:     for (f = fStart; f < fEnd; ++f) {
3802:       const PetscInt idx     = f - fStart;
3803:       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;

3805:       in.facetlist[idx].numberofpolygons = 1;
3806:       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3807:       in.facetlist[idx].numberofholes    = 0;
3808:       in.facetlist[idx].holelist         = NULL;

3810:       DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3811:       for (p = 0; p < numPoints*2; p += 2) {
3812:         const PetscInt point = points[p];
3813:         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3814:       }

3816:       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3817:       poly->numberofvertices = numVertices;
3818:       poly->vertexlist       = new int[poly->numberofvertices];
3819:       for (v = 0; v < numVertices; ++v) {
3820:         const PetscInt vIdx = points[v] - vStart;
3821:         poly->vertexlist[v] = vIdx;
3822:       }
3823:       DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);
3824:       DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3825:     }
3826:   }
3827:   if (!rank) {
3828:     char args[32];

3830:     /* Take away 'Q' for verbose output */
3831:     PetscStrcpy(args, "pqezQ");
3832:     ::tetrahedralize(args, &in, &out);
3833:   }
3834:   {
3835:     const PetscInt numCorners  = 4;
3836:     const PetscInt numCells    = out.numberoftetrahedra;
3837:     const PetscInt numVertices = out.numberofpoints;
3838:     const double   *meshCoords = out.pointlist;
3839:     int            *cells      = out.tetrahedronlist;

3841:     DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
3842:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3843:     /* Set labels */
3844:     for (v = 0; v < numVertices; ++v) {
3845:       if (out.pointmarkerlist[v]) {
3846:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3847:       }
3848:     }
3849:     if (interpolate) {
3850:       PetscInt e;

3852:       for (e = 0; e < out.numberofedges; e++) {
3853:         if (out.edgemarkerlist[e]) {
3854:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3855:           const PetscInt *edges;
3856:           PetscInt        numEdges;

3858:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3859:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3860:           DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3861:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3862:         }
3863:       }
3864:       for (f = 0; f < out.numberoftrifaces; f++) {
3865:         if (out.trifacemarkerlist[f]) {
3866:           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3867:           const PetscInt *faces;
3868:           PetscInt        numFaces;

3870:           DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);
3871:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3872:           DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);
3873:           DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
3874:         }
3875:       }
3876:     }
3877:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3878:   }
3879:   return(0);
3880: }

3884: PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3885: {
3886:   MPI_Comm       comm;
3887:   const PetscInt dim  = 3;
3888:   ::tetgenio     in;
3889:   ::tetgenio     out;
3890:   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3891:   PetscMPIInt    rank;

3895:   PetscObjectGetComm((PetscObject)dm,&comm);
3896:   MPI_Comm_rank(comm, &rank);
3897:   DMPlexGetDepth(dm, &depth);
3898:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3899:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);

3901:   in.numberofpoints = vEnd - vStart;
3902:   if (in.numberofpoints > 0) {
3903:     PetscSection coordSection;
3904:     Vec          coordinates;
3905:     PetscScalar *array;

3907:     in.pointlist       = new double[in.numberofpoints*dim];
3908:     in.pointmarkerlist = new int[in.numberofpoints];

3910:     DMGetCoordinatesLocal(dm, &coordinates);
3911:     DMGetCoordinateSection(dm, &coordSection);
3912:     VecGetArray(coordinates, &array);
3913:     for (v = vStart; v < vEnd; ++v) {
3914:       const PetscInt idx = v - vStart;
3915:       PetscInt       off, d;

3917:       PetscSectionGetOffset(coordSection, v, &off);
3918:       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3919:       DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3920:     }
3921:     VecRestoreArray(coordinates, &array);
3922:   }
3923:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

3925:   in.numberofcorners       = 4;
3926:   in.numberoftetrahedra    = cEnd - cStart;
3927:   in.tetrahedronvolumelist = (double*) maxVolumes;
3928:   if (in.numberoftetrahedra > 0) {
3929:     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3930:     for (c = cStart; c < cEnd; ++c) {
3931:       const PetscInt idx      = c - cStart;
3932:       PetscInt      *closure = NULL;
3933:       PetscInt       closureSize;

3935:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3936:       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3937:       for (v = 0; v < 4; ++v) {
3938:         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3939:       }
3940:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3941:     }
3942:   }
3943:   /* TODO: Put in boundary faces with markers */
3944:   if (!rank) {
3945:     char args[32];

3947:     /* Take away 'Q' for verbose output */
3948:     /*PetscStrcpy(args, "qezQra"); */
3949:     PetscStrcpy(args, "qezraVVVV");
3950:     ::tetrahedralize(args, &in, &out);
3951:   }
3952:   in.tetrahedronvolumelist = NULL;

3954:   {
3955:     const PetscInt numCorners  = 4;
3956:     const PetscInt numCells    = out.numberoftetrahedra;
3957:     const PetscInt numVertices = out.numberofpoints;
3958:     const double   *meshCoords = out.pointlist;
3959:     int            *cells      = out.tetrahedronlist;

3961:     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;

3963:     DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
3964:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3965:     /* Set labels */
3966:     for (v = 0; v < numVertices; ++v) {
3967:       if (out.pointmarkerlist[v]) {
3968:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3969:       }
3970:     }
3971:     if (interpolate) {
3972:       PetscInt e, f;

3974:       for (e = 0; e < out.numberofedges; e++) {
3975:         if (out.edgemarkerlist[e]) {
3976:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3977:           const PetscInt *edges;
3978:           PetscInt        numEdges;

3980:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3981:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3982:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3983:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3984:         }
3985:       }
3986:       for (f = 0; f < out.numberoftrifaces; f++) {
3987:         if (out.trifacemarkerlist[f]) {
3988:           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3989:           const PetscInt *faces;
3990:           PetscInt        numFaces;

3992:           DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3993:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3994:           DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);
3995:           DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3996:         }
3997:       }
3998:     }
3999:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
4000:   }
4001:   return(0);
4002: }
4003: #endif

4005: #if defined(PETSC_HAVE_CTETGEN)
4006: #include <ctetgen.h>

4010: PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4011: {
4012:   MPI_Comm       comm;
4013:   const PetscInt dim  = 3;
4014:   PLC           *in, *out;
4015:   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4016:   PetscMPIInt    rank;

4020:   PetscObjectGetComm((PetscObject)boundary,&comm);
4021:   PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);
4022:   MPI_Comm_rank(comm, &rank);
4023:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
4024:   PLCCreate(&in);
4025:   PLCCreate(&out);

4027:   in->numberofpoints = vEnd - vStart;
4028:   if (in->numberofpoints > 0) {
4029:     PetscSection coordSection;
4030:     Vec          coordinates;
4031:     PetscScalar *array;

4033:     PetscMalloc1(in->numberofpoints*dim, &in->pointlist);
4034:     PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);
4035:     DMGetCoordinatesLocal(boundary, &coordinates);
4036:     DMGetCoordinateSection(boundary, &coordSection);
4037:     VecGetArray(coordinates, &array);
4038:     for (v = vStart; v < vEnd; ++v) {
4039:       const PetscInt idx = v - vStart;
4040:       PetscInt       off, d, m;

4042:       PetscSectionGetOffset(coordSection, v, &off);
4043:       for (d = 0; d < dim; ++d) {
4044:         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4045:       }
4046:       DMPlexGetLabelValue(boundary, "marker", v, &m);

4048:       in->pointmarkerlist[idx] = (int) m;
4049:     }
4050:     VecRestoreArray(coordinates, &array);
4051:   }
4052:   DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);

4054:   in->numberoffacets = fEnd - fStart;
4055:   if (in->numberoffacets > 0) {
4056:     PetscMalloc1(in->numberoffacets, &in->facetlist);
4057:     PetscMalloc1(in->numberoffacets,   &in->facetmarkerlist);
4058:     for (f = fStart; f < fEnd; ++f) {
4059:       const PetscInt idx     = f - fStart;
4060:       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
4061:       polygon       *poly;

4063:       in->facetlist[idx].numberofpolygons = 1;

4065:       PetscMalloc1(in->facetlist[idx].numberofpolygons, &in->facetlist[idx].polygonlist);

4067:       in->facetlist[idx].numberofholes    = 0;
4068:       in->facetlist[idx].holelist         = NULL;

4070:       DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
4071:       for (p = 0; p < numPoints*2; p += 2) {
4072:         const PetscInt point = points[p];
4073:         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
4074:       }

4076:       poly                   = in->facetlist[idx].polygonlist;
4077:       poly->numberofvertices = numVertices;
4078:       PetscMalloc1(poly->numberofvertices, &poly->vertexlist);
4079:       for (v = 0; v < numVertices; ++v) {
4080:         const PetscInt vIdx = points[v] - vStart;
4081:         poly->vertexlist[v] = vIdx;
4082:       }
4083:       DMPlexGetLabelValue(boundary, "marker", f, &m);
4084:       in->facetmarkerlist[idx] = (int) m;
4085:       DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
4086:     }
4087:   }
4088:   if (!rank) {
4089:     TetGenOpts t;

4091:     TetGenOptsInitialize(&t);
4092:     t.in        = boundary; /* Should go away */
4093:     t.plc       = 1;
4094:     t.quality   = 1;
4095:     t.edgesout  = 1;
4096:     t.zeroindex = 1;
4097:     t.quiet     = 1;
4098:     t.verbose   = verbose;
4099:     TetGenCheckOpts(&t);
4100:     TetGenTetrahedralize(&t, in, out);
4101:   }
4102:   {
4103:     const PetscInt numCorners  = 4;
4104:     const PetscInt numCells    = out->numberoftetrahedra;
4105:     const PetscInt numVertices = out->numberofpoints;
4106:     const double   *meshCoords = out->pointlist;
4107:     int            *cells      = out->tetrahedronlist;

4109:     DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
4110:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
4111:     /* Set labels */
4112:     for (v = 0; v < numVertices; ++v) {
4113:       if (out->pointmarkerlist[v]) {
4114:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);
4115:       }
4116:     }
4117:     if (interpolate) {
4118:       PetscInt e;

4120:       for (e = 0; e < out->numberofedges; e++) {
4121:         if (out->edgemarkerlist[e]) {
4122:           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4123:           const PetscInt *edges;
4124:           PetscInt        numEdges;

4126:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
4127:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4128:           DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);
4129:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
4130:         }
4131:       }
4132:       for (f = 0; f < out->numberoftrifaces; f++) {
4133:         if (out->trifacemarkerlist[f]) {
4134:           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4135:           const PetscInt *faces;
4136:           PetscInt        numFaces;

4138:           DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);
4139:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4140:           DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);
4141:           DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
4142:         }
4143:       }
4144:     }
4145:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
4146:   }

4148:   PLCDestroy(&in);
4149:   PLCDestroy(&out);
4150:   return(0);
4151: }

4155: PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
4156: {
4157:   MPI_Comm       comm;
4158:   const PetscInt dim  = 3;
4159:   PLC           *in, *out;
4160:   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4161:   PetscMPIInt    rank;

4165:   PetscObjectGetComm((PetscObject)dm,&comm);
4166:   PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);
4167:   MPI_Comm_rank(comm, &rank);
4168:   DMPlexGetDepth(dm, &depth);
4169:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
4170:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
4171:   PLCCreate(&in);
4172:   PLCCreate(&out);

4174:   in->numberofpoints = vEnd - vStart;
4175:   if (in->numberofpoints > 0) {
4176:     PetscSection coordSection;
4177:     Vec          coordinates;
4178:     PetscScalar *array;

4180:     PetscMalloc1(in->numberofpoints*dim, &in->pointlist);
4181:     PetscMalloc1(in->numberofpoints,       &in->pointmarkerlist);
4182:     DMGetCoordinatesLocal(dm, &coordinates);
4183:     DMGetCoordinateSection(dm, &coordSection);
4184:     VecGetArray(coordinates, &array);
4185:     for (v = vStart; v < vEnd; ++v) {
4186:       const PetscInt idx = v - vStart;
4187:       PetscInt       off, d, m;

4189:       PetscSectionGetOffset(coordSection, v, &off);
4190:       for (d = 0; d < dim; ++d) {
4191:         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4192:       }
4193:       DMPlexGetLabelValue(dm, "marker", v, &m);

4195:       in->pointmarkerlist[idx] = (int) m;
4196:     }
4197:     VecRestoreArray(coordinates, &array);
4198:   }
4199:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

4201:   in->numberofcorners       = 4;
4202:   in->numberoftetrahedra    = cEnd - cStart;
4203:   in->tetrahedronvolumelist = maxVolumes;
4204:   if (in->numberoftetrahedra > 0) {
4205:     PetscMalloc1(in->numberoftetrahedra*in->numberofcorners, &in->tetrahedronlist);
4206:     for (c = cStart; c < cEnd; ++c) {
4207:       const PetscInt idx      = c - cStart;
4208:       PetscInt      *closure = NULL;
4209:       PetscInt       closureSize;

4211:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
4212:       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4213:       for (v = 0; v < 4; ++v) {
4214:         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4215:       }
4216:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
4217:     }
4218:   }
4219:   if (!rank) {
4220:     TetGenOpts t;

4222:     TetGenOptsInitialize(&t);

4224:     t.in        = dm; /* Should go away */
4225:     t.refine    = 1;
4226:     t.varvolume = 1;
4227:     t.quality   = 1;
4228:     t.edgesout  = 1;
4229:     t.zeroindex = 1;
4230:     t.quiet     = 1;
4231:     t.verbose   = verbose; /* Change this */

4233:     TetGenCheckOpts(&t);
4234:     TetGenTetrahedralize(&t, in, out);
4235:   }
4236:   {
4237:     const PetscInt numCorners  = 4;
4238:     const PetscInt numCells    = out->numberoftetrahedra;
4239:     const PetscInt numVertices = out->numberofpoints;
4240:     const double   *meshCoords = out->pointlist;
4241:     int            *cells      = out->tetrahedronlist;
4242:     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;

4244:     DMPlexInvertCells_Internal(dim, numCells, numCorners, cells);
4245:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
4246:     /* Set labels */
4247:     for (v = 0; v < numVertices; ++v) {
4248:       if (out->pointmarkerlist[v]) {
4249:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);
4250:       }
4251:     }
4252:     if (interpolate) {
4253:       PetscInt e, f;

4255:       for (e = 0; e < out->numberofedges; e++) {
4256:         if (out->edgemarkerlist[e]) {
4257:           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
4258:           const PetscInt *edges;
4259:           PetscInt        numEdges;

4261:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
4262:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4263:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);
4264:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
4265:         }
4266:       }
4267:       for (f = 0; f < out->numberoftrifaces; f++) {
4268:         if (out->trifacemarkerlist[f]) {
4269:           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
4270:           const PetscInt *faces;
4271:           PetscInt        numFaces;

4273:           DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);
4274:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4275:           DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);
4276:           DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
4277:         }
4278:       }
4279:     }
4280:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
4281:   }
4282:   PLCDestroy(&in);
4283:   PLCDestroy(&out);
4284:   return(0);
4285: }
4286: #endif

4290: /*@C
4291:   DMPlexGenerate - Generates a mesh.

4293:   Not Collective

4295:   Input Parameters:
4296: + boundary - The DMPlex boundary object
4297: . name - The mesh generation package name
4298: - interpolate - Flag to create intermediate mesh elements

4300:   Output Parameter:
4301: . mesh - The DMPlex object

4303:   Level: intermediate

4305: .keywords: mesh, elements
4306: .seealso: DMPlexCreate(), DMRefine()
4307: @*/
4308: PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
4309: {
4310:   PetscInt       dim;
4311:   char           genname[1024];
4312:   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;

4318:   DMPlexGetDimension(boundary, &dim);
4319:   PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);
4320:   if (flg) name = genname;
4321:   if (name) {
4322:     PetscStrcmp(name, "triangle", &isTriangle);
4323:     PetscStrcmp(name, "tetgen",   &isTetgen);
4324:     PetscStrcmp(name, "ctetgen",  &isCTetgen);
4325:   }
4326:   switch (dim) {
4327:   case 1:
4328:     if (!name || isTriangle) {
4329: #if defined(PETSC_HAVE_TRIANGLE)
4330:       DMPlexGenerate_Triangle(boundary, interpolate, mesh);
4331: #else
4332:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4333: #endif
4334:     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4335:     break;
4336:   case 2:
4337:     if (!name || isCTetgen) {
4338: #if defined(PETSC_HAVE_CTETGEN)
4339:       DMPlexGenerate_CTetgen(boundary, interpolate, mesh);
4340: #else
4341:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4342: #endif
4343:     } else if (isTetgen) {
4344: #if defined(PETSC_HAVE_TETGEN)
4345:       DMPlexGenerate_Tetgen(boundary, interpolate, mesh);
4346: #else
4347:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4348: #endif
4349:     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4350:     break;
4351:   default:
4352:     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4353:   }
4354:   return(0);
4355: }

4359: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
4360: {
4361:   PetscReal      refinementLimit;
4362:   PetscInt       dim, cStart, cEnd;
4363:   char           genname[1024], *name = NULL;
4364:   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;

4368:   DMPlexGetRefinementUniform(dm, &isUniform);
4369:   if (isUniform) {
4370:     CellRefiner cellRefiner;

4372:     DMPlexGetCellRefiner_Internal(dm, &cellRefiner);
4373:     DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);
4374:     return(0);
4375:   }
4376:   DMPlexGetRefinementLimit(dm, &refinementLimit);
4377:   if (refinementLimit == 0.0) return(0);
4378:   DMPlexGetDimension(dm, &dim);
4379:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4380:   PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);
4381:   if (flg) name = genname;
4382:   if (name) {
4383:     PetscStrcmp(name, "triangle", &isTriangle);
4384:     PetscStrcmp(name, "tetgen",   &isTetgen);
4385:     PetscStrcmp(name, "ctetgen",  &isCTetgen);
4386:   }
4387:   switch (dim) {
4388:   case 2:
4389:     if (!name || isTriangle) {
4390: #if defined(PETSC_HAVE_TRIANGLE)
4391:       double  *maxVolumes;
4392:       PetscInt c;

4394:       PetscMalloc1((cEnd - cStart), &maxVolumes);
4395:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4396:       DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);
4397:       PetscFree(maxVolumes);
4398: #else
4399:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
4400: #endif
4401:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4402:     break;
4403:   case 3:
4404:     if (!name || isCTetgen) {
4405: #if defined(PETSC_HAVE_CTETGEN)
4406:       PetscReal *maxVolumes;
4407:       PetscInt   c;

4409:       PetscMalloc1((cEnd - cStart), &maxVolumes);
4410:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4411:       DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);
4412: #else
4413:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4414: #endif
4415:     } else if (isTetgen) {
4416: #if defined(PETSC_HAVE_TETGEN)
4417:       double  *maxVolumes;
4418:       PetscInt c;

4420:       PetscMalloc1((cEnd - cStart), &maxVolumes);
4421:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
4422:       DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);
4423: #else
4424:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4425: #endif
4426:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4427:     break;
4428:   default:
4429:     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
4430:   }
4431:   return(0);
4432: }

4436: /*@
4437:   DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point

4439:   Not Collective

4441:   Input Parameter:
4442: . dm    - The DMPlex object

4444:   Output Parameter:
4445: . depthLabel - The DMLabel recording point depth

4447:   Level: developer

4449: .keywords: mesh, points
4450: .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4451: @*/
4452: PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel)
4453: {
4454:   DM_Plex       *mesh = (DM_Plex*) dm->data;

4460:   if (!mesh->depthLabel) {DMPlexGetLabel(dm, "depth", &mesh->depthLabel);}
4461:   *depthLabel = mesh->depthLabel;
4462:   return(0);
4463: }

4467: /*@
4468:   DMPlexGetDepth - Get the depth of the DAG representing this mesh

4470:   Not Collective

4472:   Input Parameter:
4473: . dm    - The DMPlex object

4475:   Output Parameter:
4476: . depth - The number of strata (breadth first levels) in the DAG

4478:   Level: developer

4480: .keywords: mesh, points
4481: .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
4482: @*/
4483: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
4484: {
4485:   DMLabel        label;
4486:   PetscInt       d = 0;

4492:   DMPlexGetDepthLabel(dm, &label);
4493:   if (label) {DMLabelGetNumValues(label, &d);}
4494:   *depth = d-1;
4495:   return(0);
4496: }

4500: /*@
4501:   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.

4503:   Not Collective

4505:   Input Parameters:
4506: + dm           - The DMPlex object
4507: - stratumValue - The requested depth

4509:   Output Parameters:
4510: + start - The first point at this depth
4511: - end   - One beyond the last point at this depth

4513:   Level: developer

4515: .keywords: mesh, points
4516: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
4517: @*/
4518: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4519: {
4520:   DMLabel        label;
4521:   PetscInt       pStart, pEnd;

4528:   DMPlexGetChart(dm, &pStart, &pEnd);
4529:   if (pStart == pEnd) return(0);
4530:   if (stratumValue < 0) {
4531:     if (start) *start = pStart;
4532:     if (end)   *end   = pEnd;
4533:     return(0);
4534:   }
4535:   DMPlexGetDepthLabel(dm, &label);
4536:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4537:   DMLabelGetStratumBounds(label, stratumValue, start, end);
4538:   return(0);
4539: }

4543: /*@
4544:   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.

4546:   Not Collective

4548:   Input Parameters:
4549: + dm           - The DMPlex object
4550: - stratumValue - The requested height

4552:   Output Parameters:
4553: + start - The first point at this height
4554: - end   - One beyond the last point at this height

4556:   Level: developer

4558: .keywords: mesh, points
4559: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
4560: @*/
4561: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
4562: {
4563:   DMLabel        label;
4564:   PetscInt       depth, pStart, pEnd;

4571:   DMPlexGetChart(dm, &pStart, &pEnd);
4572:   if (pStart == pEnd) return(0);
4573:   if (stratumValue < 0) {
4574:     if (start) *start = pStart;
4575:     if (end)   *end   = pEnd;
4576:     return(0);
4577:   }
4578:   DMPlexGetDepthLabel(dm, &label);
4579:   if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
4580:   DMLabelGetNumValues(label, &depth);
4581:   DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);
4582:   return(0);
4583: }

4587: /* Set the number of dof on each point and separate by fields */
4588: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
4589: {
4590:   PetscInt      *numDofTot;
4591:   PetscInt       depth, pStart = 0, pEnd = 0;
4592:   PetscInt       p, d, dep, f;

4596:   PetscMalloc1((dim+1), &numDofTot);
4597:   for (d = 0; d <= dim; ++d) {
4598:     numDofTot[d] = 0;
4599:     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
4600:   }
4601:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
4602:   if (numFields > 0) {
4603:     PetscSectionSetNumFields(*section, numFields);
4604:     if (numComp) {
4605:       for (f = 0; f < numFields; ++f) {
4606:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
4607:       }
4608:     }
4609:   }
4610:   DMPlexGetChart(dm, &pStart, &pEnd);
4611:   PetscSectionSetChart(*section, pStart, pEnd);
4612:   DMPlexGetDepth(dm, &depth);
4613:   for (dep = 0; dep <= depth; ++dep) {
4614:     d    = dim == depth ? dep : (!dep ? 0 : dim);
4615:     DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);
4616:     for (p = pStart; p < pEnd; ++p) {
4617:       for (f = 0; f < numFields; ++f) {
4618:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
4619:       }
4620:       PetscSectionSetDof(*section, p, numDofTot[d]);
4621:     }
4622:   }
4623:   PetscFree(numDofTot);
4624:   return(0);
4625: }

4629: /* Set the number of dof on each point and separate by fields
4630:    If constDof is PETSC_DETERMINE, constrain every dof on the point
4631: */
4632: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
4633: {
4634:   PetscInt       numFields;
4635:   PetscInt       bc;

4639:   PetscSectionGetNumFields(section, &numFields);
4640:   for (bc = 0; bc < numBC; ++bc) {
4641:     PetscInt        field = 0;
4642:     const PetscInt *idx;
4643:     PetscInt        n, i;

4645:     if (numFields) field = bcField[bc];
4646:     ISGetLocalSize(bcPoints[bc], &n);
4647:     ISGetIndices(bcPoints[bc], &idx);
4648:     for (i = 0; i < n; ++i) {
4649:       const PetscInt p        = idx[i];
4650:       PetscInt       numConst = constDof;

4652:       /* Constrain every dof on the point */
4653:       if (numConst < 0) {
4654:         if (numFields) {
4655:           PetscSectionGetFieldDof(section, p, field, &numConst);
4656:         } else {
4657:           PetscSectionGetDof(section, p, &numConst);
4658:         }
4659:       }
4660:       if (numFields) {
4661:         PetscSectionAddFieldConstraintDof(section, p, field, numConst);
4662:       }
4663:       PetscSectionAddConstraintDof(section, p, numConst);
4664:     }
4665:     ISRestoreIndices(bcPoints[bc], &idx);
4666:   }
4667:   return(0);
4668: }

4672: /* Set the constrained indices on each point and separate by fields */
4673: PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
4674: {
4675:   PetscInt      *maxConstraints;
4676:   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;

4680:   PetscSectionGetNumFields(section, &numFields);
4681:   PetscSectionGetChart(section, &pStart, &pEnd);
4682:   PetscMalloc1((numFields+1), &maxConstraints);
4683:   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
4684:   for (p = pStart; p < pEnd; ++p) {
4685:     PetscInt cdof;

4687:     if (numFields) {
4688:       for (f = 0; f < numFields; ++f) {
4689:         PetscSectionGetFieldConstraintDof(section, p, f, &cdof);
4690:         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
4691:       }
4692:     } else {
4693:       PetscSectionGetConstraintDof(section, p, &cdof);
4694:       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
4695:     }
4696:   }
4697:   for (f = 0; f < numFields; ++f) {
4698:     maxConstraints[numFields] += maxConstraints[f];
4699:   }
4700:   if (maxConstraints[numFields]) {
4701:     PetscInt *indices;

4703:     PetscMalloc1(maxConstraints[numFields], &indices);
4704:     for (p = pStart; p < pEnd; ++p) {
4705:       PetscInt cdof, d;

4707:       PetscSectionGetConstraintDof(section, p, &cdof);
4708:       if (cdof) {
4709:         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
4710:         if (numFields) {
4711:           PetscInt numConst = 0, foff = 0;

4713:           for (f = 0; f < numFields; ++f) {
4714:             PetscInt cfdof, fdof;

4716:             PetscSectionGetFieldDof(section, p, f, &fdof);
4717:             PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);
4718:             /* Change constraint numbering from absolute local dof number to field relative local dof number */
4719:             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
4720:             PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);
4721:             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
4722:             numConst += cfdof;
4723:             foff     += fdof;
4724:           }
4725:           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4726:         } else {
4727:           for (d = 0; d < cdof; ++d) indices[d] = d;
4728:         }
4729:         PetscSectionSetConstraintIndices(section, p, indices);
4730:       }
4731:     }
4732:     PetscFree(indices);
4733:   }
4734:   PetscFree(maxConstraints);
4735:   return(0);
4736: }

4740: /* Set the constrained field indices on each point */
4741: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
4742: {
4743:   const PetscInt *points, *indices;
4744:   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
4745:   PetscErrorCode  ierr;

4748:   PetscSectionGetNumFields(section, &numFields);
4749:   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);

4751:   ISGetLocalSize(bcPoints, &numPoints);
4752:   ISGetIndices(bcPoints, &points);
4753:   if (!constraintIndices) {
4754:     PetscInt *idx, i;

4756:     PetscSectionGetMaxDof(section, &maxDof);
4757:     PetscMalloc1(maxDof, &idx);
4758:     for (i = 0; i < maxDof; ++i) idx[i] = i;
4759:     for (p = 0; p < numPoints; ++p) {
4760:       PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);
4761:     }
4762:     PetscFree(idx);
4763:   } else {
4764:     ISGetLocalSize(constraintIndices, &numConstraints);
4765:     ISGetIndices(constraintIndices, &indices);
4766:     for (p = 0; p < numPoints; ++p) {
4767:       PetscInt fcdof;

4769:       PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);
4770:       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);
4771:       PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);
4772:     }
4773:     ISRestoreIndices(constraintIndices, &indices);
4774:   }
4775:   ISRestoreIndices(bcPoints, &points);
4776:   return(0);
4777: }

4781: /* Set the constrained indices on each point and separate by fields */
4782: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
4783: {
4784:   PetscInt      *indices;
4785:   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;

4789:   PetscSectionGetMaxDof(section, &maxDof);
4790:   PetscMalloc1(maxDof, &indices);
4791:   PetscSectionGetNumFields(section, &numFields);
4792:   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
4793:   PetscSectionGetChart(section, &pStart, &pEnd);
4794:   for (p = pStart; p < pEnd; ++p) {
4795:     PetscInt cdof, d;

4797:     PetscSectionGetConstraintDof(section, p, &cdof);
4798:     if (cdof) {
4799:       PetscInt numConst = 0, foff = 0;

4801:       for (f = 0; f < numFields; ++f) {
4802:         const PetscInt *fcind;
4803:         PetscInt        fdof, fcdof;

4805:         PetscSectionGetFieldDof(section, p, f, &fdof);
4806:         PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
4807:         if (fcdof) {PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);}
4808:         /* Change constraint numbering from field relative local dof number to absolute local dof number */
4809:         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
4810:         foff     += fdof;
4811:         numConst += fcdof;
4812:       }
4813:       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
4814:       PetscSectionSetConstraintIndices(section, p, indices);
4815:     }
4816:   }
4817:   PetscFree(indices);
4818:   return(0);
4819: }

4823: /*@C
4824:   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.

4826:   Not Collective

4828:   Input Parameters:
4829: + dm        - The DMPlex object
4830: . dim       - The spatial dimension of the problem
4831: . numFields - The number of fields in the problem
4832: . numComp   - An array of size numFields that holds the number of components for each field
4833: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
4834: . numBC     - The number of boundary conditions
4835: . bcField   - An array of size numBC giving the field number for each boundry condition
4836: - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies

4838:   Output Parameter:
4839: . section - The PetscSection object

4841:   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
4842:   nubmer of dof for field 0 on each edge.

4844:   Level: developer

4846:   Fortran Notes:
4847:   A Fortran 90 version is available as DMPlexCreateSectionF90()

4849: .keywords: mesh, elements
4850: .seealso: DMPlexCreate(), PetscSectionCreate()
4851: @*/
4852: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
4853: {

4857:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
4858:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);
4859:   PetscSectionSetUp(*section);
4860:   if (numBC) {DMPlexCreateSectionBCIndicesAll(dm, *section);}
4861:   PetscSectionViewFromOptions(*section,NULL,"-section_view");
4862:   return(0);
4863: }

4867: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
4868: {
4869:   PetscSection   section;

4873:   DMClone(dm, cdm);
4874:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
4875:   DMSetDefaultSection(*cdm, section);
4876:   PetscSectionDestroy(&section);
4877:   return(0);
4878: }

4882: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
4883: {
4884:   DM_Plex *mesh = (DM_Plex*) dm->data;

4888:   if (section) *section = mesh->coneSection;
4889:   return(0);
4890: }

4894: PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section)
4895: {
4896:   DM_Plex *mesh = (DM_Plex*) dm->data;

4900:   if (section) *section = mesh->supportSection;
4901:   return(0);
4902: }

4906: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
4907: {
4908:   DM_Plex *mesh = (DM_Plex*) dm->data;

4912:   if (cones) *cones = mesh->cones;
4913:   return(0);
4914: }

4918: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
4919: {
4920:   DM_Plex *mesh = (DM_Plex*) dm->data;

4924:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
4925:   return(0);
4926: }

4928: /******************************** FEM Support **********************************/

4932: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
4933: {
4934:   PetscScalar    *array, *vArray;
4935:   const PetscInt *cone, *coneO;
4936:   PetscInt        pStart, pEnd, p, numPoints, size = 0, offset = 0;
4937:   PetscErrorCode  ierr;

4940:   PetscSectionGetChart(section, &pStart, &pEnd);
4941:   DMPlexGetConeSize(dm, point, &numPoints);
4942:   DMPlexGetCone(dm, point, &cone);
4943:   DMPlexGetConeOrientation(dm, point, &coneO);
4944:   if (!values || !*values) {
4945:     if ((point >= pStart) && (point < pEnd)) {
4946:       PetscInt dof;

4948:       PetscSectionGetDof(section, point, &dof);
4949:       size += dof;
4950:     }
4951:     for (p = 0; p < numPoints; ++p) {
4952:       const PetscInt cp = cone[p];
4953:       PetscInt       dof;

4955:       if ((cp < pStart) || (cp >= pEnd)) continue;
4956:       PetscSectionGetDof(section, cp, &dof);
4957:       size += dof;
4958:     }
4959:     if (!values) {
4960:       if (csize) *csize = size;
4961:       return(0);
4962:     }
4963:     DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
4964:   } else {
4965:     array = *values;
4966:   }
4967:   size = 0;
4968:   VecGetArray(v, &vArray);
4969:   if ((point >= pStart) && (point < pEnd)) {
4970:     PetscInt     dof, off, d;
4971:     PetscScalar *varr;

4973:     PetscSectionGetDof(section, point, &dof);
4974:     PetscSectionGetOffset(section, point, &off);
4975:     varr = &vArray[off];
4976:     for (d = 0; d < dof; ++d, ++offset) {
4977:       array[offset] = varr[d];
4978:     }
4979:     size += dof;
4980:   }
4981:   for (p = 0; p < numPoints; ++p) {
4982:     const PetscInt cp = cone[p];
4983:     PetscInt       o  = coneO[p];
4984:     PetscInt       dof, off, d;
4985:     PetscScalar   *varr;

4987:     if ((cp < pStart) || (cp >= pEnd)) continue;
4988:     PetscSectionGetDof(section, cp, &dof);
4989:     PetscSectionGetOffset(section, cp, &off);
4990:     varr = &vArray[off];
4991:     if (o >= 0) {
4992:       for (d = 0; d < dof; ++d, ++offset) {
4993:         array[offset] = varr[d];
4994:       }
4995:     } else {
4996:       for (d = dof-1; d >= 0; --d, ++offset) {
4997:         array[offset] = varr[d];
4998:       }
4999:     }
5000:     size += dof;
5001:   }
5002:   VecRestoreArray(v, &vArray);
5003:   if (!*values) {
5004:     if (csize) *csize = size;
5005:     *values = array;
5006:   } else {
5007:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5008:     *csize = size;
5009:   }
5010:   return(0);
5011: }

5015: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5016: {
5017:   PetscInt       offset = 0, p;

5021:   *size = 0;
5022:   for (p = 0; p < numPoints*2; p += 2) {
5023:     const PetscInt point = points[p];
5024:     const PetscInt o     = points[p+1];
5025:     PetscInt       dof, off, d;
5026:     const PetscScalar *varr;

5028:     PetscSectionGetDof(section, point, &dof);
5029:     PetscSectionGetOffset(section, point, &off);
5030:     varr = &vArray[off];
5031:     if (o >= 0) {
5032:       for (d = 0; d < dof; ++d, ++offset)    array[offset] = varr[d];
5033:     } else {
5034:       for (d = dof-1; d >= 0; --d, ++offset) array[offset] = varr[d];
5035:     }
5036:   }
5037:   *size = offset;
5038:   return(0);
5039: }

5043: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscScalar vArray[], PetscInt *size, PetscScalar array[])
5044: {
5045:   PetscInt       offset = 0, f;

5049:   *size = 0;
5050:   for (f = 0; f < numFields; ++f) {
5051:     PetscInt fcomp, p;

5053:     PetscSectionGetFieldComponents(section, f, &fcomp);
5054:     for (p = 0; p < numPoints*2; p += 2) {
5055:       const PetscInt point = points[p];
5056:       const PetscInt o     = points[p+1];
5057:       PetscInt       fdof, foff, d, c;
5058:       const PetscScalar *varr;

5060:       PetscSectionGetFieldDof(section, point, f, &fdof);
5061:       PetscSectionGetFieldOffset(section, point, f, &foff);
5062:       varr = &vArray[foff];
5063:       if (o >= 0) {
5064:         for (d = 0; d < fdof; ++d, ++offset) array[offset] = varr[d];
5065:       } else {
5066:         for (d = fdof/fcomp-1; d >= 0; --d) {
5067:           for (c = 0; c < fcomp; ++c, ++offset) {
5068:             array[offset] = varr[d*fcomp+c];
5069:           }
5070:         }
5071:       }
5072:     }
5073:   }
5074:   *size = offset;
5075:   return(0);
5076: }

5080: /*@C
5081:   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'

5083:   Not collective

5085:   Input Parameters:
5086: + dm - The DM
5087: . section - The section describing the layout in v, or NULL to use the default section
5088: . v - The local vector
5089: - point - The sieve point in the DM

5091:   Output Parameters:
5092: + csize - The number of values in the closure, or NULL
5093: - values - The array of values, which is a borrowed array and should not be freed

5095:   Fortran Notes:
5096:   Since it returns an array, this routine is only available in Fortran 90, and you must
5097:   include petsc.h90 in your code.

5099:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

5101:   Level: intermediate

5103: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5104: @*/
5105: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5106: {
5107:   PetscSection    clSection;
5108:   IS              clPoints;
5109:   PetscScalar    *array, *vArray;
5110:   PetscInt       *points = NULL;
5111:   const PetscInt *clp;
5112:   PetscInt        depth, numFields, numPoints, size;
5113:   PetscErrorCode  ierr;

5117:   if (!section) {DMGetDefaultSection(dm, &section);}
5120:   DMPlexGetDepth(dm, &depth);
5121:   PetscSectionGetNumFields(section, &numFields);
5122:   if (depth == 1 && numFields < 2) {
5123:     DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);
5124:     return(0);
5125:   }
5126:   /* Get points */
5127:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5128:   if (!clPoints) {
5129:     PetscInt pStart, pEnd, p, q;

5131:     PetscSectionGetChart(section, &pStart, &pEnd);
5132:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5133:     /* Compress out points not in the section */
5134:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5135:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5136:         points[q*2]   = points[p];
5137:         points[q*2+1] = points[p+1];
5138:         ++q;
5139:       }
5140:     }
5141:     numPoints = q;
5142:   } else {
5143:     PetscInt dof, off;

5145:     PetscSectionGetDof(clSection, point, &dof);
5146:     PetscSectionGetOffset(clSection, point, &off);
5147:     ISGetIndices(clPoints, &clp);
5148:     numPoints = dof/2;
5149:     points    = (PetscInt *) &clp[off];
5150:   }
5151:   /* Get array */
5152:   if (!values || !*values) {
5153:     PetscInt asize = 0, dof, p;

5155:     for (p = 0; p < numPoints*2; p += 2) {
5156:       PetscSectionGetDof(section, points[p], &dof);
5157:       asize += dof;
5158:     }
5159:     if (!values) {
5160:       if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5161:       else           {ISRestoreIndices(clPoints, &clp);}
5162:       if (csize) *csize = asize;
5163:       return(0);
5164:     }
5165:     DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);
5166:   } else {
5167:     array = *values;
5168:   }
5169:   VecGetArray(v, &vArray);
5170:   /* Get values */
5171:   if (numFields > 1) {DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, vArray, &size, array);}
5172:   else               {DMPlexVecGetClosure_Static(section, numPoints, points, vArray, &size, array);}
5173:   /* Cleanup points */
5174:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5175:   else           {ISRestoreIndices(clPoints, &clp);}
5176:   /* Cleanup array */
5177:   VecRestoreArray(v, &vArray);
5178:   if (!*values) {
5179:     if (csize) *csize = size;
5180:     *values = array;
5181:   } else {
5182:     if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size);
5183:     *csize = size;
5184:   }
5185:   return(0);
5186: }

5190: /*@C
5191:   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'

5193:   Not collective

5195:   Input Parameters:
5196: + dm - The DM
5197: . section - The section describing the layout in v, or NULL to use the default section
5198: . v - The local vector
5199: . point - The sieve point in the DM
5200: . csize - The number of values in the closure, or NULL
5201: - values - The array of values, which is a borrowed array and should not be freed

5203:   Fortran Notes:
5204:   Since it returns an array, this routine is only available in Fortran 90, and you must
5205:   include petsc.h90 in your code.

5207:   The csize argument is not present in the Fortran 90 binding since it is internal to the array.

5209:   Level: intermediate

5211: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
5212: @*/
5213: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
5214: {
5215:   PetscInt       size = 0;

5219:   /* Should work without recalculating size */
5220:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
5221:   return(0);
5222: }

5224: PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
5225: PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}

5229: 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[])
5230: {
5231:   PetscInt        cdof;   /* The number of constraints on this point */
5232:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5233:   PetscScalar    *a;
5234:   PetscInt        off, cind = 0, k;
5235:   PetscErrorCode  ierr;

5238:   PetscSectionGetConstraintDof(section, point, &cdof);
5239:   PetscSectionGetOffset(section, point, &off);
5240:   a    = &array[off];
5241:   if (!cdof || setBC) {
5242:     if (orientation >= 0) {
5243:       for (k = 0; k < dof; ++k) {
5244:         fuse(&a[k], values[k]);
5245:       }
5246:     } else {
5247:       for (k = 0; k < dof; ++k) {
5248:         fuse(&a[k], values[dof-k-1]);
5249:       }
5250:     }
5251:   } else {
5252:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5253:     if (orientation >= 0) {
5254:       for (k = 0; k < dof; ++k) {
5255:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5256:         fuse(&a[k], values[k]);
5257:       }
5258:     } else {
5259:       for (k = 0; k < dof; ++k) {
5260:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5261:         fuse(&a[k], values[dof-k-1]);
5262:       }
5263:     }
5264:   }
5265:   return(0);
5266: }

5270: PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscScalar values[], PetscScalar array[])
5271: {
5272:   PetscInt        cdof;   /* The number of constraints on this point */
5273:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5274:   PetscScalar    *a;
5275:   PetscInt        off, cind = 0, k;
5276:   PetscErrorCode  ierr;

5279:   PetscSectionGetConstraintDof(section, point, &cdof);
5280:   PetscSectionGetOffset(section, point, &off);
5281:   a    = &array[off];
5282:   if (cdof) {
5283:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5284:     if (orientation >= 0) {
5285:       for (k = 0; k < dof; ++k) {
5286:         if ((cind < cdof) && (k == cdofs[cind])) {
5287:           fuse(&a[k], values[k]);
5288:           ++cind;
5289:         }
5290:       }
5291:     } else {
5292:       for (k = 0; k < dof; ++k) {
5293:         if ((cind < cdof) && (k == cdofs[cind])) {
5294:           fuse(&a[k], values[dof-k-1]);
5295:           ++cind;
5296:         }
5297:       }
5298:     }
5299:   }
5300:   return(0);
5301: }

5305: 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[])
5306: {
5307:   PetscScalar    *a;
5308:   PetscInt        fdof, foff, fcdof, foffset = *offset;
5309:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5310:   PetscInt        cind = 0, k, c;
5311:   PetscErrorCode  ierr;

5314:   PetscSectionGetFieldDof(section, point, f, &fdof);
5315:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
5316:   PetscSectionGetFieldOffset(section, point, f, &foff);
5317:   a    = &array[foff];
5318:   if (!fcdof || setBC) {
5319:     if (o >= 0) {
5320:       for (k = 0; k < fdof; ++k) fuse(&a[k], values[foffset+k]);
5321:     } else {
5322:       for (k = fdof/fcomp-1; k >= 0; --k) {
5323:         for (c = 0; c < fcomp; ++c) {
5324:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5325:         }
5326:       }
5327:     }
5328:   } else {
5329:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5330:     if (o >= 0) {
5331:       for (k = 0; k < fdof; ++k) {
5332:         if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
5333:         fuse(&a[k], values[foffset+k]);
5334:       }
5335:     } else {
5336:       for (k = fdof/fcomp-1; k >= 0; --k) {
5337:         for (c = 0; c < fcomp; ++c) {
5338:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
5339:           fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5340:         }
5341:       }
5342:     }
5343:   }
5344:   *offset += fdof;
5345:   return(0);
5346: }

5350: 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[])
5351: {
5352:   PetscScalar    *a;
5353:   PetscInt        fdof, foff, fcdof, foffset = *offset;
5354:   const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5355:   PetscInt        cind = 0, k, c;
5356:   PetscErrorCode  ierr;

5359:   PetscSectionGetFieldDof(section, point, f, &fdof);
5360:   PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
5361:   PetscSectionGetFieldOffset(section, point, f, &foff);
5362:   a    = &array[foff];
5363:   if (fcdof) {
5364:     PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5365:     if (o >= 0) {
5366:       for (k = 0; k < fdof; ++k) {
5367:         if ((cind < fcdof) && (k == fcdofs[cind])) {
5368:           fuse(&a[k], values[foffset+k]);
5369:           ++cind;
5370:         }
5371:       }
5372:     } else {
5373:       for (k = fdof/fcomp-1; k >= 0; --k) {
5374:         for (c = 0; c < fcomp; ++c) {
5375:           if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {
5376:             fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[foffset+k*fcomp+c]);
5377:             ++cind;
5378:           }
5379:         }
5380:       }
5381:     }
5382:   }
5383:   *offset += fdof;
5384:   return(0);
5385: }

5389: PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5390: {
5391:   PetscScalar    *array;
5392:   const PetscInt *cone, *coneO;
5393:   PetscInt        pStart, pEnd, p, numPoints, off, dof;
5394:   PetscErrorCode  ierr;

5397:   PetscSectionGetChart(section, &pStart, &pEnd);
5398:   DMPlexGetConeSize(dm, point, &numPoints);
5399:   DMPlexGetCone(dm, point, &cone);
5400:   DMPlexGetConeOrientation(dm, point, &coneO);
5401:   VecGetArray(v, &array);
5402:   for (p = 0, off = 0; p <= numPoints; ++p, off += dof) {
5403:     const PetscInt cp = !p ? point : cone[p-1];
5404:     const PetscInt o  = !p ? 0     : coneO[p-1];

5406:     if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;}
5407:     PetscSectionGetDof(section, cp, &dof);
5408:     /* ADD_VALUES */
5409:     {
5410:       const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5411:       PetscScalar    *a;
5412:       PetscInt        cdof, coff, cind = 0, k;

5414:       PetscSectionGetConstraintDof(section, cp, &cdof);
5415:       PetscSectionGetOffset(section, cp, &coff);
5416:       a    = &array[coff];
5417:       if (!cdof) {
5418:         if (o >= 0) {
5419:           for (k = 0; k < dof; ++k) {
5420:             a[k] += values[off+k];
5421:           }
5422:         } else {
5423:           for (k = 0; k < dof; ++k) {
5424:             a[k] += values[off+dof-k-1];
5425:           }
5426:         }
5427:       } else {
5428:         PetscSectionGetConstraintIndices(section, cp, &cdofs);
5429:         if (o >= 0) {
5430:           for (k = 0; k < dof; ++k) {
5431:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5432:             a[k] += values[off+k];
5433:           }
5434:         } else {
5435:           for (k = 0; k < dof; ++k) {
5436:             if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
5437:             a[k] += values[off+dof-k-1];
5438:           }
5439:         }
5440:       }
5441:     }
5442:   }
5443:   VecRestoreArray(v, &array);
5444:   return(0);
5445: }

5449: /*@C
5450:   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'

5452:   Not collective

5454:   Input Parameters:
5455: + dm - The DM
5456: . section - The section describing the layout in v, or NULL to use the default section
5457: . v - The local vector
5458: . point - The sieve point in the DM
5459: . values - The array of values
5460: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

5462:   Fortran Notes:
5463:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

5465:   Level: intermediate

5467: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
5468: @*/
5469: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
5470: {
5471:   PetscSection    clSection;
5472:   IS              clPoints;
5473:   PetscScalar    *array;
5474:   PetscInt       *points = NULL;
5475:   const PetscInt *clp;
5476:   PetscInt        depth, numFields, numPoints, p;
5477:   PetscErrorCode  ierr;

5481:   if (!section) {DMGetDefaultSection(dm, &section);}
5484:   DMPlexGetDepth(dm, &depth);
5485:   PetscSectionGetNumFields(section, &numFields);
5486:   if (depth == 1 && numFields < 2 && mode == ADD_VALUES) {
5487:     DMPlexVecSetClosure_Static(dm, section, v, point, values, mode);
5488:     return(0);
5489:   }
5490:   /* Get points */
5491:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5492:   if (!clPoints) {
5493:     PetscInt pStart, pEnd, q;

5495:     PetscSectionGetChart(section, &pStart, &pEnd);
5496:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5497:     /* Compress out points not in the section */
5498:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5499:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5500:         points[q*2]   = points[p];
5501:         points[q*2+1] = points[p+1];
5502:         ++q;
5503:       }
5504:     }
5505:     numPoints = q;
5506:   } else {
5507:     PetscInt dof, off;

5509:     PetscSectionGetDof(clSection, point, &dof);
5510:     PetscSectionGetOffset(clSection, point, &off);
5511:     ISGetIndices(clPoints, &clp);
5512:     numPoints = dof/2;
5513:     points    = (PetscInt *) &clp[off];
5514:   }
5515:   /* Get array */
5516:   VecGetArray(v, &array);
5517:   /* Get values */
5518:   if (numFields > 1) {
5519:     PetscInt offset = 0, fcomp, f;
5520:     for (f = 0; f < numFields; ++f) {
5521:       PetscSectionGetFieldComponents(section, f, &fcomp);
5522:       switch (mode) {
5523:       case INSERT_VALUES:
5524:         for (p = 0; p < numPoints*2; p += 2) {
5525:           const PetscInt point = points[p];
5526:           const PetscInt o     = points[p+1];
5527:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, values, &offset, array);
5528:         } break;
5529:       case INSERT_ALL_VALUES:
5530:         for (p = 0; p < numPoints*2; p += 2) {
5531:           const PetscInt point = points[p];
5532:           const PetscInt o     = points[p+1];
5533:           updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, values, &offset, array);
5534:         } break;
5535:       case INSERT_BC_VALUES:
5536:         for (p = 0; p < numPoints*2; p += 2) {
5537:           const PetscInt point = points[p];
5538:           const PetscInt o     = points[p+1];
5539:           updatePointFieldsBC_private(section, point, o, f, fcomp, insert, values, &offset, array);
5540:         } break;
5541:       case ADD_VALUES:
5542:         for (p = 0; p < numPoints*2; p += 2) {
5543:           const PetscInt point = points[p];
5544:           const PetscInt o     = points[p+1];
5545:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, values, &offset, array);
5546:         } break;
5547:       case ADD_ALL_VALUES:
5548:         for (p = 0; p < numPoints*2; p += 2) {
5549:           const PetscInt point = points[p];
5550:           const PetscInt o     = points[p+1];
5551:           updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, values, &offset, array);
5552:         } break;
5553:       default:
5554:         SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5555:       }
5556:     }
5557:   } else {
5558:     PetscInt dof, off;

5560:     switch (mode) {
5561:     case INSERT_VALUES:
5562:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5563:         PetscInt o = points[p+1];
5564:         PetscSectionGetDof(section, points[p], &dof);
5565:         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
5566:       } break;
5567:     case INSERT_ALL_VALUES:
5568:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5569:         PetscInt o = points[p+1];
5570:         PetscSectionGetDof(section, points[p], &dof);
5571:         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
5572:       } break;
5573:     case INSERT_BC_VALUES:
5574:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5575:         PetscInt o = points[p+1];
5576:         PetscSectionGetDof(section, points[p], &dof);
5577:         updatePointBC_private(section, points[p], dof, insert,  o, &values[off], array);
5578:       } break;
5579:     case ADD_VALUES:
5580:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5581:         PetscInt o = points[p+1];
5582:         PetscSectionGetDof(section, points[p], &dof);
5583:         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
5584:       } break;
5585:     case ADD_ALL_VALUES:
5586:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
5587:         PetscInt o = points[p+1];
5588:         PetscSectionGetDof(section, points[p], &dof);
5589:         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
5590:       } break;
5591:     default:
5592:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
5593:     }
5594:   }
5595:   /* Cleanup points */
5596:   if (!clPoints) {DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);}
5597:   else           {ISRestoreIndices(clPoints, &clp);}
5598:   /* Cleanup array */
5599:   VecRestoreArray(v, &array);
5600:   return(0);
5601: }

5605: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
5606: {
5607:   PetscMPIInt    rank;
5608:   PetscInt       i, j;

5612:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
5613:   PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);
5614:   for (i = 0; i < numIndices; i++) {
5615:     PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);
5616:   }
5617:   for (i = 0; i < numIndices; i++) {
5618:     PetscViewerASCIIPrintf(viewer, "[%D]", rank);
5619:     for (j = 0; j < numIndices; j++) {
5620: #if defined(PETSC_USE_COMPLEX)
5621:       PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numIndices+j]), (double)PetscImaginaryPart(values[i*numIndices+j]));
5622: #else
5623:       PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numIndices+j]);
5624: #endif
5625:     }
5626:     PetscViewerASCIIPrintf(viewer, "\n");
5627:   }
5628:   return(0);
5629: }

5633: /* . off - The global offset of this point */
5634: PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
5635: {
5636:   PetscInt        dof;    /* The number of unknowns on this point */
5637:   PetscInt        cdof;   /* The number of constraints on this point */
5638:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
5639:   PetscInt        cind = 0, k;
5640:   PetscErrorCode  ierr;

5643:   PetscSectionGetDof(section, point, &dof);
5644:   PetscSectionGetConstraintDof(section, point, &cdof);
5645:   if (!cdof || setBC) {
5646:     if (orientation >= 0) {
5647:       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
5648:     } else {
5649:       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
5650:     }
5651:   } else {
5652:     PetscSectionGetConstraintIndices(section, point, &cdofs);
5653:     if (orientation >= 0) {
5654:       for (k = 0; k < dof; ++k) {
5655:         if ((cind < cdof) && (k == cdofs[cind])) {
5656:           /* Insert check for returning constrained indices */
5657:           indices[*loff+k] = -(off+k+1);
5658:           ++cind;
5659:         } else {
5660:           indices[*loff+k] = off+k-cind;
5661:         }
5662:       }
5663:     } else {
5664:       for (k = 0; k < dof; ++k) {
5665:         if ((cind < cdof) && (k == cdofs[cind])) {
5666:           /* Insert check for returning constrained indices */
5667:           indices[*loff+dof-k-1] = -(off+k+1);
5668:           ++cind;
5669:         } else {
5670:           indices[*loff+dof-k-1] = off+k-cind;
5671:         }
5672:       }
5673:     }
5674:   }
5675:   *loff += dof;
5676:   return(0);
5677: }

5681: /* . off - The global offset of this point */
5682: PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
5683: {
5684:   PetscInt       numFields, foff, f;

5688:   PetscSectionGetNumFields(section, &numFields);
5689:   for (f = 0, foff = 0; f < numFields; ++f) {
5690:     PetscInt        fdof, fcomp, cfdof;
5691:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
5692:     PetscInt        cind = 0, k, c;

5694:     PetscSectionGetFieldComponents(section, f, &fcomp);
5695:     PetscSectionGetFieldDof(section, point, f, &fdof);
5696:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
5697:     if (!cfdof || setBC) {
5698:       if (orientation >= 0) {
5699:         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
5700:       } else {
5701:         for (k = fdof/fcomp-1; k >= 0; --k) {
5702:           for (c = 0; c < fcomp; ++c) {
5703:             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
5704:           }
5705:         }
5706:       }
5707:     } else {
5708:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
5709:       if (orientation >= 0) {
5710:         for (k = 0; k < fdof; ++k) {
5711:           if ((cind < cfdof) && (k == fcdofs[cind])) {
5712:             indices[foffs[f]+k] = -(off+foff+k+1);
5713:             ++cind;
5714:           } else {
5715:             indices[foffs[f]+k] = off+foff+k-cind;
5716:           }
5717:         }
5718:       } else {
5719:         for (k = fdof/fcomp-1; k >= 0; --k) {
5720:           for (c = 0; c < fcomp; ++c) {
5721:             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
5722:               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
5723:               ++cind;
5724:             } else {
5725:               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
5726:             }
5727:           }
5728:         }
5729:       }
5730:     }
5731:     foff     += fdof - cfdof;
5732:     foffs[f] += fdof;
5733:   }
5734:   return(0);
5735: }

5739: /*@C
5740:   DMPlexMatSetClosure - Set an array of the values on the closure of 'point'

5742:   Not collective

5744:   Input Parameters:
5745: + dm - The DM
5746: . section - The section describing the layout in v, or NULL to use the default section
5747: . globalSection - The section describing the layout in v, or NULL to use the default global section
5748: . A - The matrix
5749: . point - The sieve point in the DM
5750: . values - The array of values
5751: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

5753:   Fortran Notes:
5754:   This routine is only available in Fortran 90, and you must include petsc.h90 in your code.

5756:   Level: intermediate

5758: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
5759: @*/
5760: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
5761: {
5762:   DM_Plex        *mesh   = (DM_Plex*) dm->data;
5763:   PetscSection    clSection;
5764:   IS              clPoints;
5765:   PetscInt       *points = NULL;
5766:   const PetscInt *clp;
5767:   PetscInt       *indices;
5768:   PetscInt        offsets[32];
5769:   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
5770:   PetscErrorCode  ierr;

5774:   if (!section) {DMGetDefaultSection(dm, &section);}
5776:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
5779:   PetscSectionGetNumFields(section, &numFields);
5780:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
5781:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
5782:   PetscSectionGetClosureIndex(section, (PetscObject) dm, &clSection, &clPoints);
5783:   if (!clPoints) {
5784:     DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5785:     /* Compress out points not in the section */
5786:     PetscSectionGetChart(section, &pStart, &pEnd);
5787:     for (p = 0, q = 0; p < numPoints*2; p += 2) {
5788:       if ((points[p] >= pStart) && (points[p] < pEnd)) {
5789:         points[q*2]   = points[p];
5790:         points[q*2+1] = points[p+1];
5791:         ++q;
5792:       }
5793:     }
5794:     numPoints = q;
5795:   } else {
5796:     PetscInt dof, off;

5798:     PetscSectionGetDof(clSection, point, &dof);
5799:     numPoints = dof/2;
5800:     PetscSectionGetOffset(clSection, point, &off);
5801:     ISGetIndices(clPoints, &clp);
5802:     points = (PetscInt *) &clp[off];
5803:   }
5804:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
5805:     PetscInt fdof;

5807:     PetscSectionGetDof(section, points[p], &dof);
5808:     for (f = 0; f < numFields; ++f) {
5809:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
5810:       offsets[f+1] += fdof;
5811:     }
5812:     numIndices += dof;
5813:   }
5814:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

5816:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
5817:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
5818:   if (numFields) {
5819:     for (p = 0; p < numPoints*2; p += 2) {
5820:       PetscInt o = points[p+1];
5821:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5822:       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
5823:     }
5824:   } else {
5825:     for (p = 0, off = 0; p < numPoints*2; p += 2) {
5826:       PetscInt o = points[p+1];
5827:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
5828:       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
5829:     }
5830:   }
5831:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);}
5832:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
5833:   if (ierr) {
5834:     PetscMPIInt    rank;
5835:     PetscErrorCode ierr2;

5837:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
5838:     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
5839:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
5840:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
5841: 
5842:   }
5843:   if (!clPoints) {
5844:     DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
5845:   } else {
5846:     ISRestoreIndices(clPoints, &clp);
5847:   }
5848:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
5849:   return(0);
5850: }

5854: /*@
5855:   DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid

5857:   Input Parameter:
5858: . dm - The DMPlex object

5860:   Output Parameters:
5861: + cMax - The first hybrid cell
5862: . cMax - The first hybrid face
5863: . cMax - The first hybrid edge
5864: - cMax - The first hybrid vertex

5866:   Level: developer

5868: .seealso DMPlexCreateHybridMesh()
5869: @*/
5870: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
5871: {
5872:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5873:   PetscInt       dim;

5878:   DMPlexGetDimension(dm, &dim);
5879:   if (cMax) *cMax = mesh->hybridPointMax[dim];
5880:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
5881:   if (eMax) *eMax = mesh->hybridPointMax[1];
5882:   if (vMax) *vMax = mesh->hybridPointMax[0];
5883:   return(0);
5884: }

5888: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
5889: {
5890:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5891:   PetscInt       dim;

5896:   DMPlexGetDimension(dm, &dim);
5897:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
5898:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
5899:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
5900:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
5901:   return(0);
5902: }

5906: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
5907: {
5908:   DM_Plex *mesh = (DM_Plex*) dm->data;

5913:   *cellHeight = mesh->vtkCellHeight;
5914:   return(0);
5915: }

5919: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
5920: {
5921:   DM_Plex *mesh = (DM_Plex*) dm->data;

5925:   mesh->vtkCellHeight = cellHeight;
5926:   return(0);
5927: }

5931: /* We can easily have a form that takes an IS instead */
5932: PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
5933: {
5934:   PetscSection   section, globalSection;
5935:   PetscInt      *numbers, p;

5939:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
5940:   PetscSectionSetChart(section, pStart, pEnd);
5941:   for (p = pStart; p < pEnd; ++p) {
5942:     PetscSectionSetDof(section, p, 1);
5943:   }
5944:   PetscSectionSetUp(section);
5945:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);
5946:   PetscMalloc1((pEnd - pStart), &numbers);
5947:   for (p = pStart; p < pEnd; ++p) {
5948:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
5949:   }
5950:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
5951:   PetscSectionDestroy(&section);
5952:   PetscSectionDestroy(&globalSection);
5953:   return(0);
5954: }

5958: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
5959: {
5960:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5961:   PetscInt       cellHeight, cStart, cEnd, cMax;

5966:   if (!mesh->globalCellNumbers) {
5967:     DMPlexGetVTKCellHeight(dm, &cellHeight);
5968:     DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
5969:     DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5970:     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
5971:     DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);
5972:   }
5973:   *globalCellNumbers = mesh->globalCellNumbers;
5974:   return(0);
5975: }

5979: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
5980: {
5981:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5982:   PetscInt       vStart, vEnd, vMax;

5987:   if (!mesh->globalVertexNumbers) {
5988:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5989:     DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
5990:     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
5991:     DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);
5992:   }
5993:   *globalVertexNumbers = mesh->globalVertexNumbers;
5994:   return(0);
5995: }


6000: /*@C
6001:   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
6002:   the local section and an SF describing the section point overlap.

6004:   Input Parameters:
6005:   + s - The PetscSection for the local field layout
6006:   . sf - The SF describing parallel layout of the section points
6007:   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
6008:   . label - The label specifying the points
6009:   - labelValue - The label stratum specifying the points

6011:   Output Parameter:
6012:   . gsection - The PetscSection for the global field layout

6014:   Note: This gives negative sizes and offsets to points not owned by this process

6016:   Level: developer

6018: .seealso: PetscSectionCreate()
6019: @*/
6020: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
6021: {
6022:   PetscInt      *neg = NULL, *tmpOff = NULL;
6023:   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;

6027:   PetscSectionCreate(s->atlasLayout.comm, gsection);
6028:   PetscSectionGetChart(s, &pStart, &pEnd);
6029:   PetscSectionSetChart(*gsection, pStart, pEnd);
6030:   PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);
6031:   if (nroots >= 0) {
6032:     if (nroots < pEnd-pStart) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %d < %d section size", nroots, pEnd-pStart);
6033:     PetscCalloc1(nroots, &neg);
6034:     if (nroots > pEnd-pStart) {
6035:       PetscCalloc1(nroots, &tmpOff);
6036:     } else {
6037:       tmpOff = &(*gsection)->atlasDof[-pStart];
6038:     }
6039:   }
6040:   /* Mark ghost points with negative dof */
6041:   for (p = pStart; p < pEnd; ++p) {
6042:     PetscInt value;

6044:     DMLabelGetValue(label, p, &value);
6045:     if (value != labelValue) continue;
6046:     PetscSectionGetDof(s, p, &dof);
6047:     PetscSectionSetDof(*gsection, p, dof);
6048:     PetscSectionGetConstraintDof(s, p, &cdof);
6049:     if (!includeConstraints && cdof > 0) {PetscSectionSetConstraintDof(*gsection, p, cdof);}
6050:     if (neg) neg[p] = -(dof+1);
6051:   }
6052:   PetscSectionSetUpBC(*gsection);
6053:   if (nroots >= 0) {
6054:     PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
6055:     PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
6056:     if (nroots > pEnd-pStart) {
6057:       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpOff[p];}
6058:     }
6059:   }
6060:   /* Calculate new sizes, get proccess offset, and calculate point offsets */
6061:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6062:     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
6063:     (*gsection)->atlasOff[p] = off;
6064:     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
6065:   }
6066:   MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);
6067:   globalOff -= off;
6068:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
6069:     (*gsection)->atlasOff[p] += globalOff;
6070:     if (neg) neg[p] = -((*gsection)->atlasOff[p]+1);
6071:   }
6072:   /* Put in negative offsets for ghost points */
6073:   if (nroots >= 0) {
6074:     PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff);
6075:     PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff);
6076:     if (nroots > pEnd-pStart) {
6077:       for (p = pStart; p < pEnd; ++p) {if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];}
6078:     }
6079:   }
6080:   if (nroots >= 0 && nroots > pEnd-pStart) {PetscFree(tmpOff);}
6081:   PetscFree(neg);
6082:   return(0);
6083: }

6087: /*@
6088:   DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric.

6090:   Input Parameters:
6091:   + dm - The DMPlex object

6093:   Note: This is a useful diagnostic when creating meshes programmatically.

6095:   Level: developer

6097: .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces()
6098: @*/
6099: PetscErrorCode DMPlexCheckSymmetry(DM dm)
6100: {
6101:   PetscSection    coneSection, supportSection;
6102:   const PetscInt *cone, *support;
6103:   PetscInt        coneSize, c, supportSize, s;
6104:   PetscInt        pStart, pEnd, p, csize, ssize;
6105:   PetscErrorCode  ierr;

6109:   DMPlexGetConeSection(dm, &coneSection);
6110:   DMPlexGetSupportSection(dm, &supportSection);
6111:   /* Check that point p is found in the support of its cone points, and vice versa */
6112:   DMPlexGetChart(dm, &pStart, &pEnd);
6113:   for (p = pStart; p < pEnd; ++p) {
6114:     DMPlexGetConeSize(dm, p, &coneSize);
6115:     DMPlexGetCone(dm, p, &cone);
6116:     for (c = 0; c < coneSize; ++c) {
6117:       DMPlexGetSupportSize(dm, cone[c], &supportSize);
6118:       DMPlexGetSupport(dm, cone[c], &support);
6119:       for (s = 0; s < supportSize; ++s) {
6120:         if (support[s] == p) break;
6121:       }
6122:       if (s >= supportSize) {
6123:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);
6124:         for (s = 0; s < coneSize; ++s) {
6125:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);
6126:         }
6127:         PetscPrintf(PETSC_COMM_SELF, "\n");
6128:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);
6129:         for (s = 0; s < supportSize; ++s) {
6130:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);
6131:         }
6132:         PetscPrintf(PETSC_COMM_SELF, "\n");
6133:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]);
6134:       }
6135:     }
6136:     DMPlexGetSupportSize(dm, p, &supportSize);
6137:     DMPlexGetSupport(dm, p, &support);
6138:     for (s = 0; s < supportSize; ++s) {
6139:       DMPlexGetConeSize(dm, support[s], &coneSize);
6140:       DMPlexGetCone(dm, support[s], &cone);
6141:       for (c = 0; c < coneSize; ++c) {
6142:         if (cone[c] == p) break;
6143:       }
6144:       if (c >= coneSize) {
6145:         PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);
6146:         for (c = 0; c < supportSize; ++c) {
6147:           PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);
6148:         }
6149:         PetscPrintf(PETSC_COMM_SELF, "\n");
6150:         PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);
6151:         for (c = 0; c < coneSize; ++c) {
6152:           PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);
6153:         }
6154:         PetscPrintf(PETSC_COMM_SELF, "\n");
6155:         SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]);
6156:       }
6157:     }
6158:   }
6159:   PetscSectionGetStorageSize(coneSection, &csize);
6160:   PetscSectionGetStorageSize(supportSection, &ssize);
6161:   if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize);
6162:   return(0);
6163: }

6167: /*@
6168:   DMPlexCheckSkeleton - Check that each cell has the correct number of vertices

6170:   Input Parameters:
6171: + dm - The DMPlex object
6172: . isSimplex - Are the cells simplices or tensor products
6173: - cellHeight - Normally 0

6175:   Note: This is a useful diagnostic when creating meshes programmatically.

6177:   Level: developer

6179: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces()
6180: @*/
6181: PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6182: {
6183:   PetscInt       dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c;

6188:   DMPlexGetDimension(dm, &dim);
6189:   switch (dim) {
6190:   case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break;
6191:   case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break;
6192:   case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break;
6193:   default:
6194:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim);
6195:   }
6196:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6197:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
6198:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
6199:   cMax = cMax >= 0 ? cMax : cEnd;
6200:   for (c = cStart; c < cMax; ++c) {
6201:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6203:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6204:     for (cl = 0; cl < closureSize*2; cl += 2) {
6205:       const PetscInt p = closure[cl];
6206:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6207:     }
6208:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6209:     if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has  %d vertices != %d", c, coneSize, numCorners);
6210:   }
6211:   for (c = cMax; c < cEnd; ++c) {
6212:     PetscInt *closure = NULL, closureSize, cl, coneSize = 0;

6214:     DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6215:     for (cl = 0; cl < closureSize*2; cl += 2) {
6216:       const PetscInt p = closure[cl];
6217:       if ((p >= vStart) && (p < vEnd)) ++coneSize;
6218:     }
6219:     DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6220:     if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has  %d vertices > %d", c, coneSize, numHybridCorners);
6221:   }
6222:   return(0);
6223: }

6227: /*@
6228:   DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type

6230:   Input Parameters:
6231: + dm - The DMPlex object
6232: . isSimplex - Are the cells simplices or tensor products
6233: - cellHeight - Normally 0

6235:   Note: This is a useful diagnostic when creating meshes programmatically.

6237:   Level: developer

6239: .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton()
6240: @*/
6241: PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight)
6242: {
6243:   PetscInt       pMax[4];
6244:   PetscInt       dim, vStart, vEnd, cStart, cEnd, c, h;

6249:   DMPlexGetDimension(dm, &dim);
6250:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
6251:   DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);
6252:   for (h = cellHeight; h < dim; ++h) {
6253:     DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);
6254:     for (c = cStart; c < cEnd; ++c) {
6255:       const PetscInt *cone, *ornt, *faces;
6256:       PetscInt        numFaces, faceSize, coneSize,f;
6257:       PetscInt       *closure = NULL, closureSize, cl, numCorners = 0;

6259:       if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue;
6260:       DMPlexGetConeSize(dm, c, &coneSize);
6261:       DMPlexGetCone(dm, c, &cone);
6262:       DMPlexGetConeOrientation(dm, c, &ornt);
6263:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6264:       for (cl = 0; cl < closureSize*2; cl += 2) {
6265:         const PetscInt p = closure[cl];
6266:         if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p;
6267:       }
6268:       DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);
6269:       if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces);
6270:       for (f = 0; f < numFaces; ++f) {
6271:         PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v;

6273:         DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);
6274:         for (cl = 0; cl < fclosureSize*2; cl += 2) {
6275:           const PetscInt p = fclosure[cl];
6276:           if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p;
6277:         }
6278:         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);
6279:         for (v = 0; v < fnumCorners; ++v) {
6280:           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]);
6281:         }
6282:         DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);
6283:       }
6284:       DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);
6285:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
6286:     }
6287:   }
6288:   return(0);
6289: }