Actual source code: plex.c

petsc-3.4.5 2014-06-29
  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_Distribute, DMPLEX_Stratify;

  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", 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", 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;
279:     PetscInt    locDepth, depth, dim, d;
280:     PetscInt    pStart, pEnd, p;
281:     PetscInt    numLabels, l;
282:     PetscMPIInt size;

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

324:       DMPlexGetLabelName(dm, l, &name);
325:       DMPlexGetLabel(dm, name, &label);
326:       DMLabelGetNumValues(label, &numValues);
327:       PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);
328:       DMLabelGetValueIS(label, &valueIS);
329:       ISGetIndices(valueIS, &values);
330:       for (v = 0; v < numValues; ++v) {
331:         PetscInt size;

333:         DMLabelGetStratumSize(label, values[v], &size);
334:         if (v > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
335:         PetscViewerASCIIPrintf(viewer, "%d", size);
336:       }
337:       PetscViewerASCIIPrintf(viewer, ")\n");
338:       ISRestoreIndices(valueIS, &values);
339:       ISDestroy(&valueIS);
340:     }
341:   }
342:   return(0);
343: }

347: PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
348: {
349:   PetscBool      iascii, isbinary;

355:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
356:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);
357:   if (iascii) {
358:     DMPlexView_Ascii(dm, viewer);
359: #if 0
360:   } else if (isbinary) {
361:     DMPlexView_Binary(dm, viewer);
362: #endif
363:   }
364:   return(0);
365: }

369: PetscErrorCode DMDestroy_Plex(DM dm)
370: {
371:   DM_Plex       *mesh = (DM_Plex*) dm->data;
372:   DMLabel        next  = mesh->labels;

376:   if (--mesh->refct > 0) return(0);
377:   PetscSectionDestroy(&mesh->coneSection);
378:   PetscFree(mesh->cones);
379:   PetscFree(mesh->coneOrientations);
380:   PetscSectionDestroy(&mesh->supportSection);
381:   PetscFree(mesh->supports);
382:   PetscFree(mesh->facesTmp);
383:   while (next) {
384:     DMLabel tmp = next->next;

386:     DMLabelDestroy(&next);
387:     next = tmp;
388:   }
389:   DMLabelDestroy(&mesh->subpointMap);
390:   ISDestroy(&mesh->globalVertexNumbers);
391:   ISDestroy(&mesh->globalCellNumbers);
392:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
393:   PetscFree(mesh);
394:   return(0);
395: }

399: PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
400: {
401:   PetscSection   section, sectionGlobal;
402:   PetscInt       bs = -1;
403:   PetscInt       localSize;
404:   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;

408: #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
409:   MatInitializePackage();
410: #endif
411:   if (!mtype) mtype = MATAIJ;
412:   DMGetDefaultSection(dm, &section);
413:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
414:   /* PetscSectionGetStorageSize(sectionGlobal, &localSize); */
415:   PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);
416:   MatCreate(PetscObjectComm((PetscObject)dm), J);
417:   MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);
418:   MatSetType(*J, mtype);
419:   MatSetFromOptions(*J);
420:   PetscStrcmp(mtype, MATSHELL, &isShell);
421:   PetscStrcmp(mtype, MATBAIJ, &isBlock);
422:   PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);
423:   PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);
424:   PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);
425:   PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);
426:   PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);
427:   /* Check for symmetric storage */
428:   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
429:   if (isSymmetric) {
430:     MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);
431:   }
432:   if (!isShell) {
433:     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
434:     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;

436:     if (bs < 0) {
437:       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
438:         PetscInt pStart, pEnd, p, dof, cdof;

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

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

484:   Not collective

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

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

492:   Level: beginner

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

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

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

512:   Collective on mesh

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

518:   Level: beginner

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

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

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

539:   Not collective

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

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

548:   Level: beginner

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

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

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

568:   Not collective

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

575:   Output Parameters:

577:   Level: beginner

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

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

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

598:   Not collective

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

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

607:   Level: beginner

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

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

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

628:   Not collective

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

635:   Output Parameter:

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

640:   Level: beginner

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

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

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

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

662:   Not collective

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

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

671:   Level: beginner

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

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

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

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

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

700:   Not collective

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

707:   Output Parameter:

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

712:   Level: beginner

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

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

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

742:   Not collective

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

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

754:   Level: beginner

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

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

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

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

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

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

790:   Not collective

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

800:   Output Parameter:

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

805:   Level: beginner

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

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

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

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

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

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

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

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

879:   Not collective

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

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

888:   Level: beginner

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

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

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

909:   Not collective

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

916:   Output Parameter:

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

921:   Level: beginner

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

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

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

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

943:   Not collective

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

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

952:   Level: beginner

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

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

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

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

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

981:   Not collective

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

988:   Output Parameter:

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

993:   Level: beginner

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

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

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

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

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

1044:   Not collective

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

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

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

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

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

1065:   Level: beginner

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

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

1103:     closure[closureSize]   = cp;
1104:     closure[closureSize+1] = co;
1105:     fifo[fifoSize]         = cp;
1106:     fifo[fifoSize+1]       = co;
1107:   }
1108:   while (fifoSize - fifoStart) {
1109:     const PetscInt q   = fifo[fifoStart];
1110:     const PetscInt o   = fifo[fifoStart+1];
1111:     const PetscInt rev = o >= 0 ? 0 : 1;
1112:     const PetscInt off = rev ? -(o+1) : o;

1114:     if (useCone) {
1115:       DMPlexGetConeSize(dm, q, &tmpSize);
1116:       DMPlexGetCone(dm, q, &tmp);
1117:       DMPlexGetConeOrientation(dm, q, &tmpO);
1118:     } else {
1119:       DMPlexGetSupportSize(dm, q, &tmpSize);
1120:       DMPlexGetSupport(dm, q, &tmp);
1121:       tmpO = NULL;
1122:     }
1123:     for (t = 0; t < tmpSize; ++t) {
1124:       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1125:       const PetscInt cp = tmp[i];
1126:       /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */
1127:       /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1)
1128:        const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */
1129:       PetscInt       co = tmpO ? tmpO[i] : 0;
1130:       PetscInt       c;

1132:       if (rev) {
1133:         PetscInt childSize, coff;
1134:         DMPlexGetConeSize(dm, cp, &childSize);
1135:         coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i];
1136:         co   = childSize ? -(((coff+childSize-1)%childSize)+1) : 0;
1137:       }
1138:       /* Check for duplicate */
1139:       for (c = 0; c < closureSize; c += 2) {
1140:         if (closure[c] == cp) break;
1141:       }
1142:       if (c == closureSize) {
1143:         closure[closureSize]   = cp;
1144:         closure[closureSize+1] = co;
1145:         fifo[fifoSize]         = cp;
1146:         fifo[fifoSize+1]       = co;
1147:         closureSize           += 2;
1148:         fifoSize              += 2;
1149:       }
1150:     }
1151:     fifoStart += 2;
1152:   }
1153:   if (numPoints) *numPoints = closureSize/2;
1154:   if (points)    *points    = closure;
1155:   DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);
1156:   return(0);
1157: }

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

1164:   Not collective

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

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

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

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

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

1185:   Level: beginner

1187: .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1188: @*/
1189: PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1190: {

1195:   DMRestoreWorkArray(dm, 0, PETSC_INT, points);
1196:   return(0);
1197: }

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

1204:   Not collective

1206:   Input Parameter:
1207: . mesh - The DMPlex

1209:   Output Parameters:
1210: + maxConeSize - The maximum number of in-edges
1211: - maxSupportSize - The maximum number of out-edges

1213:   Level: beginner

1215: .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1216: @*/
1217: PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1218: {
1219:   DM_Plex *mesh = (DM_Plex*) dm->data;

1223:   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1224:   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1225:   return(0);
1226: }

1230: PetscErrorCode DMSetUp_Plex(DM dm)
1231: {
1232:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1233:   PetscInt       size;

1238:   PetscSectionSetUp(mesh->coneSection);
1239:   PetscSectionGetStorageSize(mesh->coneSection, &size);
1240:   PetscMalloc(size * sizeof(PetscInt), &mesh->cones);
1241:   PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);
1242:   PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));
1243:   if (mesh->maxSupportSize) {
1244:     PetscSectionSetUp(mesh->supportSection);
1245:     PetscSectionGetStorageSize(mesh->supportSection, &size);
1246:     PetscMalloc(size * sizeof(PetscInt), &mesh->supports);
1247:   }
1248:   return(0);
1249: }

1253: PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1254: {
1255:   PetscSection   section, sectionGlobal;
1256:   PetscInt      *subIndices;
1257:   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;

1261:   if (!numFields) return(0);
1262:   DMGetDefaultSection(dm, &section);
1263:   DMGetDefaultGlobalSection(dm, &sectionGlobal);
1264:   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1265:   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1266:   PetscSectionGetNumFields(section, &nF);
1267:   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1268:   PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1269:   for (p = pStart; p < pEnd; ++p) {
1270:     PetscInt gdof;

1272:     PetscSectionGetDof(sectionGlobal, p, &gdof);
1273:     if (gdof > 0) {
1274:       for (f = 0; f < numFields; ++f) {
1275:         PetscInt fdof, fcdof;

1277:         PetscSectionGetFieldDof(section, p, fields[f], &fdof);
1278:         PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);
1279:         subSize += fdof-fcdof;
1280:       }
1281:     }
1282:   }
1283:   PetscMalloc(subSize * sizeof(PetscInt), &subIndices);
1284:   for (p = pStart; p < pEnd; ++p) {
1285:     PetscInt gdof, goff;

1287:     PetscSectionGetDof(sectionGlobal, p, &gdof);
1288:     if (gdof > 0) {
1289:       PetscSectionGetOffset(sectionGlobal, p, &goff);
1290:       for (f = 0; f < numFields; ++f) {
1291:         PetscInt fdof, fcdof, fc, f2, poff = 0;

1293:         /* Can get rid of this loop by storing field information in the global section */
1294:         for (f2 = 0; f2 < fields[f]; ++f2) {
1295:           PetscSectionGetFieldDof(section, p, f2, &fdof);
1296:           PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);
1297:           poff += fdof-fcdof;
1298:         }
1299:         PetscSectionGetFieldDof(section, p, fields[f], &fdof);
1300:         PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);
1301:         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1302:           subIndices[subOff] = goff+poff+fc;
1303:         }
1304:       }
1305:     }
1306:   }
1307:   if (is) {ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);}
1308:   if (subdm) {
1309:     PetscSection subsection;
1310:     PetscBool    haveNull = PETSC_FALSE;
1311:     PetscInt     f, nf = 0;

1313:     DMPlexClone(dm, subdm);
1314:     PetscSectionCreateSubsection(section, numFields, fields, &subsection);
1315:     DMSetDefaultSection(*subdm, subsection);
1316:     PetscSectionDestroy(&subsection);
1317:     for (f = 0; f < numFields; ++f) {
1318:       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1319:       if ((*subdm)->nullspaceConstructors[f]) {
1320:         haveNull = PETSC_TRUE;
1321:         nf       = f;
1322:       }
1323:     }
1324:     if (haveNull) {
1325:       MatNullSpace nullSpace;

1327:       (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);
1328:       PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);
1329:       MatNullSpaceDestroy(&nullSpace);
1330:     }
1331:     if (dm->fields) {
1332:       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1333:       DMSetNumFields(*subdm, numFields);
1334:       for (f = 0; f < numFields; ++f) {
1335:         PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);
1336:       }
1337:       if (numFields == 1) {
1338:         MatNullSpace space;
1339:         Mat          pmat;

1341:         PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);
1342:         if (space) {PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);}
1343:         PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);
1344:         if (space) {PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);}
1345:         PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);
1346:         if (pmat) {PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);}
1347:       }
1348:     }
1349:   }
1350:   return(0);
1351: }

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

1358:   Not collective

1360:   Input Parameter:
1361: . mesh - The DMPlex

1363:   Output Parameter:

1365:   Note:
1366:   This should be called after all calls to DMPlexSetCone()

1368:   Level: beginner

1370: .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1371: @*/
1372: PetscErrorCode DMPlexSymmetrize(DM dm)
1373: {
1374:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1375:   PetscInt      *offsets;
1376:   PetscInt       supportSize;
1377:   PetscInt       pStart, pEnd, p;

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

1388:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1389:     PetscSectionGetOffset(mesh->coneSection, p, &off);
1390:     for (c = off; c < off+dof; ++c) {
1391:       PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);
1392:     }
1393:   }
1394:   for (p = pStart; p < pEnd; ++p) {
1395:     PetscInt dof;

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

1399:     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1400:   }
1401:   PetscSectionSetUp(mesh->supportSection);
1402:   /* Calculate supports */
1403:   PetscSectionGetStorageSize(mesh->supportSection, &supportSize);
1404:   PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);
1405:   PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);
1406:   PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));
1407:   for (p = pStart; p < pEnd; ++p) {
1408:     PetscInt dof, off, c;

1410:     PetscSectionGetDof(mesh->coneSection, p, &dof);
1411:     PetscSectionGetOffset(mesh->coneSection, p, &off);
1412:     for (c = off; c < off+dof; ++c) {
1413:       const PetscInt q = mesh->cones[c];
1414:       PetscInt       offS;

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

1418:       mesh->supports[offS+offsets[q]] = p;
1419:       ++offsets[q];
1420:     }
1421:   }
1422:   PetscFree(offsets);
1423:   return(0);
1424: }

1428: PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1429: {
1430:   PetscInt       d;

1434:   DMPlexGetLabelValue(dm, "depth", p, &d);
1435:   if (d < 0) {
1436:     /* We are guaranteed that the point has a cone since the depth was not yet set */
1437:     const PetscInt *cone = NULL;
1438:     PetscInt        dCone;

1440:     DMPlexGetCone(dm, p, &cone);
1441:     DMPlexSetDepth_Private(dm, cone[0], &dCone);
1442:     d    = dCone+1;
1443:     DMPlexSetLabelValue(dm, "depth", p, d);
1444:   }
1445:   *depth = d;
1446:   return(0);
1447: }

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

1457:   Not collective

1459:   Input Parameter:
1460: . mesh - The DMPlex

1462:   Output Parameter:

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

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

1470:   Level: beginner

1472: .seealso: DMPlexCreate(), DMPlexSymmetrize()
1473: @*/
1474: PetscErrorCode DMPlexStratify(DM dm)
1475: {
1476:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1477:   PetscInt       pStart, pEnd, p;
1478:   PetscInt       numRoots = 0, numLeaves = 0;

1483:   PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);
1484:   /* Calculate depth */
1485:   PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);
1486:   /* Initialize roots and count leaves */
1487:   for (p = pStart; p < pEnd; ++p) {
1488:     PetscInt coneSize, supportSize;

1490:     DMPlexGetConeSize(dm, p, &coneSize);
1491:     DMPlexGetSupportSize(dm, p, &supportSize);
1492:     if (!coneSize && supportSize) {
1493:       ++numRoots;
1494:       DMPlexSetLabelValue(dm, "depth", p, 0);
1495:     } else if (!supportSize && coneSize) {
1496:       ++numLeaves;
1497:     } else if (!supportSize && !coneSize) {
1498:       /* Isolated points */
1499:       DMPlexSetLabelValue(dm, "depth", p, 0);
1500:     }
1501:   }
1502:   if (numRoots + numLeaves == (pEnd - pStart)) {
1503:     for (p = pStart; p < pEnd; ++p) {
1504:       PetscInt coneSize, supportSize;

1506:       DMPlexGetConeSize(dm, p, &coneSize);
1507:       DMPlexGetSupportSize(dm, p, &supportSize);
1508:       if (!supportSize && coneSize) {
1509:         DMPlexSetLabelValue(dm, "depth", p, 1);
1510:       }
1511:     }
1512:   } else {
1513:     /* This might be slow since lookup is not fast */
1514:     for (p = pStart; p < pEnd; ++p) {
1515:       PetscInt depth;

1517:       DMPlexSetDepth_Private(dm, p, &depth);
1518:     }
1519:   }
1520:   PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);
1521:   return(0);
1522: }

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

1529:   Not Collective

1531:   Input Parameters:
1532: + dm - The DMPlex object
1533: . numPoints - The number of input points for the join
1534: - points - The input points

1536:   Output Parameters:
1537: + numCoveredPoints - The number of points in the join
1538: - coveredPoints - The points in the join

1540:   Level: intermediate

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

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

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

1550: .keywords: mesh
1551: .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1552: @*/
1553: PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1554: {
1555:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1556:   PetscInt      *join[2];
1557:   PetscInt       joinSize, i = 0;
1558:   PetscInt       dof, off, p, c, m;

1566:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);
1567:   DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);
1568:   /* Copy in support of first point */
1569:   PetscSectionGetDof(mesh->supportSection, points[0], &dof);
1570:   PetscSectionGetOffset(mesh->supportSection, points[0], &off);
1571:   for (joinSize = 0; joinSize < dof; ++joinSize) {
1572:     join[i][joinSize] = mesh->supports[off+joinSize];
1573:   }
1574:   /* Check each successive support */
1575:   for (p = 1; p < numPoints; ++p) {
1576:     PetscInt newJoinSize = 0;

1578:     PetscSectionGetDof(mesh->supportSection, points[p], &dof);
1579:     PetscSectionGetOffset(mesh->supportSection, points[p], &off);
1580:     for (c = 0; c < dof; ++c) {
1581:       const PetscInt point = mesh->supports[off+c];

1583:       for (m = 0; m < joinSize; ++m) {
1584:         if (point == join[i][m]) {
1585:           join[1-i][newJoinSize++] = point;
1586:           break;
1587:         }
1588:       }
1589:     }
1590:     joinSize = newJoinSize;
1591:     i        = 1-i;
1592:   }
1593:   *numCoveredPoints = joinSize;
1594:   *coveredPoints    = join[i];
1595:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1596:   return(0);
1597: }

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

1604:   Not Collective

1606:   Input Parameters:
1607: + dm - The DMPlex object
1608: . numPoints - The number of input points for the join
1609: - points - The input points

1611:   Output Parameters:
1612: + numCoveredPoints - The number of points in the join
1613: - coveredPoints - The points in the join

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

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

1621:   Level: intermediate

1623: .keywords: mesh
1624: .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1625: @*/
1626: PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1627: {

1633:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1634:   return(0);
1635: }

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

1642:   Not Collective

1644:   Input Parameters:
1645: + dm - The DMPlex object
1646: . numPoints - The number of input points for the join
1647: - points - The input points

1649:   Output Parameters:
1650: + numCoveredPoints - The number of points in the join
1651: - coveredPoints - The points in the join

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

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

1659:   Level: intermediate

1661: .keywords: mesh
1662: .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1663: @*/
1664: PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1665: {
1666:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1667:   PetscInt      *offsets, **closures;
1668:   PetscInt      *join[2];
1669:   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1670:   PetscInt       p, d, c, m;


1679:   DMPlexGetDepth(dm, &depth);
1680:   PetscMalloc(numPoints * sizeof(PetscInt*), &closures);
1681:   PetscMemzero(closures,numPoints*sizeof(PetscInt*));
1682:   DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1683:   maxSize = PetscPowInt(mesh->maxSupportSize,depth+1);
1684:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);
1685:   DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);

1687:   for (p = 0; p < numPoints; ++p) {
1688:     PetscInt closureSize;

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

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

1696:       DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
1697:       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1698:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1699:           offsets[p*(depth+2)+d+1] = i;
1700:           break;
1701:         }
1702:       }
1703:       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1704:     }
1705:     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);
1706:   }
1707:   for (d = 0; d < depth+1; ++d) {
1708:     PetscInt dof;

1710:     /* Copy in support of first point */
1711:     dof = offsets[d+1] - offsets[d];
1712:     for (joinSize = 0; joinSize < dof; ++joinSize) {
1713:       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1714:     }
1715:     /* Check each successive cone */
1716:     for (p = 1; p < numPoints && joinSize; ++p) {
1717:       PetscInt newJoinSize = 0;

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

1723:         for (m = 0; m < joinSize; ++m) {
1724:           if (point == join[i][m]) {
1725:             join[1-i][newJoinSize++] = point;
1726:             break;
1727:           }
1728:         }
1729:       }
1730:       joinSize = newJoinSize;
1731:       i        = 1-i;
1732:     }
1733:     if (joinSize) break;
1734:   }
1735:   *numCoveredPoints = joinSize;
1736:   *coveredPoints    = join[i];
1737:   for (p = 0; p < numPoints; ++p) {
1738:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);
1739:   }
1740:   PetscFree(closures);
1741:   DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);
1742:   DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);
1743:   return(0);
1744: }

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

1751:   Not Collective

1753:   Input Parameters:
1754: + dm - The DMPlex object
1755: . numPoints - The number of input points for the meet
1756: - points - The input points

1758:   Output Parameters:
1759: + numCoveredPoints - The number of points in the meet
1760: - coveredPoints - The points in the meet

1762:   Level: intermediate

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

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

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

1772: .keywords: mesh
1773: .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1774: @*/
1775: PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1776: {
1777:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1778:   PetscInt      *meet[2];
1779:   PetscInt       meetSize, i = 0;
1780:   PetscInt       dof, off, p, c, m;

1788:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);
1789:   DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);
1790:   /* Copy in cone of first point */
1791:   PetscSectionGetDof(mesh->coneSection, points[0], &dof);
1792:   PetscSectionGetOffset(mesh->coneSection, points[0], &off);
1793:   for (meetSize = 0; meetSize < dof; ++meetSize) {
1794:     meet[i][meetSize] = mesh->cones[off+meetSize];
1795:   }
1796:   /* Check each successive cone */
1797:   for (p = 1; p < numPoints; ++p) {
1798:     PetscInt newMeetSize = 0;

1800:     PetscSectionGetDof(mesh->coneSection, points[p], &dof);
1801:     PetscSectionGetOffset(mesh->coneSection, points[p], &off);
1802:     for (c = 0; c < dof; ++c) {
1803:       const PetscInt point = mesh->cones[off+c];

1805:       for (m = 0; m < meetSize; ++m) {
1806:         if (point == meet[i][m]) {
1807:           meet[1-i][newMeetSize++] = point;
1808:           break;
1809:         }
1810:       }
1811:     }
1812:     meetSize = newMeetSize;
1813:     i        = 1-i;
1814:   }
1815:   *numCoveringPoints = meetSize;
1816:   *coveringPoints    = meet[i];
1817:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
1818:   return(0);
1819: }

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

1826:   Not Collective

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

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

1837:   Level: intermediate

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

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

1845: .keywords: mesh
1846: .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1847: @*/
1848: PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1849: {

1855:   DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);
1856:   return(0);
1857: }

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

1864:   Not Collective

1866:   Input Parameters:
1867: + dm - The DMPlex object
1868: . numPoints - The number of input points for the meet
1869: - points - The input points

1871:   Output Parameters:
1872: + numCoveredPoints - The number of points in the meet
1873: - coveredPoints - The points in the meet

1875:   Level: intermediate

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

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

1883: .keywords: mesh
1884: .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1885: @*/
1886: PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1887: {
1888:   DM_Plex       *mesh = (DM_Plex*) dm->data;
1889:   PetscInt      *offsets, **closures;
1890:   PetscInt      *meet[2];
1891:   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1892:   PetscInt       p, h, c, m;


1901:   DMPlexGetDepth(dm, &height);
1902:   PetscMalloc(numPoints * sizeof(PetscInt*), &closures);
1903:   DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
1904:   maxSize = PetscPowInt(mesh->maxConeSize,height+1);
1905:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);
1906:   DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);

1908:   for (p = 0; p < numPoints; ++p) {
1909:     PetscInt closureSize;

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

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

1917:       DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);
1918:       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1919:         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1920:           offsets[p*(height+2)+h+1] = i;
1921:           break;
1922:         }
1923:       }
1924:       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1925:     }
1926:     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);
1927:   }
1928:   for (h = 0; h < height+1; ++h) {
1929:     PetscInt dof;

1931:     /* Copy in cone of first point */
1932:     dof = offsets[h+1] - offsets[h];
1933:     for (meetSize = 0; meetSize < dof; ++meetSize) {
1934:       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1935:     }
1936:     /* Check each successive cone */
1937:     for (p = 1; p < numPoints && meetSize; ++p) {
1938:       PetscInt newMeetSize = 0;

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

1944:         for (m = 0; m < meetSize; ++m) {
1945:           if (point == meet[i][m]) {
1946:             meet[1-i][newMeetSize++] = point;
1947:             break;
1948:           }
1949:         }
1950:       }
1951:       meetSize = newMeetSize;
1952:       i        = 1-i;
1953:     }
1954:     if (meetSize) break;
1955:   }
1956:   *numCoveredPoints = meetSize;
1957:   *coveredPoints    = meet[i];
1958:   for (p = 0; p < numPoints; ++p) {
1959:     DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);
1960:   }
1961:   PetscFree(closures);
1962:   DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);
1963:   DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);
1964:   return(0);
1965: }

1969: PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1970: {
1971:   MPI_Comm       comm;

1975:   PetscObjectGetComm((PetscObject)dm,&comm);
1977:   switch (cellDim) {
1978:   case 0:
1979:     *numFaceVertices = 0;
1980:     break;
1981:   case 1:
1982:     *numFaceVertices = 1;
1983:     break;
1984:   case 2:
1985:     switch (numCorners) {
1986:     case 3: /* triangle */
1987:       *numFaceVertices = 2; /* Edge has 2 vertices */
1988:       break;
1989:     case 4: /* quadrilateral */
1990:       *numFaceVertices = 2; /* Edge has 2 vertices */
1991:       break;
1992:     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1993:       *numFaceVertices = 3; /* Edge has 3 vertices */
1994:       break;
1995:     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1996:       *numFaceVertices = 3; /* Edge has 3 vertices */
1997:       break;
1998:     default:
1999:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2000:     }
2001:     break;
2002:   case 3:
2003:     switch (numCorners) {
2004:     case 4: /* tetradehdron */
2005:       *numFaceVertices = 3; /* Face has 3 vertices */
2006:       break;
2007:     case 6: /* tet cohesive cells */
2008:       *numFaceVertices = 4; /* Face has 4 vertices */
2009:       break;
2010:     case 8: /* hexahedron */
2011:       *numFaceVertices = 4; /* Face has 4 vertices */
2012:       break;
2013:     case 9: /* tet cohesive Lagrange cells */
2014:       *numFaceVertices = 6; /* Face has 6 vertices */
2015:       break;
2016:     case 10: /* quadratic tetrahedron */
2017:       *numFaceVertices = 6; /* Face has 6 vertices */
2018:       break;
2019:     case 12: /* hex cohesive Lagrange cells */
2020:       *numFaceVertices = 6; /* Face has 6 vertices */
2021:       break;
2022:     case 18: /* quadratic tet cohesive Lagrange cells */
2023:       *numFaceVertices = 6; /* Face has 6 vertices */
2024:       break;
2025:     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2026:       *numFaceVertices = 9; /* Face has 9 vertices */
2027:       break;
2028:     default:
2029:       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2030:     }
2031:     break;
2032:   default:
2033:     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2034:   }
2035:   return(0);
2036: }

2040: /* Trys to give the mesh a consistent orientation */
2041: PetscErrorCode DMPlexOrient(DM dm)
2042: {
2043:   PetscBT        seenCells, flippedCells, seenFaces;
2044:   PetscInt      *faceFIFO, fTop, fBottom;
2045:   PetscInt       dim, h, cStart, cEnd, c, fStart, fEnd, face, maxConeSize, *revcone, *revconeO;

2049:   /* Truth Table
2050:      mismatch    flips   do action   mismatch   flipA ^ flipB   action
2051:          F       0 flips     no         F             F           F
2052:          F       1 flip      yes        F             T           T
2053:          F       2 flips     no         T             F           T
2054:          T       0 flips     yes        T             T           F
2055:          T       1 flip      no
2056:          T       2 flips     yes
2057:   */
2058:   DMPlexGetDimension(dm, &dim);
2059:   DMPlexGetVTKCellHeight(dm, &h);
2060:   DMPlexGetHeightStratum(dm, h,   &cStart, &cEnd);
2061:   DMPlexGetHeightStratum(dm, h+1, &fStart, &fEnd);
2062:   PetscBTCreate(cEnd - cStart, &seenCells);
2063:   PetscBTMemzero(cEnd - cStart, seenCells);
2064:   PetscBTCreate(cEnd - cStart, &flippedCells);
2065:   PetscBTMemzero(cEnd - cStart, flippedCells);
2066:   PetscBTCreate(fEnd - fStart, &seenFaces);
2067:   PetscBTMemzero(fEnd - fStart, seenFaces);
2068:   PetscMalloc((fEnd - fStart) * sizeof(PetscInt), &faceFIFO);
2069:   fTop = fBottom = 0;
2070:   /* Initialize FIFO with first cell */
2071:   {
2072:     const PetscInt *cone;
2073:     PetscInt        coneSize;

2075:     DMPlexGetConeSize(dm, cStart, &coneSize);
2076:     DMPlexGetCone(dm, cStart, &cone);
2077:     for (c = 0; c < coneSize; ++c) {
2078:       faceFIFO[fBottom++] = cone[c];
2079:       PetscBTSet(seenFaces, cone[c]-fStart);
2080:     }
2081:   }
2082:   /* Consider each face in FIFO */
2083:   while (fTop < fBottom) {
2084:     const PetscInt *support, *coneA, *coneB, *coneOA, *coneOB;
2085:     PetscInt        supportSize, coneSizeA, coneSizeB, posA = -1, posB = -1;
2086:     PetscInt        seenA, flippedA, seenB, flippedB, mismatch;

2088:     face = faceFIFO[fTop++];
2089:     DMPlexGetSupportSize(dm, face, &supportSize);
2090:     DMPlexGetSupport(dm, face, &support);
2091:     if (supportSize < 2) continue;
2092:     if (supportSize != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Faces should separate only two cells, not %d", supportSize);
2093:     seenA    = PetscBTLookup(seenCells,    support[0]-cStart);
2094:     flippedA = PetscBTLookup(flippedCells, support[0]-cStart);
2095:     seenB    = PetscBTLookup(seenCells,    support[1]-cStart);
2096:     flippedB = PetscBTLookup(flippedCells, support[1]-cStart);

2098:     DMPlexGetConeSize(dm, support[0], &coneSizeA);
2099:     DMPlexGetConeSize(dm, support[1], &coneSizeB);
2100:     DMPlexGetCone(dm, support[0], &coneA);
2101:     DMPlexGetCone(dm, support[1], &coneB);
2102:     DMPlexGetConeOrientation(dm, support[0], &coneOA);
2103:     DMPlexGetConeOrientation(dm, support[1], &coneOB);
2104:     for (c = 0; c < coneSizeA; ++c) {
2105:       if (!PetscBTLookup(seenFaces, coneA[c]-fStart)) {
2106:         faceFIFO[fBottom++] = coneA[c];
2107:         PetscBTSet(seenFaces, coneA[c]-fStart);
2108:       }
2109:       if (coneA[c] == face) posA = c;
2110:       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2111:     }
2112:     if (posA < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[0]);
2113:     for (c = 0; c < coneSizeB; ++c) {
2114:       if (!PetscBTLookup(seenFaces, coneB[c]-fStart)) {
2115:         faceFIFO[fBottom++] = coneB[c];
2116:         PetscBTSet(seenFaces, coneB[c]-fStart);
2117:       }
2118:       if (coneB[c] == face) posB = c;
2119:       if (fBottom > fEnd-fStart) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Face %d was pushed exceeding capacity %d > %d", coneA[c], fBottom, fEnd-fStart);
2120:     }
2121:     if (posB < 0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d could not be located in cell %d", face, support[1]);

2123:     if (dim == 1) {
2124:       mismatch = posA == posB;
2125:     } else {
2126:       mismatch = coneOA[posA] == coneOB[posB];
2127:     }

2129:     if (mismatch ^ (flippedA ^ flippedB)) {
2130:       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]);
2131:       if (!seenA && !flippedA) {
2132:         PetscBTSet(flippedCells, support[0]-cStart);
2133:       } else if (!seenB && !flippedB) {
2134:         PetscBTSet(flippedCells, support[1]-cStart);
2135:       } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent mesh orientation: Fault mesh is non-orientable");
2136:     } else if (flippedA && flippedB) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Attempt to flip already flipped cell: Fault mesh is non-orientable");
2137:     PetscBTSet(seenCells, support[0]-cStart);
2138:     PetscBTSet(seenCells, support[1]-cStart);
2139:   }

2141:   DMPlexGetMaxSizes(dm, &maxConeSize, NULL);
2142:   DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2143:   DMGetWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2144:   for (c = cStart; c < cEnd; ++c) {
2145:     const PetscInt *cone, *coneO;
2146:     PetscInt        coneSize, faceSize, cp;

2148:     if (!PetscBTLookup(flippedCells, c-cStart)) continue;
2149:     DMPlexGetConeSize(dm, c, &coneSize);
2150:     DMPlexGetCone(dm, c, &cone);
2151:     DMPlexGetConeOrientation(dm, c, &coneO);
2152:     for (cp = 0; cp < coneSize; ++cp) {
2153:       const PetscInt rcp = coneSize-cp-1;

2155:       DMPlexGetConeSize(dm, cone[rcp], &faceSize);
2156:       revcone[cp]  = cone[rcp];
2157:       revconeO[cp] = coneO[rcp] >= 0 ? -(faceSize-coneO[rcp]) : faceSize+coneO[rcp];
2158:     }
2159:     DMPlexSetCone(dm, c, revcone);
2160:     DMPlexSetConeOrientation(dm, c, revconeO);
2161:   }
2162:   DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revcone);
2163:   DMRestoreWorkArray(dm, maxConeSize, PETSC_INT, &revconeO);
2164:   PetscBTDestroy(&seenCells);
2165:   PetscBTDestroy(&flippedCells);
2166:   PetscBTDestroy(&seenFaces);
2167:   PetscFree(faceFIFO);
2168:   return(0);
2169: }

2173: static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2174: {
2175:   const PetscInt *support = NULL;
2176:   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2177:   PetscErrorCode  ierr;

2180:   if (useClosure) {
2181:     DMPlexGetConeSize(dm, p, &supportSize);
2182:     DMPlexGetCone(dm, p, &support);
2183:     for (s = 0; s < supportSize; ++s) {
2184:       const PetscInt *cone = NULL;
2185:       PetscInt        coneSize, c, q;

2187:       DMPlexGetSupportSize(dm, support[s], &coneSize);
2188:       DMPlexGetSupport(dm, support[s], &cone);
2189:       for (c = 0; c < coneSize; ++c) {
2190:         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2191:           if (cone[c] == adj[q]) break;
2192:         }
2193:         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2194:       }
2195:     }
2196:   } else {
2197:     DMPlexGetSupportSize(dm, p, &supportSize);
2198:     DMPlexGetSupport(dm, p, &support);
2199:     for (s = 0; s < supportSize; ++s) {
2200:       const PetscInt *cone = NULL;
2201:       PetscInt        coneSize, c, q;

2203:       DMPlexGetConeSize(dm, support[s], &coneSize);
2204:       DMPlexGetCone(dm, support[s], &cone);
2205:       for (c = 0; c < coneSize; ++c) {
2206:         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2207:           if (cone[c] == adj[q]) break;
2208:         }
2209:         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2210:       }
2211:     }
2212:   }
2213:   *adjSize = numAdj;
2214:   return(0);
2215: }

2219: PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2220: {
2221:   const PetscInt maxFaceCases = 30;
2222:   PetscInt       numFaceCases = 0;
2223:   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2224:   PetscInt      *off, *adj;
2225:   PetscInt      *neighborCells, *tmpClosure;
2226:   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2227:   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;

2231:   /* For parallel partitioning, I think you have to communicate supports */
2232:   DMPlexGetDimension(dm, &dim);
2233:   cellDim = dim - cellHeight;
2234:   DMPlexGetDepth(dm, &depth);
2235:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
2236:   DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);
2237:   if (cEnd - cStart == 0) {
2238:     if (numVertices) *numVertices = 0;
2239:     if (offsets)   *offsets   = NULL;
2240:     if (adjacency) *adjacency = NULL;
2241:     return(0);
2242:   }
2243:   numCells  = cEnd - cStart;
2244:   faceDepth = depth - cellHeight;
2245:   /* Setup face recognition */
2246:   if (faceDepth == 1) {
2247:     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 */

2249:     for (c = cStart; c < cEnd; ++c) {
2250:       PetscInt corners;

2252:       DMPlexGetConeSize(dm, c, &corners);
2253:       if (!cornersSeen[corners]) {
2254:         PetscInt nFV;

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

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

2261:         numFaceVertices[numFaceCases++] = nFV;
2262:       }
2263:     }
2264:   }
2265:   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth+1),PetscPowInt(maxSupportSize,depth+1));
2266:   maxNeighbors = PetscPowInt(maxConeSize,depth+1)*PetscPowInt(maxSupportSize,depth+1);
2267:   PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);
2268:   PetscMalloc((numCells+1) * sizeof(PetscInt), &off);
2269:   PetscMemzero(off, (numCells+1) * sizeof(PetscInt));
2270:   /* Count neighboring cells */
2271:   for (cell = cStart; cell < cEnd; ++cell) {
2272:     PetscInt numNeighbors = maxNeighbors, n;

2274:     DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2275:     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2276:     for (n = 0; n < numNeighbors; ++n) {
2277:       PetscInt        cellPair[2];
2278:       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2279:       PetscInt        meetSize = 0;
2280:       const PetscInt *meet    = NULL;

2282:       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2283:       if (cellPair[0] == cellPair[1]) continue;
2284:       if (!found) {
2285:         DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2286:         if (meetSize) {
2287:           PetscInt f;

2289:           for (f = 0; f < numFaceCases; ++f) {
2290:             if (numFaceVertices[f] == meetSize) {
2291:               found = PETSC_TRUE;
2292:               break;
2293:             }
2294:           }
2295:         }
2296:         DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2297:       }
2298:       if (found) ++off[cell-cStart+1];
2299:     }
2300:   }
2301:   /* Prefix sum */
2302:   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];

2304:   if (adjacency) {
2305:     PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);
2306:     /* Get neighboring cells */
2307:     for (cell = cStart; cell < cEnd; ++cell) {
2308:       PetscInt numNeighbors = maxNeighbors, n;
2309:       PetscInt cellOffset   = 0;

2311:       DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);
2312:       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2313:       for (n = 0; n < numNeighbors; ++n) {
2314:         PetscInt        cellPair[2];
2315:         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2316:         PetscInt        meetSize = 0;
2317:         const PetscInt *meet    = NULL;

2319:         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2320:         if (cellPair[0] == cellPair[1]) continue;
2321:         if (!found) {
2322:           DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);
2323:           if (meetSize) {
2324:             PetscInt f;

2326:             for (f = 0; f < numFaceCases; ++f) {
2327:               if (numFaceVertices[f] == meetSize) {
2328:                 found = PETSC_TRUE;
2329:                 break;
2330:               }
2331:             }
2332:           }
2333:           DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);
2334:         }
2335:         if (found) {
2336:           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2337:           ++cellOffset;
2338:         }
2339:       }
2340:     }
2341:   }
2342:   PetscFree2(neighborCells,tmpClosure);
2343:   if (numVertices) *numVertices = numCells;
2344:   if (offsets)   *offsets   = off;
2345:   if (adjacency) *adjacency = adj;
2346:   return(0);
2347: }

2349: #if defined(PETSC_HAVE_CHACO)
2350: #if defined(PETSC_HAVE_UNISTD_H)
2351: #include <unistd.h>
2352: #endif
2353: /* Chaco does not have an include file */
2354: PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2355:                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2356:                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2357:                        int mesh_dims[3], double *goal, int global_method, int local_method,
2358:                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);

2360: extern int FREE_GRAPH;

2364: PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2365: {
2366:   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2367:   MPI_Comm       comm;
2368:   int            nvtxs          = numVertices; /* number of vertices in full graph */
2369:   int           *vwgts          = NULL;   /* weights for all vertices */
2370:   float         *ewgts          = NULL;   /* weights for all edges */
2371:   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2372:   char          *outassignname  = NULL;   /*  name of assignment output file */
2373:   char          *outfilename    = NULL;   /* output file name */
2374:   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2375:   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2376:   int            mesh_dims[3];            /* dimensions of mesh of processors */
2377:   double        *goal          = NULL;    /* desired set sizes for each set */
2378:   int            global_method = 1;       /* global partitioning algorithm */
2379:   int            local_method  = 1;       /* local partitioning algorithm */
2380:   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2381:   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2382:   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2383:   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2384:   long           seed          = 123636512; /* for random graph mutations */
2385:   short int     *assignment;              /* Output partition */
2386:   int            fd_stdout, fd_pipe[2];
2387:   PetscInt      *points;
2388:   PetscMPIInt    commSize;
2389:   int            i, v, p;

2393:   PetscObjectGetComm((PetscObject)dm,&comm);
2394:   MPI_Comm_size(comm, &commSize);
2395:   if (!numVertices) {
2396:     PetscSectionCreate(comm, partSection);
2397:     PetscSectionSetChart(*partSection, 0, commSize);
2398:     PetscSectionSetUp(*partSection);
2399:     ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);
2400:     return(0);
2401:   }
2402:   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2403:   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];

2405:   if (global_method == INERTIAL_METHOD) {
2406:     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2407:     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2408:   }
2409:   mesh_dims[0] = commSize;
2410:   mesh_dims[1] = 1;
2411:   mesh_dims[2] = 1;
2412:   PetscMalloc(nvtxs * sizeof(short int), &assignment);
2413:   /* Chaco outputs to stdout. We redirect this to a buffer. */
2414:   /* TODO: check error codes for UNIX calls */
2415: #if defined(PETSC_HAVE_UNISTD_H)
2416:   {
2417:     int piperet;
2418:     piperet = pipe(fd_pipe);
2419:     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2420:     fd_stdout = dup(1);
2421:     close(1);
2422:     dup2(fd_pipe[1], 1);
2423:   }
2424: #endif
2425:   interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2426:                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2427:                    vmax, ndims, eigtol, seed);
2428: #if defined(PETSC_HAVE_UNISTD_H)
2429:   {
2430:     char msgLog[10000];
2431:     int  count;

2433:     fflush(stdout);
2434:     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2435:     if (count < 0) count = 0;
2436:     msgLog[count] = 0;
2437:     close(1);
2438:     dup2(fd_stdout, 1);
2439:     close(fd_stdout);
2440:     close(fd_pipe[0]);
2441:     close(fd_pipe[1]);
2442:     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2443:   }
2444: #endif
2445:   /* Convert to PetscSection+IS */
2446:   PetscSectionCreate(comm, partSection);
2447:   PetscSectionSetChart(*partSection, 0, commSize);
2448:   for (v = 0; v < nvtxs; ++v) {
2449:     PetscSectionAddDof(*partSection, assignment[v], 1);
2450:   }
2451:   PetscSectionSetUp(*partSection);
2452:   PetscMalloc(nvtxs * sizeof(PetscInt), &points);
2453:   for (p = 0, i = 0; p < commSize; ++p) {
2454:     for (v = 0; v < nvtxs; ++v) {
2455:       if (assignment[v] == p) points[i++] = v;
2456:     }
2457:   }
2458:   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2459:   ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);
2460:   if (global_method == INERTIAL_METHOD) {
2461:     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2462:   }
2463:   PetscFree(assignment);
2464:   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2465:   return(0);
2466: }
2467: #endif

2469: #if defined(PETSC_HAVE_PARMETIS)
2472: PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2473: {
2475:   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2476:   return(0);
2477: }
2478: #endif

2482: /* Expand the partition by BFS on the adjacency graph */
2483: PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2484: {
2485:   PetscHashI      h;
2486:   const PetscInt *points;
2487:   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2488:   PetscInt        pStart, pEnd, part, q;
2489:   PetscErrorCode  ierr;

2492:   PetscHashICreate(h);
2493:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2494:   PetscSectionGetChart(origPartSection, &pStart, &pEnd);
2495:   PetscSectionSetChart(*partSection, pStart, pEnd);
2496:   ISGetIndices(origPartition, &points);
2497:   PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);
2498:   for (part = pStart; part < pEnd; ++part) {
2499:     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;

2501:     PetscHashIClear(h);
2502:     PetscSectionGetDof(origPartSection, part, &numPoints);
2503:     PetscSectionGetOffset(origPartSection, part, &off);
2504:     /* Add all existing points to h */
2505:     for (p = 0; p < numPoints; ++p) {
2506:       const PetscInt point = points[off+p];
2507:       PetscHashIAdd(h, point, 1);
2508:     }
2509:     PetscHashISize(h, nP);
2510:     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2511:     /* Add all points in next BFS level */
2512:     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2513:     for (p = 0; p < numPoints; ++p) {
2514:       const PetscInt point = points[off+p];
2515:       PetscInt       s     = start[point], e = start[point+1], a;

2517:       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2518:     }
2519:     PetscHashISize(h, numNewPoints);
2520:     PetscSectionSetDof(*partSection, part, numNewPoints);
2521:     PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);
2522:     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2523:     totPoints += numNewPoints;
2524:   }
2525:   ISRestoreIndices(origPartition, &points);
2526:   PetscHashIDestroy(h);
2527:   PetscSectionSetUp(*partSection);
2528:   PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);
2529:   for (part = pStart, q = 0; part < pEnd; ++part) {
2530:     PetscInt numPoints, p;

2532:     PetscSectionGetDof(*partSection, part, &numPoints);
2533:     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2534:     PetscFree(tmpPoints[part]);
2535:   }
2536:   PetscFree(tmpPoints);
2537:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);
2538:   return(0);
2539: }

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

2546:   Collective on DM

2548:   Input Parameters:
2549:   + dm - The DM
2550:   . height - The height for points in the partition
2551:   - enlarge - Expand each partition with neighbors

2553:   Output Parameters:
2554:   + partSection - The PetscSection giving the division of points by partition
2555:   . partition - The list of points by partition
2556:   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2557:   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL

2559:   Level: developer

2561: .seealso DMPlexDistribute()
2562: */
2563: PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2564: {
2565:   PetscMPIInt    size;

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

2571:   *origPartSection = NULL;
2572:   *origPartition   = NULL;
2573:   if (size == 1) {
2574:     PetscInt *points;
2575:     PetscInt  cStart, cEnd, c;

2577:     DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
2578:     PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);
2579:     PetscSectionSetChart(*partSection, 0, size);
2580:     PetscSectionSetDof(*partSection, 0, cEnd-cStart);
2581:     PetscSectionSetUp(*partSection);
2582:     PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);
2583:     for (c = cStart; c < cEnd; ++c) points[c] = c;
2584:     ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);
2585:     return(0);
2586:   }
2587:   if (height == 0) {
2588:     PetscInt  numVertices;
2589:     PetscInt *start     = NULL;
2590:     PetscInt *adjacency = NULL;

2592:     DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);
2593:     if (1) {
2594: #if defined(PETSC_HAVE_CHACO)
2595:       DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);
2596: #endif
2597:     } else {
2598: #if defined(PETSC_HAVE_PARMETIS)
2599:       DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);
2600: #endif
2601:     }
2602:     if (enlarge) {
2603:       *origPartSection = *partSection;
2604:       *origPartition   = *partition;

2606:       DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);
2607:     }
2608:     PetscFree(start);
2609:     PetscFree(adjacency);
2610: # if 0
2611:   } else if (height == 1) {
2612:     /* Build the dual graph for faces and partition the hypergraph */
2613:     PetscInt numEdges;

2615:     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2616:     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2617:     destroyCSR(numEdges, start, adjacency);
2618: #endif
2619:   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2620:   return(0);
2621: }

2625: PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2626: {
2627:   /* const PetscInt  height = 0; */
2628:   const PetscInt *partArray;
2629:   PetscInt       *allPoints, *packPoints;
2630:   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
2631:   PetscErrorCode  ierr;
2632:   PetscBT         bt;
2633:   PetscSegBuffer  segpack,segpart;

2636:   PetscSectionGetChart(pointSection, &rStart, &rEnd);
2637:   ISGetIndices(pointPartition, &partArray);
2638:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
2639:   PetscSectionSetChart(*section, rStart, rEnd);
2640:   DMPlexGetChart(dm,&pStart,&pEnd);
2641:   PetscBTCreate(pEnd-pStart,&bt);
2642:   PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);
2643:   PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);
2644:   for (rank = rStart; rank < rEnd; ++rank) {
2645:     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;

2647:     PetscSectionGetDof(pointSection, rank, &numPoints);
2648:     PetscSectionGetOffset(pointSection, rank, &offset);
2649:     for (p = 0; p < numPoints; ++p) {
2650:       PetscInt  point   = partArray[offset+p], closureSize, c;
2651:       PetscInt *closure = NULL;

2653:       /* TODO Include support for height > 0 case */
2654:       DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2655:       for (c=0; c<closureSize; c++) {
2656:         PetscInt cpoint = closure[c*2];
2657:         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
2658:           PetscInt *PETSC_RESTRICT pt;
2659:           partSize++;
2660:           PetscSegBufferGetInts(segpart,1,&pt);
2661:           *pt = cpoint;
2662:         }
2663:       }
2664:       DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);
2665:     }
2666:     PetscSectionSetDof(*section, rank, partSize);
2667:     PetscSegBufferGetInts(segpack,partSize,&placePoints);
2668:     PetscSegBufferExtractTo(segpart,placePoints);
2669:     PetscSortInt(partSize,placePoints);
2670:     for (p=0; p<partSize; p++) {PetscBTClear(bt,placePoints[p]-pStart);}
2671:   }
2672:   PetscBTDestroy(&bt);
2673:   PetscSegBufferDestroy(&segpart);

2675:   PetscSectionSetUp(*section);
2676:   PetscSectionGetStorageSize(*section, &newSize);
2677:   PetscMalloc(newSize * sizeof(PetscInt), &allPoints);

2679:   PetscSegBufferExtractInPlace(segpack,&packPoints);
2680:   for (rank = rStart; rank < rEnd; ++rank) {
2681:     PetscInt numPoints, offset;

2683:     PetscSectionGetDof(*section, rank, &numPoints);
2684:     PetscSectionGetOffset(*section, rank, &offset);
2685:     PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));
2686:     packPoints += numPoints;
2687:   }

2689:   PetscSegBufferDestroy(&segpack);
2690:   ISRestoreIndices(pointPartition, &partArray);
2691:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);
2692:   return(0);
2693: }

2697: /*
2698:   Input Parameters:
2699: . originalSection
2700: , originalVec

2702:   Output Parameters:
2703: . newSection
2704: . newVec
2705: */
2706: PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2707: {
2708:   PetscSF        fieldSF;
2709:   PetscInt      *remoteOffsets, fieldSize;
2710:   PetscScalar   *originalValues, *newValues;

2714:   PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);

2716:   PetscSectionGetStorageSize(newSection, &fieldSize);
2717:   VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);
2718:   VecSetFromOptions(newVec);

2720:   VecGetArray(originalVec, &originalValues);
2721:   VecGetArray(newVec, &newValues);
2722:   PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);
2723:   PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);
2724:   PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);
2725:   PetscSFDestroy(&fieldSF);
2726:   VecRestoreArray(newVec, &newValues);
2727:   VecRestoreArray(originalVec, &originalValues);
2728:   return(0);
2729: }

2733: /*@C
2734:   DMPlexDistribute - Distributes the mesh and any associated sections.

2736:   Not Collective

2738:   Input Parameter:
2739: + dm  - The original DMPlex object
2740: . partitioner - The partitioning package, or NULL for the default
2741: - overlap - The overlap of partitions, 0 is the default

2743:   Output Parameter:
2744: . parallelMesh - The distributed DMPlex object, or NULL

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

2748:   Level: intermediate

2750: .keywords: mesh, elements
2751: .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2752: @*/
2753: PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2754: {
2755:   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2756:   MPI_Comm               comm;
2757:   const PetscInt         height = 0;
2758:   PetscInt               dim, numRemoteRanks;
2759:   IS                     origCellPart,        cellPart,        part;
2760:   PetscSection           origCellPartSection, cellPartSection, partSection;
2761:   PetscSFNode           *remoteRanks;
2762:   PetscSF                partSF, pointSF, coneSF;
2763:   ISLocalToGlobalMapping renumbering;
2764:   PetscSection           originalConeSection, newConeSection;
2765:   PetscInt              *remoteOffsets;
2766:   PetscInt              *cones, *newCones, newConesSize;
2767:   PetscBool              flg;
2768:   PetscMPIInt            rank, numProcs, p;
2769:   PetscErrorCode         ierr;


2775:   PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);
2776:   PetscObjectGetComm((PetscObject)dm,&comm);
2777:   MPI_Comm_rank(comm, &rank);
2778:   MPI_Comm_size(comm, &numProcs);

2780:   *dmParallel = NULL;
2781:   if (numProcs == 1) return(0);

2783:   DMPlexGetDimension(dm, &dim);
2784:   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2785:   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2786:   DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);
2787:   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2788:   if (!rank) numRemoteRanks = numProcs;
2789:   else       numRemoteRanks = 0;
2790:   PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);
2791:   for (p = 0; p < numRemoteRanks; ++p) {
2792:     remoteRanks[p].rank  = p;
2793:     remoteRanks[p].index = 0;
2794:   }
2795:   PetscSFCreate(comm, &partSF);
2796:   PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);
2797:   PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);
2798:   if (flg) {
2799:     PetscPrintf(comm, "Cell Partition:\n");
2800:     PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);
2801:     ISView(cellPart, NULL);
2802:     if (origCellPart) {
2803:       PetscPrintf(comm, "Original Cell Partition:\n");
2804:       PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);
2805:       ISView(origCellPart, NULL);
2806:     }
2807:     PetscSFView(partSF, NULL);
2808:   }
2809:   /* Close the partition over the mesh */
2810:   DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);
2811:   ISDestroy(&cellPart);
2812:   PetscSectionDestroy(&cellPartSection);
2813:   /* Create new mesh */
2814:   DMPlexCreate(comm, dmParallel);
2815:   DMPlexSetDimension(*dmParallel, dim);
2816:   PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");
2817:   pmesh = (DM_Plex*) (*dmParallel)->data;
2818:   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2819:   PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);
2820:   if (flg) {
2821:     PetscPrintf(comm, "Point Partition:\n");
2822:     PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);
2823:     ISView(part, NULL);
2824:     PetscSFView(pointSF, NULL);
2825:     PetscPrintf(comm, "Point Renumbering after partition:\n");
2826:     ISLocalToGlobalMappingView(renumbering, NULL);
2827:   }
2828:   /* Distribute cone section */
2829:   DMPlexGetConeSection(dm, &originalConeSection);
2830:   DMPlexGetConeSection(*dmParallel, &newConeSection);
2831:   PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);
2832:   DMSetUp(*dmParallel);
2833:   {
2834:     PetscInt pStart, pEnd, p;

2836:     PetscSectionGetChart(newConeSection, &pStart, &pEnd);
2837:     for (p = pStart; p < pEnd; ++p) {
2838:       PetscInt coneSize;
2839:       PetscSectionGetDof(newConeSection, p, &coneSize);
2840:       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2841:     }
2842:   }
2843:   /* Communicate and renumber cones */
2844:   PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);
2845:   DMPlexGetCones(dm, &cones);
2846:   DMPlexGetCones(*dmParallel, &newCones);
2847:   PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
2848:   PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
2849:   PetscSectionGetStorageSize(newConeSection, &newConesSize);
2850:   ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);
2851:   PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);
2852:   if (flg) {
2853:     PetscPrintf(comm, "Serial Cone Section:\n");
2854:     PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);
2855:     PetscPrintf(comm, "Parallel Cone Section:\n");
2856:     PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);
2857:     PetscSFView(coneSF, NULL);
2858:   }
2859:   DMPlexGetConeOrientations(dm, &cones);
2860:   DMPlexGetConeOrientations(*dmParallel, &newCones);
2861:   PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);
2862:   PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);
2863:   PetscSFDestroy(&coneSF);
2864:   /* Create supports and stratify sieve */
2865:   {
2866:     PetscInt pStart, pEnd;

2868:     PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);
2869:     PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);
2870:   }
2871:   DMPlexSymmetrize(*dmParallel);
2872:   DMPlexStratify(*dmParallel);
2873:   /* Distribute Coordinates */
2874:   {
2875:     PetscSection originalCoordSection, newCoordSection;
2876:     Vec          originalCoordinates, newCoordinates;
2877:     const char  *name;

2879:     DMPlexGetCoordinateSection(dm, &originalCoordSection);
2880:     DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);
2881:     DMGetCoordinatesLocal(dm, &originalCoordinates);
2882:     VecCreate(comm, &newCoordinates);
2883:     PetscObjectGetName((PetscObject) originalCoordinates, &name);
2884:     PetscObjectSetName((PetscObject) newCoordinates, name);

2886:     DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);
2887:     DMSetCoordinatesLocal(*dmParallel, newCoordinates);
2888:     VecDestroy(&newCoordinates);
2889:   }
2890:   /* Distribute labels */
2891:   {
2892:     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2893:     PetscInt numLabels = 0, l;

2895:     /* Bcast number of labels */
2896:     while (next) {
2897:       ++numLabels; next = next->next;
2898:     }
2899:     MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);
2900:     next = mesh->labels;
2901:     for (l = 0; l < numLabels; ++l) {
2902:       DMLabel         newLabel;
2903:       const PetscInt *partArray;
2904:       char           *name;
2905:       PetscInt       *stratumSizes = NULL, *points = NULL;
2906:       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2907:       PetscInt        nameSize, s, p;
2908:       PetscBool       isdepth;
2909:       size_t          len = 0;

2911:       /* Bcast name (could filter for no points) */
2912:       if (!rank) {PetscStrlen(next->name, &len);}
2913:       nameSize = len;
2914:       MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);
2915:       PetscMalloc(nameSize+1, &name);
2916:       if (!rank) {PetscMemcpy(name, next->name, nameSize+1);}
2917:       MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);
2918:       PetscStrcmp(name, "depth", &isdepth);
2919:       if (isdepth) {            /* skip because "depth" is not distributed */
2920:         PetscFree(name);
2921:         if (!rank) next = next->next;
2922:         continue;
2923:       }
2924:       PetscNew(struct _n_DMLabel, &newLabel);
2925:       newLabel->name = name;
2926:       /* Bcast numStrata (could filter for no points in stratum) */
2927:       if (!rank) newLabel->numStrata = next->numStrata;
2928:       MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);
2929:       PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2930:                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2931:                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);
2932:       /* Bcast stratumValues (could filter for no points in stratum) */
2933:       if (!rank) {PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));}
2934:       MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);
2935:       /* Find size on each process and Scatter */
2936:       if (!rank) {
2937:         ISGetIndices(part, &partArray);
2938:         PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);
2939:         PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));
2940:         for (s = 0; s < next->numStrata; ++s) {
2941:           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2942:             const PetscInt point = next->points[p];
2943:             PetscInt       proc;

2945:             for (proc = 0; proc < numProcs; ++proc) {
2946:               PetscInt dof, off, pPart;

2948:               PetscSectionGetDof(partSection, proc, &dof);
2949:               PetscSectionGetOffset(partSection, proc, &off);
2950:               for (pPart = off; pPart < off+dof; ++pPart) {
2951:                 if (partArray[pPart] == point) {
2952:                   ++stratumSizes[proc*next->numStrata+s];
2953:                   break;
2954:                 }
2955:               }
2956:             }
2957:           }
2958:         }
2959:         ISRestoreIndices(part, &partArray);
2960:       }
2961:       MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);
2962:       /* Calculate stratumOffsets */
2963:       newLabel->stratumOffsets[0] = 0;
2964:       for (s = 0; s < newLabel->numStrata; ++s) {
2965:         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2966:       }
2967:       /* Pack points and Scatter */
2968:       if (!rank) {
2969:         PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);
2970:         displs[0] = 0;
2971:         for (p = 0; p < numProcs; ++p) {
2972:           sendcnts[p] = 0;
2973:           for (s = 0; s < next->numStrata; ++s) {
2974:             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2975:           }
2976:           offsets[p]  = displs[p];
2977:           displs[p+1] = displs[p] + sendcnts[p];
2978:         }
2979:         PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);
2980:         for (s = 0; s < next->numStrata; ++s) {
2981:           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2982:             const PetscInt point = next->points[p];
2983:             PetscInt       proc;

2985:             for (proc = 0; proc < numProcs; ++proc) {
2986:               PetscInt dof, off, pPart;

2988:               PetscSectionGetDof(partSection, proc, &dof);
2989:               PetscSectionGetOffset(partSection, proc, &off);
2990:               for (pPart = off; pPart < off+dof; ++pPart) {
2991:                 if (partArray[pPart] == point) {
2992:                   points[offsets[proc]++] = point;
2993:                   break;
2994:                 }
2995:               }
2996:             }
2997:           }
2998:         }
2999:       }
3000:       PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);
3001:       MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);
3002:       PetscFree(points);
3003:       PetscFree3(sendcnts,offsets,displs);
3004:       PetscFree(stratumSizes);
3005:       /* Renumber points */
3006:       ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);
3007:       /* Sort points */
3008:       for (s = 0; s < newLabel->numStrata; ++s) {
3009:         PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);
3010:       }
3011:       /* Insert into list */
3012:       if (newNext) newNext->next = newLabel;
3013:       else pmesh->labels = newLabel;
3014:       newNext = newLabel;
3015:       if (!rank) next = next->next;
3016:     }
3017:   }
3018:   /* Cleanup Partition */
3019:   ISLocalToGlobalMappingDestroy(&renumbering);
3020:   PetscSFDestroy(&partSF);
3021:   PetscSectionDestroy(&partSection);
3022:   ISDestroy(&part);
3023:   /* Create point SF for parallel mesh */
3024:   {
3025:     const PetscInt *leaves;
3026:     PetscSFNode    *remotePoints, *rowners, *lowners;
3027:     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3028:     PetscInt        pStart, pEnd;

3030:     DMPlexGetChart(*dmParallel, &pStart, &pEnd);
3031:     PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);
3032:     PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);
3033:     for (p=0; p<numRoots; p++) {
3034:       rowners[p].rank  = -1;
3035:       rowners[p].index = -1;
3036:     }
3037:     if (origCellPart) {
3038:       /* Make sure cells in the original partition are not assigned to other procs */
3039:       const PetscInt *origCells;

3041:       ISGetIndices(origCellPart, &origCells);
3042:       for (p = 0; p < numProcs; ++p) {
3043:         PetscInt dof, off, d;

3045:         PetscSectionGetDof(origCellPartSection, p, &dof);
3046:         PetscSectionGetOffset(origCellPartSection, p, &off);
3047:         for (d = off; d < off+dof; ++d) {
3048:           rowners[origCells[d]].rank = p;
3049:         }
3050:       }
3051:       ISRestoreIndices(origCellPart, &origCells);
3052:     }
3053:     ISDestroy(&origCellPart);
3054:     PetscSectionDestroy(&origCellPartSection);

3056:     PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3057:     PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3058:     for (p = 0; p < numLeaves; ++p) {
3059:       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3060:         lowners[p].rank  = rank;
3061:         lowners[p].index = leaves ? leaves[p] : p;
3062:       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3063:         lowners[p].rank  = -2;
3064:         lowners[p].index = -2;
3065:       }
3066:     }
3067:     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3068:       rowners[p].rank  = -3;
3069:       rowners[p].index = -3;
3070:     }
3071:     PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3072:     PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);
3073:     PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);
3074:     PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);
3075:     for (p = 0; p < numLeaves; ++p) {
3076:       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3077:       if (lowners[p].rank != rank) ++numGhostPoints;
3078:     }
3079:     PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);
3080:     PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);
3081:     for (p = 0, gp = 0; p < numLeaves; ++p) {
3082:       if (lowners[p].rank != rank) {
3083:         ghostPoints[gp]        = leaves ? leaves[p] : p;
3084:         remotePoints[gp].rank  = lowners[p].rank;
3085:         remotePoints[gp].index = lowners[p].index;
3086:         ++gp;
3087:       }
3088:     }
3089:     PetscFree2(rowners,lowners);
3090:     PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);
3091:     PetscSFSetFromOptions((*dmParallel)->sf);
3092:   }
3093:   /* Cleanup */
3094:   PetscSFDestroy(&pointSF);
3095:   DMSetFromOptions(*dmParallel);
3096:   PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);
3097:   return(0);
3098: }

3102: /* This is to fix the tetrahedron orientation from TetGen */
3103: PETSC_UNUSED static PetscErrorCode DMPlexInvertCells_Internal(PetscInt numCells, PetscInt numCorners, int cells[])
3104: {
3105:   PetscInt c;

3108:   if (numCorners != 4) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot invert cells with %d corners", numCorners);
3109:   for (c = 0; c < numCells; ++c) {
3110:     int *cone = &cells[c*4], tmpc;

3112:     tmpc    = cone[0];
3113:     cone[0] = cone[1];
3114:     cone[1] = tmpc;
3115:   }
3116:   return(0);
3117: }

3119: #if defined(PETSC_HAVE_TRIANGLE)
3120: #include <triangle.h>

3124: PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3125: {
3127:   inputCtx->numberofpoints             = 0;
3128:   inputCtx->numberofpointattributes    = 0;
3129:   inputCtx->pointlist                  = NULL;
3130:   inputCtx->pointattributelist         = NULL;
3131:   inputCtx->pointmarkerlist            = NULL;
3132:   inputCtx->numberofsegments           = 0;
3133:   inputCtx->segmentlist                = NULL;
3134:   inputCtx->segmentmarkerlist          = NULL;
3135:   inputCtx->numberoftriangleattributes = 0;
3136:   inputCtx->trianglelist               = NULL;
3137:   inputCtx->numberofholes              = 0;
3138:   inputCtx->holelist                   = NULL;
3139:   inputCtx->numberofregions            = 0;
3140:   inputCtx->regionlist                 = NULL;
3141:   return(0);
3142: }

3146: PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3147: {
3149:   outputCtx->numberofpoints        = 0;
3150:   outputCtx->pointlist             = NULL;
3151:   outputCtx->pointattributelist    = NULL;
3152:   outputCtx->pointmarkerlist       = NULL;
3153:   outputCtx->numberoftriangles     = 0;
3154:   outputCtx->trianglelist          = NULL;
3155:   outputCtx->triangleattributelist = NULL;
3156:   outputCtx->neighborlist          = NULL;
3157:   outputCtx->segmentlist           = NULL;
3158:   outputCtx->segmentmarkerlist     = NULL;
3159:   outputCtx->numberofedges         = 0;
3160:   outputCtx->edgelist              = NULL;
3161:   outputCtx->edgemarkerlist        = NULL;
3162:   return(0);
3163: }

3167: PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3168: {
3170:   free(outputCtx->pointmarkerlist);
3171:   free(outputCtx->edgelist);
3172:   free(outputCtx->edgemarkerlist);
3173:   free(outputCtx->trianglelist);
3174:   free(outputCtx->neighborlist);
3175:   return(0);
3176: }

3180: PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3181: {
3182:   MPI_Comm             comm;
3183:   PetscInt             dim              = 2;
3184:   const PetscBool      createConvexHull = PETSC_FALSE;
3185:   const PetscBool      constrained      = PETSC_FALSE;
3186:   struct triangulateio in;
3187:   struct triangulateio out;
3188:   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3189:   PetscMPIInt          rank;
3190:   PetscErrorCode       ierr;

3193:   PetscObjectGetComm((PetscObject)boundary,&comm);
3194:   MPI_Comm_rank(comm, &rank);
3195:   InitInput_Triangle(&in);
3196:   InitOutput_Triangle(&out);
3197:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);

3199:   in.numberofpoints = vEnd - vStart;
3200:   if (in.numberofpoints > 0) {
3201:     PetscSection coordSection;
3202:     Vec          coordinates;
3203:     PetscScalar *array;

3205:     PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);
3206:     PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);
3207:     DMGetCoordinatesLocal(boundary, &coordinates);
3208:     DMPlexGetCoordinateSection(boundary, &coordSection);
3209:     VecGetArray(coordinates, &array);
3210:     for (v = vStart; v < vEnd; ++v) {
3211:       const PetscInt idx = v - vStart;
3212:       PetscInt       off, d;

3214:       PetscSectionGetOffset(coordSection, v, &off);
3215:       for (d = 0; d < dim; ++d) {
3216:         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3217:       }
3218:       DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3219:     }
3220:     VecRestoreArray(coordinates, &array);
3221:   }
3222:   DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);
3223:   in.numberofsegments = eEnd - eStart;
3224:   if (in.numberofsegments > 0) {
3225:     PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);
3226:     PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);
3227:     for (e = eStart; e < eEnd; ++e) {
3228:       const PetscInt  idx = e - eStart;
3229:       const PetscInt *cone;

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

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

3236:       DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);
3237:     }
3238:   }
3239: #if 0 /* Do not currently support holes */
3240:   PetscReal *holeCoords;
3241:   PetscInt   h, d;

3243:   DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3244:   if (in.numberofholes > 0) {
3245:     PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);
3246:     for (h = 0; h < in.numberofholes; ++h) {
3247:       for (d = 0; d < dim; ++d) {
3248:         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3249:       }
3250:     }
3251:   }
3252: #endif
3253:   if (!rank) {
3254:     char args[32];

3256:     /* Take away 'Q' for verbose output */
3257:     PetscStrcpy(args, "pqezQ");
3258:     if (createConvexHull) {
3259:       PetscStrcat(args, "c");
3260:     }
3261:     if (constrained) {
3262:       PetscStrcpy(args, "zepDQ");
3263:     }
3264:     triangulate(args, &in, &out, NULL);
3265:   }
3266:   PetscFree(in.pointlist);
3267:   PetscFree(in.pointmarkerlist);
3268:   PetscFree(in.segmentlist);
3269:   PetscFree(in.segmentmarkerlist);
3270:   PetscFree(in.holelist);

3272:   {
3273:     const PetscInt numCorners  = 3;
3274:     const PetscInt numCells    = out.numberoftriangles;
3275:     const PetscInt numVertices = out.numberofpoints;
3276:     const int     *cells      = out.trianglelist;
3277:     const double  *meshCoords = out.pointlist;

3279:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3280:     /* Set labels */
3281:     for (v = 0; v < numVertices; ++v) {
3282:       if (out.pointmarkerlist[v]) {
3283:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3284:       }
3285:     }
3286:     if (interpolate) {
3287:       for (e = 0; e < out.numberofedges; e++) {
3288:         if (out.edgemarkerlist[e]) {
3289:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3290:           const PetscInt *edges;
3291:           PetscInt        numEdges;

3293:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3294:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3295:           DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3296:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3297:         }
3298:       }
3299:     }
3300:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3301:   }
3302: #if 0 /* Do not currently support holes */
3303:   DMPlexCopyHoles(*dm, boundary);
3304: #endif
3305:   FiniOutput_Triangle(&out);
3306:   return(0);
3307: }

3311: PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3312: {
3313:   MPI_Comm             comm;
3314:   PetscInt             dim  = 2;
3315:   struct triangulateio in;
3316:   struct triangulateio out;
3317:   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3318:   PetscMPIInt          rank;
3319:   PetscErrorCode       ierr;

3322:   PetscObjectGetComm((PetscObject)dm,&comm);
3323:   MPI_Comm_rank(comm, &rank);
3324:   InitInput_Triangle(&in);
3325:   InitOutput_Triangle(&out);
3326:   DMPlexGetDepth(dm, &depth);
3327:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3328:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);

3330:   in.numberofpoints = vEnd - vStart;
3331:   if (in.numberofpoints > 0) {
3332:     PetscSection coordSection;
3333:     Vec          coordinates;
3334:     PetscScalar *array;

3336:     PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);
3337:     PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);
3338:     DMGetCoordinatesLocal(dm, &coordinates);
3339:     DMPlexGetCoordinateSection(dm, &coordSection);
3340:     VecGetArray(coordinates, &array);
3341:     for (v = vStart; v < vEnd; ++v) {
3342:       const PetscInt idx = v - vStart;
3343:       PetscInt       off, d;

3345:       PetscSectionGetOffset(coordSection, v, &off);
3346:       for (d = 0; d < dim; ++d) {
3347:         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3348:       }
3349:       DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3350:     }
3351:     VecRestoreArray(coordinates, &array);
3352:   }
3353:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

3355:   in.numberofcorners   = 3;
3356:   in.numberoftriangles = cEnd - cStart;

3358:   in.trianglearealist  = (double*) maxVolumes;
3359:   if (in.numberoftriangles > 0) {
3360:     PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);
3361:     for (c = cStart; c < cEnd; ++c) {
3362:       const PetscInt idx      = c - cStart;
3363:       PetscInt      *closure = NULL;
3364:       PetscInt       closureSize;

3366:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3367:       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3368:       for (v = 0; v < 3; ++v) {
3369:         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3370:       }
3371:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3372:     }
3373:   }
3374:   /* TODO: Segment markers are missing on input */
3375: #if 0 /* Do not currently support holes */
3376:   PetscReal *holeCoords;
3377:   PetscInt   h, d;

3379:   DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);
3380:   if (in.numberofholes > 0) {
3381:     PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);
3382:     for (h = 0; h < in.numberofholes; ++h) {
3383:       for (d = 0; d < dim; ++d) {
3384:         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3385:       }
3386:     }
3387:   }
3388: #endif
3389:   if (!rank) {
3390:     char args[32];

3392:     /* Take away 'Q' for verbose output */
3393:     PetscStrcpy(args, "pqezQra");
3394:     triangulate(args, &in, &out, NULL);
3395:   }
3396:   PetscFree(in.pointlist);
3397:   PetscFree(in.pointmarkerlist);
3398:   PetscFree(in.segmentlist);
3399:   PetscFree(in.segmentmarkerlist);
3400:   PetscFree(in.trianglelist);

3402:   {
3403:     const PetscInt numCorners  = 3;
3404:     const PetscInt numCells    = out.numberoftriangles;
3405:     const PetscInt numVertices = out.numberofpoints;
3406:     const int     *cells      = out.trianglelist;
3407:     const double  *meshCoords = out.pointlist;
3408:     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;

3410:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3411:     /* Set labels */
3412:     for (v = 0; v < numVertices; ++v) {
3413:       if (out.pointmarkerlist[v]) {
3414:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3415:       }
3416:     }
3417:     if (interpolate) {
3418:       PetscInt e;

3420:       for (e = 0; e < out.numberofedges; e++) {
3421:         if (out.edgemarkerlist[e]) {
3422:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3423:           const PetscInt *edges;
3424:           PetscInt        numEdges;

3426:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3427:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3428:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3429:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3430:         }
3431:       }
3432:     }
3433:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
3434:   }
3435: #if 0 /* Do not currently support holes */
3436:   DMPlexCopyHoles(*dm, boundary);
3437: #endif
3438:   FiniOutput_Triangle(&out);
3439:   return(0);
3440: }
3441: #endif

3443: #if defined(PETSC_HAVE_TETGEN)
3444: #include <tetgen.h>
3447: PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3448: {
3449:   MPI_Comm       comm;
3450:   const PetscInt dim  = 3;
3451:   ::tetgenio     in;
3452:   ::tetgenio     out;
3453:   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3454:   PetscMPIInt    rank;

3458:   PetscObjectGetComm((PetscObject)boundary,&comm);
3459:   MPI_Comm_rank(comm, &rank);
3460:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
3461:   in.numberofpoints = vEnd - vStart;
3462:   if (in.numberofpoints > 0) {
3463:     PetscSection coordSection;
3464:     Vec          coordinates;
3465:     PetscScalar *array;

3467:     in.pointlist       = new double[in.numberofpoints*dim];
3468:     in.pointmarkerlist = new int[in.numberofpoints];

3470:     DMGetCoordinatesLocal(boundary, &coordinates);
3471:     DMPlexGetCoordinateSection(boundary, &coordSection);
3472:     VecGetArray(coordinates, &array);
3473:     for (v = vStart; v < vEnd; ++v) {
3474:       const PetscInt idx = v - vStart;
3475:       PetscInt       off, d;

3477:       PetscSectionGetOffset(coordSection, v, &off);
3478:       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3479:       DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);
3480:     }
3481:     VecRestoreArray(coordinates, &array);
3482:   }
3483:   DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);

3485:   in.numberoffacets = fEnd - fStart;
3486:   if (in.numberoffacets > 0) {
3487:     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3488:     in.facetmarkerlist = new int[in.numberoffacets];
3489:     for (f = fStart; f < fEnd; ++f) {
3490:       const PetscInt idx     = f - fStart;
3491:       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;

3493:       in.facetlist[idx].numberofpolygons = 1;
3494:       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3495:       in.facetlist[idx].numberofholes    = 0;
3496:       in.facetlist[idx].holelist         = NULL;

3498:       DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3499:       for (p = 0; p < numPoints*2; p += 2) {
3500:         const PetscInt point = points[p];
3501:         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3502:       }

3504:       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3505:       poly->numberofvertices = numVertices;
3506:       poly->vertexlist       = new int[poly->numberofvertices];
3507:       for (v = 0; v < numVertices; ++v) {
3508:         const PetscInt vIdx = points[v] - vStart;
3509:         poly->vertexlist[v] = vIdx;
3510:       }
3511:       DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);
3512:       DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3513:     }
3514:   }
3515:   if (!rank) {
3516:     char args[32];

3518:     /* Take away 'Q' for verbose output */
3519:     PetscStrcpy(args, "pqezQ");
3520:     ::tetrahedralize(args, &in, &out);
3521:   }
3522:   {
3523:     const PetscInt numCorners  = 4;
3524:     const PetscInt numCells    = out.numberoftetrahedra;
3525:     const PetscInt numVertices = out.numberofpoints;
3526:     const double   *meshCoords = out.pointlist;
3527:     int            *cells      = out.tetrahedronlist;

3529:     DMPlexInvertCells_Internal(numCells, numCorners, cells);
3530:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3531:     /* Set labels */
3532:     for (v = 0; v < numVertices; ++v) {
3533:       if (out.pointmarkerlist[v]) {
3534:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);
3535:       }
3536:     }
3537:     if (interpolate) {
3538:       PetscInt e;

3540:       for (e = 0; e < out.numberofedges; e++) {
3541:         if (out.edgemarkerlist[e]) {
3542:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3543:           const PetscInt *edges;
3544:           PetscInt        numEdges;

3546:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3547:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3548:           DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);
3549:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3550:         }
3551:       }
3552:       for (f = 0; f < out.numberoftrifaces; f++) {
3553:         if (out.trifacemarkerlist[f]) {
3554:           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3555:           const PetscInt *faces;
3556:           PetscInt        numFaces;

3558:           DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);
3559:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3560:           DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);
3561:           DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
3562:         }
3563:       }
3564:     }
3565:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3566:   }
3567:   return(0);
3568: }

3572: PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3573: {
3574:   MPI_Comm       comm;
3575:   const PetscInt dim  = 3;
3576:   ::tetgenio     in;
3577:   ::tetgenio     out;
3578:   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3579:   PetscMPIInt    rank;

3583:   PetscObjectGetComm((PetscObject)dm,&comm);
3584:   MPI_Comm_rank(comm, &rank);
3585:   DMPlexGetDepth(dm, &depth);
3586:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3587:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);

3589:   in.numberofpoints = vEnd - vStart;
3590:   if (in.numberofpoints > 0) {
3591:     PetscSection coordSection;
3592:     Vec          coordinates;
3593:     PetscScalar *array;

3595:     in.pointlist       = new double[in.numberofpoints*dim];
3596:     in.pointmarkerlist = new int[in.numberofpoints];

3598:     DMGetCoordinatesLocal(dm, &coordinates);
3599:     DMPlexGetCoordinateSection(dm, &coordSection);
3600:     VecGetArray(coordinates, &array);
3601:     for (v = vStart; v < vEnd; ++v) {
3602:       const PetscInt idx = v - vStart;
3603:       PetscInt       off, d;

3605:       PetscSectionGetOffset(coordSection, v, &off);
3606:       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3607:       DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);
3608:     }
3609:     VecRestoreArray(coordinates, &array);
3610:   }
3611:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

3613:   in.numberofcorners       = 4;
3614:   in.numberoftetrahedra    = cEnd - cStart;
3615:   in.tetrahedronvolumelist = (double*) maxVolumes;
3616:   if (in.numberoftetrahedra > 0) {
3617:     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3618:     for (c = cStart; c < cEnd; ++c) {
3619:       const PetscInt idx      = c - cStart;
3620:       PetscInt      *closure = NULL;
3621:       PetscInt       closureSize;

3623:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3624:       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3625:       for (v = 0; v < 4; ++v) {
3626:         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3627:       }
3628:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3629:     }
3630:   }
3631:   /* TODO: Put in boundary faces with markers */
3632:   if (!rank) {
3633:     char args[32];

3635:     /* Take away 'Q' for verbose output */
3636:     /*PetscStrcpy(args, "qezQra"); */
3637:     PetscStrcpy(args, "qezraVVVV");
3638:     ::tetrahedralize(args, &in, &out);
3639:   }
3640:   in.tetrahedronvolumelist = NULL;

3642:   {
3643:     const PetscInt numCorners  = 4;
3644:     const PetscInt numCells    = out.numberoftetrahedra;
3645:     const PetscInt numVertices = out.numberofpoints;
3646:     const double   *meshCoords = out.pointlist;
3647:     int            *cells      = out.tetrahedronlist;

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

3651:     DMPlexInvertCells_Internal(numCells, numCorners, cells);
3652:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3653:     /* Set labels */
3654:     for (v = 0; v < numVertices; ++v) {
3655:       if (out.pointmarkerlist[v]) {
3656:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);
3657:       }
3658:     }
3659:     if (interpolate) {
3660:       PetscInt e, f;

3662:       for (e = 0; e < out.numberofedges; e++) {
3663:         if (out.edgemarkerlist[e]) {
3664:           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3665:           const PetscInt *edges;
3666:           PetscInt        numEdges;

3668:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3669:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3670:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);
3671:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3672:         }
3673:       }
3674:       for (f = 0; f < out.numberoftrifaces; f++) {
3675:         if (out.trifacemarkerlist[f]) {
3676:           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3677:           const PetscInt *faces;
3678:           PetscInt        numFaces;

3680:           DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3681:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3682:           DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);
3683:           DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3684:         }
3685:       }
3686:     }
3687:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
3688:   }
3689:   return(0);
3690: }
3691: #endif

3693: #if defined(PETSC_HAVE_CTETGEN)
3694: #include "ctetgen.h"

3698: PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3699: {
3700:   MPI_Comm       comm;
3701:   const PetscInt dim  = 3;
3702:   PLC           *in, *out;
3703:   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3704:   PetscMPIInt    rank;

3708:   PetscObjectGetComm((PetscObject)boundary,&comm);
3709:   PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);
3710:   MPI_Comm_rank(comm, &rank);
3711:   DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);
3712:   PLCCreate(&in);
3713:   PLCCreate(&out);

3715:   in->numberofpoints = vEnd - vStart;
3716:   if (in->numberofpoints > 0) {
3717:     PetscSection coordSection;
3718:     Vec          coordinates;
3719:     PetscScalar *array;

3721:     PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);
3722:     PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);
3723:     DMGetCoordinatesLocal(boundary, &coordinates);
3724:     DMPlexGetCoordinateSection(boundary, &coordSection);
3725:     VecGetArray(coordinates, &array);
3726:     for (v = vStart; v < vEnd; ++v) {
3727:       const PetscInt idx = v - vStart;
3728:       PetscInt       off, d, m;

3730:       PetscSectionGetOffset(coordSection, v, &off);
3731:       for (d = 0; d < dim; ++d) {
3732:         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3733:       }
3734:       DMPlexGetLabelValue(boundary, "marker", v, &m);

3736:       in->pointmarkerlist[idx] = (int) m;
3737:     }
3738:     VecRestoreArray(coordinates, &array);
3739:   }
3740:   DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);

3742:   in->numberoffacets = fEnd - fStart;
3743:   if (in->numberoffacets > 0) {
3744:     PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);
3745:     PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);
3746:     for (f = fStart; f < fEnd; ++f) {
3747:       const PetscInt idx     = f - fStart;
3748:       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3749:       polygon       *poly;

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

3753:       PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);

3755:       in->facetlist[idx].numberofholes    = 0;
3756:       in->facetlist[idx].holelist         = NULL;

3758:       DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3759:       for (p = 0; p < numPoints*2; p += 2) {
3760:         const PetscInt point = points[p];
3761:         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3762:       }

3764:       poly                   = in->facetlist[idx].polygonlist;
3765:       poly->numberofvertices = numVertices;
3766:       PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);
3767:       for (v = 0; v < numVertices; ++v) {
3768:         const PetscInt vIdx = points[v] - vStart;
3769:         poly->vertexlist[v] = vIdx;
3770:       }
3771:       DMPlexGetLabelValue(boundary, "marker", f, &m);
3772:       in->facetmarkerlist[idx] = (int) m;
3773:       DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);
3774:     }
3775:   }
3776:   if (!rank) {
3777:     TetGenOpts t;

3779:     TetGenOptsInitialize(&t);
3780:     t.in        = boundary; /* Should go away */
3781:     t.plc       = 1;
3782:     t.quality   = 1;
3783:     t.edgesout  = 1;
3784:     t.zeroindex = 1;
3785:     t.quiet     = 1;
3786:     t.verbose   = verbose;
3787:     TetGenCheckOpts(&t);
3788:     TetGenTetrahedralize(&t, in, out);
3789:   }
3790:   {
3791:     const PetscInt numCorners  = 4;
3792:     const PetscInt numCells    = out->numberoftetrahedra;
3793:     const PetscInt numVertices = out->numberofpoints;
3794:     const double   *meshCoords = out->pointlist;
3795:     int            *cells      = out->tetrahedronlist;

3797:     DMPlexInvertCells_Internal(numCells, numCorners, cells);
3798:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);
3799:     /* Set labels */
3800:     for (v = 0; v < numVertices; ++v) {
3801:       if (out->pointmarkerlist[v]) {
3802:         DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);
3803:       }
3804:     }
3805:     if (interpolate) {
3806:       PetscInt e;

3808:       for (e = 0; e < out->numberofedges; e++) {
3809:         if (out->edgemarkerlist[e]) {
3810:           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3811:           const PetscInt *edges;
3812:           PetscInt        numEdges;

3814:           DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);
3815:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3816:           DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);
3817:           DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);
3818:         }
3819:       }
3820:       for (f = 0; f < out->numberoftrifaces; f++) {
3821:         if (out->trifacemarkerlist[f]) {
3822:           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3823:           const PetscInt *faces;
3824:           PetscInt        numFaces;

3826:           DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);
3827:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3828:           DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);
3829:           DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);
3830:         }
3831:       }
3832:     }
3833:     DMPlexSetRefinementUniform(*dm, PETSC_FALSE);
3834:   }

3836:   PLCDestroy(&in);
3837:   PLCDestroy(&out);
3838:   return(0);
3839: }

3843: PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3844: {
3845:   MPI_Comm       comm;
3846:   const PetscInt dim  = 3;
3847:   PLC           *in, *out;
3848:   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3849:   PetscMPIInt    rank;

3853:   PetscObjectGetComm((PetscObject)dm,&comm);
3854:   PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);
3855:   MPI_Comm_rank(comm, &rank);
3856:   DMPlexGetDepth(dm, &depth);
3857:   MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);
3858:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
3859:   PLCCreate(&in);
3860:   PLCCreate(&out);

3862:   in->numberofpoints = vEnd - vStart;
3863:   if (in->numberofpoints > 0) {
3864:     PetscSection coordSection;
3865:     Vec          coordinates;
3866:     PetscScalar *array;

3868:     PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);
3869:     PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);
3870:     DMGetCoordinatesLocal(dm, &coordinates);
3871:     DMPlexGetCoordinateSection(dm, &coordSection);
3872:     VecGetArray(coordinates, &array);
3873:     for (v = vStart; v < vEnd; ++v) {
3874:       const PetscInt idx = v - vStart;
3875:       PetscInt       off, d, m;

3877:       PetscSectionGetOffset(coordSection, v, &off);
3878:       for (d = 0; d < dim; ++d) {
3879:         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3880:       }
3881:       DMPlexGetLabelValue(dm, "marker", v, &m);

3883:       in->pointmarkerlist[idx] = (int) m;
3884:     }
3885:     VecRestoreArray(coordinates, &array);
3886:   }
3887:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);

3889:   in->numberofcorners       = 4;
3890:   in->numberoftetrahedra    = cEnd - cStart;
3891:   in->tetrahedronvolumelist = maxVolumes;
3892:   if (in->numberoftetrahedra > 0) {
3893:     PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);
3894:     for (c = cStart; c < cEnd; ++c) {
3895:       const PetscInt idx      = c - cStart;
3896:       PetscInt      *closure = NULL;
3897:       PetscInt       closureSize;

3899:       DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3900:       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3901:       for (v = 0; v < 4; ++v) {
3902:         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3903:       }
3904:       DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);
3905:     }
3906:   }
3907:   if (!rank) {
3908:     TetGenOpts t;

3910:     TetGenOptsInitialize(&t);

3912:     t.in        = dm; /* Should go away */
3913:     t.refine    = 1;
3914:     t.varvolume = 1;
3915:     t.quality   = 1;
3916:     t.edgesout  = 1;
3917:     t.zeroindex = 1;
3918:     t.quiet     = 1;
3919:     t.verbose   = verbose; /* Change this */

3921:     TetGenCheckOpts(&t);
3922:     TetGenTetrahedralize(&t, in, out);
3923:   }
3924:   {
3925:     const PetscInt numCorners  = 4;
3926:     const PetscInt numCells    = out->numberoftetrahedra;
3927:     const PetscInt numVertices = out->numberofpoints;
3928:     const double   *meshCoords = out->pointlist;
3929:     int            *cells      = out->tetrahedronlist;
3930:     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;

3932:     DMPlexInvertCells_Internal(numCells, numCorners, cells);
3933:     DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);
3934:     /* Set labels */
3935:     for (v = 0; v < numVertices; ++v) {
3936:       if (out->pointmarkerlist[v]) {
3937:         DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);
3938:       }
3939:     }
3940:     if (interpolate) {
3941:       PetscInt e, f;

3943:       for (e = 0; e < out->numberofedges; e++) {
3944:         if (out->edgemarkerlist[e]) {
3945:           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3946:           const PetscInt *edges;
3947:           PetscInt        numEdges;

3949:           DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3950:           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3951:           DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);
3952:           DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);
3953:         }
3954:       }
3955:       for (f = 0; f < out->numberoftrifaces; f++) {
3956:         if (out->trifacemarkerlist[f]) {
3957:           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3958:           const PetscInt *faces;
3959:           PetscInt        numFaces;

3961:           DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3962:           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3963:           DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);
3964:           DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);
3965:         }
3966:       }
3967:     }
3968:     DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);
3969:   }
3970:   PLCDestroy(&in);
3971:   PLCDestroy(&out);
3972:   return(0);
3973: }
3974: #endif

3978: /*@C
3979:   DMPlexGenerate - Generates a mesh.

3981:   Not Collective

3983:   Input Parameters:
3984: + boundary - The DMPlex boundary object
3985: . name - The mesh generation package name
3986: - interpolate - Flag to create intermediate mesh elements

3988:   Output Parameter:
3989: . mesh - The DMPlex object

3991:   Level: intermediate

3993: .keywords: mesh, elements
3994: .seealso: DMPlexCreate(), DMRefine()
3995: @*/
3996: PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3997: {
3998:   PetscInt       dim;
3999:   char           genname[1024];
4000:   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;

4006:   DMPlexGetDimension(boundary, &dim);
4007:   PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);
4008:   if (flg) name = genname;
4009:   if (name) {
4010:     PetscStrcmp(name, "triangle", &isTriangle);
4011:     PetscStrcmp(name, "tetgen",   &isTetgen);
4012:     PetscStrcmp(name, "ctetgen",  &isCTetgen);
4013:   }
4014:   switch (dim) {
4015:   case 1:
4016:     if (!name || isTriangle) {
4017: #if defined(PETSC_HAVE_TRIANGLE)
4018:       DMPlexGenerate_Triangle(boundary, interpolate, mesh);
4019: #else
4020:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
4021: #endif
4022:     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
4023:     break;
4024:   case 2:
4025:     if (!name || isCTetgen) {
4026: #if defined(PETSC_HAVE_CTETGEN)
4027:       DMPlexGenerate_CTetgen(boundary, interpolate, mesh);
4028: #else
4029:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
4030: #endif
4031:     } else if (isTetgen) {
4032: #if defined(PETSC_HAVE_TETGEN)
4033:       DMPlexGenerate_Tetgen(boundary, interpolate, mesh);
4034: #else
4035:       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
4036: #endif
4037:     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
4038:     break;
4039:   default:
4040:     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
4041:   }
4042:   return(0);
4043: }

4045: typedef PetscInt CellRefiner;

4049: PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
4050: {
4052:   if (cStart) *cStart = 0;
4053:   if (vStart) *vStart = depthSize[depth];
4054:   if (fStart) *fStart = depthSize[depth] + depthSize[0];
4055:   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4056:   return(0);
4057: }

4061: PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
4062: {
4064:   if (cEnd) *cEnd = depthSize[depth];
4065:   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
4066:   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
4067:   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
4068:   return(0);
4069: }

4073: PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
4074: {
4075:   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;

4079:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
4080:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
4081:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4082:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4083:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
4084:   switch (refiner) {
4085:   case 1:
4086:     /* Simplicial 2D */
4087:     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
4088:     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
4089:     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
4090:     break;
4091:   case 3:
4092:     /* Hybrid 2D */
4093:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4094:     cMax = PetscMin(cEnd, cMax);
4095:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4096:     fMax         = PetscMin(fEnd, fMax);
4097:     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
4098:     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
4099:     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
4100:     break;
4101:   case 2:
4102:     /* Hex 2D */
4103:     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
4104:     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
4105:     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
4106:     break;
4107:   default:
4108:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4109:   }
4110:   return(0);
4111: }

4115: PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4116: {
4117:   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;

4121:   DMPlexGetDepth(dm, &depth);
4122:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
4123:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
4124:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4125:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4126:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
4127:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
4128:   switch (refiner) {
4129:   case 1:
4130:     /* Simplicial 2D */
4131:     /* All cells have 3 faces */
4132:     for (c = cStart; c < cEnd; ++c) {
4133:       for (r = 0; r < 4; ++r) {
4134:         const PetscInt newp = (c - cStart)*4 + r;

4136:         DMPlexSetConeSize(rdm, newp, 3);
4137:       }
4138:     }
4139:     /* Split faces have 2 vertices and the same cells as the parent */
4140:     for (f = fStart; f < fEnd; ++f) {
4141:       for (r = 0; r < 2; ++r) {
4142:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4143:         PetscInt       size;

4145:         DMPlexSetConeSize(rdm, newp, 2);
4146:         DMPlexGetSupportSize(dm, f, &size);
4147:         DMPlexSetSupportSize(rdm, newp, size);
4148:       }
4149:     }
4150:     /* Interior faces have 2 vertices and 2 cells */
4151:     for (c = cStart; c < cEnd; ++c) {
4152:       for (r = 0; r < 3; ++r) {
4153:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;

4155:         DMPlexSetConeSize(rdm, newp, 2);
4156:         DMPlexSetSupportSize(rdm, newp, 2);
4157:       }
4158:     }
4159:     /* Old vertices have identical supports */
4160:     for (v = vStart; v < vEnd; ++v) {
4161:       const PetscInt newp = vStartNew + (v - vStart);
4162:       PetscInt       size;

4164:       DMPlexGetSupportSize(dm, v, &size);
4165:       DMPlexSetSupportSize(rdm, newp, size);
4166:     }
4167:     /* Face vertices have 2 + cells*2 supports */
4168:     for (f = fStart; f < fEnd; ++f) {
4169:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4170:       PetscInt       size;

4172:       DMPlexGetSupportSize(dm, f, &size);
4173:       DMPlexSetSupportSize(rdm, newp, 2 + size*2);
4174:     }
4175:     break;
4176:   case 2:
4177:     /* Hex 2D */
4178:     /* All cells have 4 faces */
4179:     for (c = cStart; c < cEnd; ++c) {
4180:       for (r = 0; r < 4; ++r) {
4181:         const PetscInt newp = (c - cStart)*4 + r;

4183:         DMPlexSetConeSize(rdm, newp, 4);
4184:       }
4185:     }
4186:     /* Split faces have 2 vertices and the same cells as the parent */
4187:     for (f = fStart; f < fEnd; ++f) {
4188:       for (r = 0; r < 2; ++r) {
4189:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4190:         PetscInt       size;

4192:         DMPlexSetConeSize(rdm, newp, 2);
4193:         DMPlexGetSupportSize(dm, f, &size);
4194:         DMPlexSetSupportSize(rdm, newp, size);
4195:       }
4196:     }
4197:     /* Interior faces have 2 vertices and 2 cells */
4198:     for (c = cStart; c < cEnd; ++c) {
4199:       for (r = 0; r < 4; ++r) {
4200:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

4202:         DMPlexSetConeSize(rdm, newp, 2);
4203:         DMPlexSetSupportSize(rdm, newp, 2);
4204:       }
4205:     }
4206:     /* Old vertices have identical supports */
4207:     for (v = vStart; v < vEnd; ++v) {
4208:       const PetscInt newp = vStartNew + (v - vStart);
4209:       PetscInt       size;

4211:       DMPlexGetSupportSize(dm, v, &size);
4212:       DMPlexSetSupportSize(rdm, newp, size);
4213:     }
4214:     /* Face vertices have 2 + cells supports */
4215:     for (f = fStart; f < fEnd; ++f) {
4216:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4217:       PetscInt       size;

4219:       DMPlexGetSupportSize(dm, f, &size);
4220:       DMPlexSetSupportSize(rdm, newp, 2 + size);
4221:     }
4222:     /* Cell vertices have 4 supports */
4223:     for (c = cStart; c < cEnd; ++c) {
4224:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);

4226:       DMPlexSetSupportSize(rdm, newp, 4);
4227:     }
4228:     break;
4229:   case 3:
4230:     /* Hybrid 2D */
4231:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4232:     cMax = PetscMin(cEnd, cMax);
4233:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4234:     fMax = PetscMin(fEnd, fMax);
4235:     DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);
4236:     /* Interior cells have 3 faces */
4237:     for (c = cStart; c < cMax; ++c) {
4238:       for (r = 0; r < 4; ++r) {
4239:         const PetscInt newp = cStartNew + (c - cStart)*4 + r;

4241:         DMPlexSetConeSize(rdm, newp, 3);
4242:       }
4243:     }
4244:     /* Hybrid cells have 4 faces */
4245:     for (c = cMax; c < cEnd; ++c) {
4246:       for (r = 0; r < 2; ++r) {
4247:         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;

4249:         DMPlexSetConeSize(rdm, newp, 4);
4250:       }
4251:     }
4252:     /* Interior split faces have 2 vertices and the same cells as the parent */
4253:     for (f = fStart; f < fMax; ++f) {
4254:       for (r = 0; r < 2; ++r) {
4255:         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4256:         PetscInt       size;

4258:         DMPlexSetConeSize(rdm, newp, 2);
4259:         DMPlexGetSupportSize(dm, f, &size);
4260:         DMPlexSetSupportSize(rdm, newp, size);
4261:       }
4262:     }
4263:     /* Interior cell faces have 2 vertices and 2 cells */
4264:     for (c = cStart; c < cMax; ++c) {
4265:       for (r = 0; r < 3; ++r) {
4266:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;

4268:         DMPlexSetConeSize(rdm, newp, 2);
4269:         DMPlexSetSupportSize(rdm, newp, 2);
4270:       }
4271:     }
4272:     /* Hybrid faces have 2 vertices and the same cells */
4273:     for (f = fMax; f < fEnd; ++f) {
4274:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4275:       PetscInt       size;

4277:       DMPlexSetConeSize(rdm, newp, 2);
4278:       DMPlexGetSupportSize(dm, f, &size);
4279:       DMPlexSetSupportSize(rdm, newp, size);
4280:     }
4281:     /* Hybrid cell faces have 2 vertices and 2 cells */
4282:     for (c = cMax; c < cEnd; ++c) {
4283:       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);

4285:       DMPlexSetConeSize(rdm, newp, 2);
4286:       DMPlexSetSupportSize(rdm, newp, 2);
4287:     }
4288:     /* Old vertices have identical supports */
4289:     for (v = vStart; v < vEnd; ++v) {
4290:       const PetscInt newp = vStartNew + (v - vStart);
4291:       PetscInt       size;

4293:       DMPlexGetSupportSize(dm, v, &size);
4294:       DMPlexSetSupportSize(rdm, newp, size);
4295:     }
4296:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4297:     for (f = fStart; f < fMax; ++f) {
4298:       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4299:       const PetscInt *support;
4300:       PetscInt       size, newSize = 2, s;

4302:       DMPlexGetSupportSize(dm, f, &size);
4303:       DMPlexGetSupport(dm, f, &support);
4304:       for (s = 0; s < size; ++s) {
4305:         if (support[s] >= cMax) newSize += 1;
4306:         else newSize += 2;
4307:       }
4308:       DMPlexSetSupportSize(rdm, newp, newSize);
4309:     }
4310:     break;
4311:   default:
4312:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4313:   }
4314:   return(0);
4315: }

4319: PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4320: {
4321:   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
4322:   PetscInt       maxSupportSize, *supportRef;

4326:   DMPlexGetDepth(dm, &depth);
4327:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
4328:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
4329:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
4330:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4331:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
4332:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
4333:   GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);
4334:   switch (refiner) {
4335:   case 1:
4336:     /* Simplicial 2D */
4337:     /*
4338:      2
4339:      |\
4340:      | \
4341:      |  \
4342:      |   \
4343:      | C  \
4344:      |     \
4345:      |      \
4346:      2---1---1
4347:      |\  D  / \
4348:      | 2   0   \
4349:      |A \ /  B  \
4350:      0---0-------1
4351:      */
4352:     /* All cells have 3 faces */
4353:     for (c = cStart; c < cEnd; ++c) {
4354:       const PetscInt  newp = cStartNew + (c - cStart)*4;
4355:       const PetscInt *cone, *ornt;
4356:       PetscInt        coneNew[3], orntNew[3];

4358:       DMPlexGetCone(dm, c, &cone);
4359:       DMPlexGetConeOrientation(dm, c, &ornt);
4360:       /* A triangle */
4361:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4362:       orntNew[0] = ornt[0];
4363:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4364:       orntNew[1] = -2;
4365:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4366:       orntNew[2] = ornt[2];
4367:       DMPlexSetCone(rdm, newp+0, coneNew);
4368:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4369: #if 1
4370:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4371:       for (p = 0; p < 3; ++p) {
4372:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4373:       }
4374: #endif
4375:       /* B triangle */
4376:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4377:       orntNew[0] = ornt[0];
4378:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4379:       orntNew[1] = ornt[1];
4380:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4381:       orntNew[2] = -2;
4382:       DMPlexSetCone(rdm, newp+1, coneNew);
4383:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4384: #if 1
4385:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4386:       for (p = 0; p < 3; ++p) {
4387:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4388:       }
4389: #endif
4390:       /* C triangle */
4391:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4392:       orntNew[0] = -2;
4393:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4394:       orntNew[1] = ornt[1];
4395:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4396:       orntNew[2] = ornt[2];
4397:       DMPlexSetCone(rdm, newp+2, coneNew);
4398:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4399: #if 1
4400:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4401:       for (p = 0; p < 3; ++p) {
4402:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4403:       }
4404: #endif
4405:       /* D triangle */
4406:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4407:       orntNew[0] = 0;
4408:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4409:       orntNew[1] = 0;
4410:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4411:       orntNew[2] = 0;
4412:       DMPlexSetCone(rdm, newp+3, coneNew);
4413:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4414: #if 1
4415:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4416:       for (p = 0; p < 3; ++p) {
4417:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4418:       }
4419: #endif
4420:     }
4421:     /* Split faces have 2 vertices and the same cells as the parent */
4422:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4423:     PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);
4424:     for (f = fStart; f < fEnd; ++f) {
4425:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

4427:       for (r = 0; r < 2; ++r) {
4428:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4429:         const PetscInt *cone, *support;
4430:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4432:         DMPlexGetCone(dm, f, &cone);
4433:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4434:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4435:         coneNew[(r+1)%2] = newv;
4436:         DMPlexSetCone(rdm, newp, coneNew);
4437: #if 1
4438:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4439:         for (p = 0; p < 2; ++p) {
4440:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4441:         }
4442: #endif
4443:         DMPlexGetSupportSize(dm, f, &supportSize);
4444:         DMPlexGetSupport(dm, f, &support);
4445:         for (s = 0; s < supportSize; ++s) {
4446:           DMPlexGetConeSize(dm, support[s], &coneSize);
4447:           DMPlexGetCone(dm, support[s], &cone);
4448:           for (c = 0; c < coneSize; ++c) {
4449:             if (cone[c] == f) break;
4450:           }
4451:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4452:         }
4453:         DMPlexSetSupport(rdm, newp, supportRef);
4454: #if 1
4455:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4456:         for (p = 0; p < supportSize; ++p) {
4457:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4458:         }
4459: #endif
4460:       }
4461:     }
4462:     /* Interior faces have 2 vertices and 2 cells */
4463:     for (c = cStart; c < cEnd; ++c) {
4464:       const PetscInt *cone;

4466:       DMPlexGetCone(dm, c, &cone);
4467:       for (r = 0; r < 3; ++r) {
4468:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4469:         PetscInt       coneNew[2];
4470:         PetscInt       supportNew[2];

4472:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4473:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4474:         DMPlexSetCone(rdm, newp, coneNew);
4475: #if 1
4476:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4477:         for (p = 0; p < 2; ++p) {
4478:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4479:         }
4480: #endif
4481:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4482:         supportNew[1] = (c - cStart)*4 + 3;
4483:         DMPlexSetSupport(rdm, newp, supportNew);
4484: #if 1
4485:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4486:         for (p = 0; p < 2; ++p) {
4487:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4488:         }
4489: #endif
4490:       }
4491:     }
4492:     /* Old vertices have identical supports */
4493:     for (v = vStart; v < vEnd; ++v) {
4494:       const PetscInt  newp = vStartNew + (v - vStart);
4495:       const PetscInt *support, *cone;
4496:       PetscInt        size, s;

4498:       DMPlexGetSupportSize(dm, v, &size);
4499:       DMPlexGetSupport(dm, v, &support);
4500:       for (s = 0; s < size; ++s) {
4501:         PetscInt r = 0;

4503:         DMPlexGetCone(dm, support[s], &cone);
4504:         if (cone[1] == v) r = 1;
4505:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4506:       }
4507:       DMPlexSetSupport(rdm, newp, supportRef);
4508: #if 1
4509:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4510:       for (p = 0; p < size; ++p) {
4511:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4512:       }
4513: #endif
4514:     }
4515:     /* Face vertices have 2 + cells*2 supports */
4516:     for (f = fStart; f < fEnd; ++f) {
4517:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4518:       const PetscInt *cone, *support;
4519:       PetscInt        size, s;

4521:       DMPlexGetSupportSize(dm, f, &size);
4522:       DMPlexGetSupport(dm, f, &support);
4523:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4524:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4525:       for (s = 0; s < size; ++s) {
4526:         PetscInt r = 0;

4528:         DMPlexGetCone(dm, support[s], &cone);
4529:         if      (cone[1] == f) r = 1;
4530:         else if (cone[2] == f) r = 2;
4531:         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4532:         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4533:       }
4534:       DMPlexSetSupport(rdm, newp, supportRef);
4535: #if 1
4536:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4537:       for (p = 0; p < 2+size*2; ++p) {
4538:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4539:       }
4540: #endif
4541:     }
4542:     PetscFree(supportRef);
4543:     break;
4544:   case 2:
4545:     /* Hex 2D */
4546:     /*
4547:      3---------2---------2
4548:      |         |         |
4549:      |    D    2    C    |
4550:      |         |         |
4551:      3----3----0----1----1
4552:      |         |         |
4553:      |    A    0    B    |
4554:      |         |         |
4555:      0---------0---------1
4556:      */
4557:     /* All cells have 4 faces */
4558:     for (c = cStart; c < cEnd; ++c) {
4559:       const PetscInt  newp = (c - cStart)*4;
4560:       const PetscInt *cone, *ornt;
4561:       PetscInt        coneNew[4], orntNew[4];

4563:       DMPlexGetCone(dm, c, &cone);
4564:       DMPlexGetConeOrientation(dm, c, &ornt);
4565:       /* A quad */
4566:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4567:       orntNew[0] = ornt[0];
4568:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4569:       orntNew[1] = 0;
4570:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4571:       orntNew[2] = -2;
4572:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4573:       orntNew[3] = ornt[3];
4574:       DMPlexSetCone(rdm, newp+0, coneNew);
4575:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4576: #if 1
4577:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4578:       for (p = 0; p < 4; ++p) {
4579:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4580:       }
4581: #endif
4582:       /* B quad */
4583:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4584:       orntNew[0] = ornt[0];
4585:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4586:       orntNew[1] = ornt[1];
4587:       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4588:       orntNew[2] = 0;
4589:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4590:       orntNew[3] = -2;
4591:       DMPlexSetCone(rdm, newp+1, coneNew);
4592:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4593: #if 1
4594:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4595:       for (p = 0; p < 4; ++p) {
4596:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4597:       }
4598: #endif
4599:       /* C quad */
4600:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4601:       orntNew[0] = -2;
4602:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4603:       orntNew[1] = ornt[1];
4604:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4605:       orntNew[2] = ornt[2];
4606:       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4607:       orntNew[3] = 0;
4608:       DMPlexSetCone(rdm, newp+2, coneNew);
4609:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4610: #if 1
4611:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4612:       for (p = 0; p < 4; ++p) {
4613:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4614:       }
4615: #endif
4616:       /* D quad */
4617:       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4618:       orntNew[0] = 0;
4619:       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4620:       orntNew[1] = -2;
4621:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4622:       orntNew[2] = ornt[2];
4623:       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4624:       orntNew[3] = ornt[3];
4625:       DMPlexSetCone(rdm, newp+3, coneNew);
4626:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4627: #if 1
4628:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4629:       for (p = 0; p < 4; ++p) {
4630:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4631:       }
4632: #endif
4633:     }
4634:     /* Split faces have 2 vertices and the same cells as the parent */
4635:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4636:     PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);
4637:     for (f = fStart; f < fEnd; ++f) {
4638:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

4640:       for (r = 0; r < 2; ++r) {
4641:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4642:         const PetscInt *cone, *support;
4643:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4645:         DMPlexGetCone(dm, f, &cone);
4646:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4647:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4648:         coneNew[(r+1)%2] = newv;
4649:         DMPlexSetCone(rdm, newp, coneNew);
4650: #if 1
4651:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4652:         for (p = 0; p < 2; ++p) {
4653:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4654:         }
4655: #endif
4656:         DMPlexGetSupportSize(dm, f, &supportSize);
4657:         DMPlexGetSupport(dm, f, &support);
4658:         for (s = 0; s < supportSize; ++s) {
4659:           DMPlexGetConeSize(dm, support[s], &coneSize);
4660:           DMPlexGetCone(dm, support[s], &cone);
4661:           for (c = 0; c < coneSize; ++c) {
4662:             if (cone[c] == f) break;
4663:           }
4664:           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4665:         }
4666:         DMPlexSetSupport(rdm, newp, supportRef);
4667: #if 1
4668:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4669:         for (p = 0; p < supportSize; ++p) {
4670:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4671:         }
4672: #endif
4673:       }
4674:     }
4675:     /* Interior faces have 2 vertices and 2 cells */
4676:     for (c = cStart; c < cEnd; ++c) {
4677:       const PetscInt *cone;
4678:       PetscInt        coneNew[2], supportNew[2];

4680:       DMPlexGetCone(dm, c, &cone);
4681:       for (r = 0; r < 4; ++r) {
4682:         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;

4684:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4685:         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4686:         DMPlexSetCone(rdm, newp, coneNew);
4687: #if 1
4688:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4689:         for (p = 0; p < 2; ++p) {
4690:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4691:         }
4692: #endif
4693:         supportNew[0] = (c - cStart)*4 + r;
4694:         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4695:         DMPlexSetSupport(rdm, newp, supportNew);
4696: #if 1
4697:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4698:         for (p = 0; p < 2; ++p) {
4699:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4700:         }
4701: #endif
4702:       }
4703:     }
4704:     /* Old vertices have identical supports */
4705:     for (v = vStart; v < vEnd; ++v) {
4706:       const PetscInt  newp = vStartNew + (v - vStart);
4707:       const PetscInt *support, *cone;
4708:       PetscInt        size, s;

4710:       DMPlexGetSupportSize(dm, v, &size);
4711:       DMPlexGetSupport(dm, v, &support);
4712:       for (s = 0; s < size; ++s) {
4713:         PetscInt r = 0;

4715:         DMPlexGetCone(dm, support[s], &cone);
4716:         if (cone[1] == v) r = 1;
4717:         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4718:       }
4719:       DMPlexSetSupport(rdm, newp, supportRef);
4720: #if 1
4721:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4722:       for (p = 0; p < size; ++p) {
4723:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4724:       }
4725: #endif
4726:     }
4727:     /* Face vertices have 2 + cells supports */
4728:     for (f = fStart; f < fEnd; ++f) {
4729:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4730:       const PetscInt *cone, *support;
4731:       PetscInt        size, s;

4733:       DMPlexGetSupportSize(dm, f, &size);
4734:       DMPlexGetSupport(dm, f, &support);
4735:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4736:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4737:       for (s = 0; s < size; ++s) {
4738:         PetscInt r = 0;

4740:         DMPlexGetCone(dm, support[s], &cone);
4741:         if      (cone[1] == f) r = 1;
4742:         else if (cone[2] == f) r = 2;
4743:         else if (cone[3] == f) r = 3;
4744:         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4745:       }
4746:       DMPlexSetSupport(rdm, newp, supportRef);
4747: #if 1
4748:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4749:       for (p = 0; p < 2+size; ++p) {
4750:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4751:       }
4752: #endif
4753:     }
4754:     /* Cell vertices have 4 supports */
4755:     for (c = cStart; c < cEnd; ++c) {
4756:       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4757:       PetscInt       supportNew[4];

4759:       for (r = 0; r < 4; ++r) {
4760:         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4761:       }
4762:       DMPlexSetSupport(rdm, newp, supportNew);
4763:     }
4764:     break;
4765:   case 3:
4766:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4767:     cMax = PetscMin(cEnd, cMax);
4768:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4769:     fMax = PetscMin(fEnd, fMax);
4770:     /* Interior cells have 3 faces */
4771:     for (c = cStart; c < cMax; ++c) {
4772:       const PetscInt  newp = cStartNew + (c - cStart)*4;
4773:       const PetscInt *cone, *ornt;
4774:       PetscInt        coneNew[3], orntNew[3];

4776:       DMPlexGetCone(dm, c, &cone);
4777:       DMPlexGetConeOrientation(dm, c, &ornt);
4778:       /* A triangle */
4779:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4780:       orntNew[0] = ornt[0];
4781:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4782:       orntNew[1] = -2;
4783:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4784:       orntNew[2] = ornt[2];
4785:       DMPlexSetCone(rdm, newp+0, coneNew);
4786:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4787: #if 1
4788:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4789:       for (p = 0; p < 3; ++p) {
4790:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4791:       }
4792: #endif
4793:       /* B triangle */
4794:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4795:       orntNew[0] = ornt[0];
4796:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4797:       orntNew[1] = ornt[1];
4798:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4799:       orntNew[2] = -2;
4800:       DMPlexSetCone(rdm, newp+1, coneNew);
4801:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4802: #if 1
4803:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4804:       for (p = 0; p < 3; ++p) {
4805:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4806:       }
4807: #endif
4808:       /* C triangle */
4809:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4810:       orntNew[0] = -2;
4811:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4812:       orntNew[1] = ornt[1];
4813:       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4814:       orntNew[2] = ornt[2];
4815:       DMPlexSetCone(rdm, newp+2, coneNew);
4816:       DMPlexSetConeOrientation(rdm, newp+2, orntNew);
4817: #if 1
4818:       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4819:       for (p = 0; p < 3; ++p) {
4820:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4821:       }
4822: #endif
4823:       /* D triangle */
4824:       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4825:       orntNew[0] = 0;
4826:       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4827:       orntNew[1] = 0;
4828:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4829:       orntNew[2] = 0;
4830:       DMPlexSetCone(rdm, newp+3, coneNew);
4831:       DMPlexSetConeOrientation(rdm, newp+3, orntNew);
4832: #if 1
4833:       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4834:       for (p = 0; p < 3; ++p) {
4835:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4836:       }
4837: #endif
4838:     }
4839:     /*
4840:      2----3----3
4841:      |         |
4842:      |    B    |
4843:      |         |
4844:      0----4--- 1
4845:      |         |
4846:      |    A    |
4847:      |         |
4848:      0----2----1
4849:      */
4850:     /* Hybrid cells have 4 faces */
4851:     for (c = cMax; c < cEnd; ++c) {
4852:       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4853:       const PetscInt *cone, *ornt;
4854:       PetscInt        coneNew[4], orntNew[4];

4856:       DMPlexGetCone(dm, c, &cone);
4857:       DMPlexGetConeOrientation(dm, c, &ornt);
4858:       /* A quad */
4859:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4860:       orntNew[0] = ornt[0];
4861:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4862:       orntNew[1] = ornt[1];
4863:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4864:       orntNew[2] = 0;
4865:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4866:       orntNew[3] = 0;
4867:       DMPlexSetCone(rdm, newp+0, coneNew);
4868:       DMPlexSetConeOrientation(rdm, newp+0, orntNew);
4869: #if 1
4870:       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4871:       for (p = 0; p < 4; ++p) {
4872:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4873:       }
4874: #endif
4875:       /* B quad */
4876:       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4877:       orntNew[0] = ornt[0];
4878:       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4879:       orntNew[1] = ornt[1];
4880:       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4881:       orntNew[2] = 0;
4882:       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4883:       orntNew[3] = 0;
4884:       DMPlexSetCone(rdm, newp+1, coneNew);
4885:       DMPlexSetConeOrientation(rdm, newp+1, orntNew);
4886: #if 1
4887:       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4888:       for (p = 0; p < 4; ++p) {
4889:         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4890:       }
4891: #endif
4892:     }
4893:     /* Interior split faces have 2 vertices and the same cells as the parent */
4894:     DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);
4895:     PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);
4896:     for (f = fStart; f < fMax; ++f) {
4897:       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);

4899:       for (r = 0; r < 2; ++r) {
4900:         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4901:         const PetscInt *cone, *support;
4902:         PetscInt        coneNew[2], coneSize, c, supportSize, s;

4904:         DMPlexGetCone(dm, f, &cone);
4905:         coneNew[0]       = vStartNew + (cone[0] - vStart);
4906:         coneNew[1]       = vStartNew + (cone[1] - vStart);
4907:         coneNew[(r+1)%2] = newv;
4908:         DMPlexSetCone(rdm, newp, coneNew);
4909: #if 1
4910:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4911:         for (p = 0; p < 2; ++p) {
4912:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4913:         }
4914: #endif
4915:         DMPlexGetSupportSize(dm, f, &supportSize);
4916:         DMPlexGetSupport(dm, f, &support);
4917:         for (s = 0; s < supportSize; ++s) {
4918:           if (support[s] >= cMax) {
4919:             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4920:           } else {
4921:             DMPlexGetConeSize(dm, support[s], &coneSize);
4922:             DMPlexGetCone(dm, support[s], &cone);
4923:             for (c = 0; c < coneSize; ++c) {
4924:               if (cone[c] == f) break;
4925:             }
4926:             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4927:           }
4928:         }
4929:         DMPlexSetSupport(rdm, newp, supportRef);
4930: #if 1
4931:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4932:         for (p = 0; p < supportSize; ++p) {
4933:           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4934:         }
4935: #endif
4936:       }
4937:     }
4938:     /* Interior cell faces have 2 vertices and 2 cells */
4939:     for (c = cStart; c < cMax; ++c) {
4940:       const PetscInt *cone;

4942:       DMPlexGetCone(dm, c, &cone);
4943:       for (r = 0; r < 3; ++r) {
4944:         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4945:         PetscInt       coneNew[2];
4946:         PetscInt       supportNew[2];

4948:         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4949:         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4950:         DMPlexSetCone(rdm, newp, coneNew);
4951: #if 1
4952:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4953:         for (p = 0; p < 2; ++p) {
4954:           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4955:         }
4956: #endif
4957:         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4958:         supportNew[1] = (c - cStart)*4 + 3;
4959:         DMPlexSetSupport(rdm, newp, supportNew);
4960: #if 1
4961:         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4962:         for (p = 0; p < 2; ++p) {
4963:           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4964:         }
4965: #endif
4966:       }
4967:     }
4968:     /* Interior hybrid faces have 2 vertices and the same cells */
4969:     for (f = fMax; f < fEnd; ++f) {
4970:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4971:       const PetscInt *cone;
4972:       const PetscInt *support;
4973:       PetscInt        coneNew[2];
4974:       PetscInt        supportNew[2];
4975:       PetscInt        size, s, r;

4977:       DMPlexGetCone(dm, f, &cone);
4978:       coneNew[0] = vStartNew + (cone[0] - vStart);
4979:       coneNew[1] = vStartNew + (cone[1] - vStart);
4980:       DMPlexSetCone(rdm, newp, coneNew);
4981: #if 1
4982:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4983:       for (p = 0; p < 2; ++p) {
4984:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4985:       }
4986: #endif
4987:       DMPlexGetSupportSize(dm, f, &size);
4988:       DMPlexGetSupport(dm, f, &support);
4989:       for (s = 0; s < size; ++s) {
4990:         DMPlexGetCone(dm, support[s], &cone);
4991:         for (r = 0; r < 2; ++r) {
4992:           if (cone[r+2] == f) break;
4993:         }
4994:         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4995:       }
4996:       DMPlexSetSupport(rdm, newp, supportNew);
4997: #if 1
4998:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4999:       for (p = 0; p < size; ++p) {
5000:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5001:       }
5002: #endif
5003:     }
5004:     /* Cell hybrid faces have 2 vertices and 2 cells */
5005:     for (c = cMax; c < cEnd; ++c) {
5006:       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5007:       const PetscInt *cone;
5008:       PetscInt        coneNew[2];
5009:       PetscInt        supportNew[2];

5011:       DMPlexGetCone(dm, c, &cone);
5012:       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
5013:       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
5014:       DMPlexSetCone(rdm, newp, coneNew);
5015: #if 1
5016:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5017:       for (p = 0; p < 2; ++p) {
5018:         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5019:       }
5020: #endif
5021:       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
5022:       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
5023:       DMPlexSetSupport(rdm, newp, supportNew);
5024: #if 1
5025:       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5026:       for (p = 0; p < 2; ++p) {
5027:         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5028:       }
5029: #endif
5030:     }
5031:     /* Old vertices have identical supports */
5032:     for (v = vStart; v < vEnd; ++v) {
5033:       const PetscInt  newp = vStartNew + (v - vStart);
5034:       const PetscInt *support, *cone;
5035:       PetscInt        size, s;

5037:       DMPlexGetSupportSize(dm, v, &size);
5038:       DMPlexGetSupport(dm, v, &support);
5039:       for (s = 0; s < size; ++s) {
5040:         if (support[s] >= fMax) {
5041:           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
5042:         } else {
5043:           PetscInt r = 0;

5045:           DMPlexGetCone(dm, support[s], &cone);
5046:           if (cone[1] == v) r = 1;
5047:           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5048:         }
5049:       }
5050:       DMPlexSetSupport(rdm, newp, supportRef);
5051: #if 1
5052:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5053:       for (p = 0; p < size; ++p) {
5054:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5055:       }
5056: #endif
5057:     }
5058:     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5059:     for (f = fStart; f < fMax; ++f) {
5060:       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5061:       const PetscInt *cone, *support;
5062:       PetscInt        size, newSize = 2, s;

5064:       DMPlexGetSupportSize(dm, f, &size);
5065:       DMPlexGetSupport(dm, f, &support);
5066:       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5067:       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5068:       for (s = 0; s < size; ++s) {
5069:         PetscInt r = 0;

5071:         DMPlexGetCone(dm, support[s], &cone);
5072:         if (support[s] >= cMax) {
5073:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);

5075:           newSize += 1;
5076:         } else {
5077:           if      (cone[1] == f) r = 1;
5078:           else if (cone[2] == f) r = 2;
5079:           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5080:           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;

5082:           newSize += 2;
5083:         }
5084:       }
5085:       DMPlexSetSupport(rdm, newp, supportRef);
5086: #if 1
5087:       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5088:       for (p = 0; p < newSize; ++p) {
5089:         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5090:       }
5091: #endif
5092:     }
5093:     PetscFree(supportRef);
5094:     break;
5095:   default:
5096:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5097:   }
5098:   return(0);
5099: }

5103: PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5104: {
5105:   PetscSection   coordSection, coordSectionNew;
5106:   Vec            coordinates, coordinatesNew;
5107:   PetscScalar   *coords, *coordsNew;
5108:   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;

5112:   DMPlexGetDimension(dm, &dim);
5113:   DMPlexGetDepth(dm, &depth);
5114:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5115:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5116:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5117:   DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);
5118:   GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);
5119:   DMPlexGetCoordinateSection(dm, &coordSection);
5120:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);
5121:   PetscSectionSetNumFields(coordSectionNew, 1);
5122:   PetscSectionSetFieldComponents(coordSectionNew, 0, dim);
5123:   PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);
5124:   if (fMax < 0) fMax = fEnd;
5125:   switch (refiner) {
5126:   case 1:
5127:   case 2:
5128:   case 3:
5129:     /* Simplicial and Hex 2D */
5130:     /* All vertices have the dim coordinates */
5131:     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5132:       PetscSectionSetDof(coordSectionNew, v, dim);
5133:       PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);
5134:     }
5135:     PetscSectionSetUp(coordSectionNew);
5136:     DMPlexSetCoordinateSection(rdm, coordSectionNew);
5137:     DMGetCoordinatesLocal(dm, &coordinates);
5138:     PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);
5139:     VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);
5140:     PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");
5141:     VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);
5142:     VecSetFromOptions(coordinatesNew);
5143:     VecGetArray(coordinates, &coords);
5144:     VecGetArray(coordinatesNew, &coordsNew);
5145:     /* Old vertices have the same coordinates */
5146:     for (v = vStart; v < vEnd; ++v) {
5147:       const PetscInt newv = vStartNew + (v - vStart);
5148:       PetscInt       off, offnew, d;

5150:       PetscSectionGetOffset(coordSection, v, &off);
5151:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5152:       for (d = 0; d < dim; ++d) {
5153:         coordsNew[offnew+d] = coords[off+d];
5154:       }
5155:     }
5156:     /* Face vertices have the average of endpoint coordinates */
5157:     for (f = fStart; f < fMax; ++f) {
5158:       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5159:       const PetscInt *cone;
5160:       PetscInt        coneSize, offA, offB, offnew, d;

5162:       DMPlexGetConeSize(dm, f, &coneSize);
5163:       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5164:       DMPlexGetCone(dm, f, &cone);
5165:       PetscSectionGetOffset(coordSection, cone[0], &offA);
5166:       PetscSectionGetOffset(coordSection, cone[1], &offB);
5167:       PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5168:       for (d = 0; d < dim; ++d) {
5169:         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5170:       }
5171:     }
5172:     /* Just Hex 2D */
5173:     if (refiner == 2) {
5174:       /* Cell vertices have the average of corner coordinates */
5175:       for (c = cStart; c < cEnd; ++c) {
5176:         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5177:         PetscInt      *cone = NULL;
5178:         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;

5180:         DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5181:         for (p = 0; p < closureSize*2; p += 2) {
5182:           const PetscInt point = cone[p];
5183:           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5184:         }
5185:         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5186:         PetscSectionGetOffset(coordSection, cone[0], &offA);
5187:         PetscSectionGetOffset(coordSection, cone[1], &offB);
5188:         PetscSectionGetOffset(coordSection, cone[2], &offC);
5189:         PetscSectionGetOffset(coordSection, cone[3], &offD);
5190:         PetscSectionGetOffset(coordSectionNew, newv, &offnew);
5191:         for (d = 0; d < dim; ++d) {
5192:           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5193:         }
5194:         DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);
5195:       }
5196:     }
5197:     VecRestoreArray(coordinates, &coords);
5198:     VecRestoreArray(coordinatesNew, &coordsNew);
5199:     DMSetCoordinatesLocal(rdm, coordinatesNew);
5200:     VecDestroy(&coordinatesNew);
5201:     PetscSectionDestroy(&coordSectionNew);
5202:     break;
5203:   default:
5204:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5205:   }
5206:   return(0);
5207: }

5211: PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5212: {
5213:   PetscInt           numRoots, numLeaves, l;
5214:   const PetscInt    *localPoints;
5215:   const PetscSFNode *remotePoints;
5216:   PetscInt          *localPointsNew;
5217:   PetscSFNode       *remotePointsNew;
5218:   PetscInt          *ranks, *ranksNew;
5219:   PetscErrorCode     ierr;

5222:   PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);
5223:   PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);
5224:   for (l = 0; l < numLeaves; ++l) {
5225:     ranks[l] = remotePoints[l].rank;
5226:   }
5227:   PetscSortRemoveDupsInt(&numLeaves, ranks);
5228:   PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);
5229:   PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);
5230:   PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);
5231:   for (l = 0; l < numLeaves; ++l) {
5232:     ranksNew[l]              = ranks[l];
5233:     localPointsNew[l]        = l;
5234:     remotePointsNew[l].index = 0;
5235:     remotePointsNew[l].rank  = ranksNew[l];
5236:   }
5237:   PetscFree(ranks);
5238:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);
5239:   PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);
5240:   PetscSFSetFromOptions(*sfProcess);
5241:   PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
5242:   return(0);
5243: }

5247: PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5248: {
5249:   PetscSF            sf, sfNew, sfProcess;
5250:   IS                 processRanks;
5251:   MPI_Datatype       depthType;
5252:   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5253:   const PetscInt    *localPoints, *neighbors;
5254:   const PetscSFNode *remotePoints;
5255:   PetscInt          *localPointsNew;
5256:   PetscSFNode       *remotePointsNew;
5257:   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5258:   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5259:   PetscErrorCode     ierr;

5262:   DMPlexGetChart(rdm, &pStartNew, &pEndNew);
5263:   DMPlexGetDepth(dm, &depth);
5264:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5265:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5266:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5267:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
5268:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
5269:   GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);
5270:   switch (refiner) {
5271:   case 3:
5272:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5273:     cMax = PetscMin(cEnd, cMax);
5274:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5275:     fMax = PetscMin(fEnd, fMax);
5276:   }
5277:   DMGetPointSF(dm, &sf);
5278:   DMGetPointSF(rdm, &sfNew);
5279:   /* Caculate size of new SF */
5280:   PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);
5281:   if (numRoots < 0) return(0);
5282:   for (l = 0; l < numLeaves; ++l) {
5283:     const PetscInt p = localPoints[l];

5285:     switch (refiner) {
5286:     case 1:
5287:       /* Simplicial 2D */
5288:       if ((p >= vStart) && (p < vEnd)) {
5289:         /* Old vertices stay the same */
5290:         ++numLeavesNew;
5291:       } else if ((p >= fStart) && (p < fEnd)) {
5292:         /* Old faces add new faces and vertex */
5293:         numLeavesNew += 1 + 2;
5294:       } else if ((p >= cStart) && (p < cEnd)) {
5295:         /* Old cells add new cells and interior faces */
5296:         numLeavesNew += 4 + 3;
5297:       }
5298:       break;
5299:     case 2:
5300:       /* Hex 2D */
5301:       if ((p >= vStart) && (p < vEnd)) {
5302:         /* Old vertices stay the same */
5303:         ++numLeavesNew;
5304:       } else if ((p >= fStart) && (p < fEnd)) {
5305:         /* Old faces add new faces and vertex */
5306:         numLeavesNew += 1 + 2;
5307:       } else if ((p >= cStart) && (p < cEnd)) {
5308:         /* Old cells add new cells and interior faces */
5309:         numLeavesNew += 4 + 4;
5310:       }
5311:       break;
5312:     default:
5313:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5314:     }
5315:   }
5316:   /* Communicate depthSizes for each remote rank */
5317:   DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);
5318:   ISGetLocalSize(processRanks, &numNeighbors);
5319:   PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);
5320:   PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);
5321:   MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);
5322:   MPI_Type_commit(&depthType);
5323:   PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);
5324:   PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);
5325:   for (n = 0; n < numNeighbors; ++n) {
5326:     GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);
5327:   }
5328:   depthSizeOld[depth]   = cMax;
5329:   depthSizeOld[0]       = vMax;
5330:   depthSizeOld[depth-1] = fMax;
5331:   depthSizeOld[1]       = eMax;

5333:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);
5334:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);

5336:   depthSizeOld[depth]   = cEnd - cStart;
5337:   depthSizeOld[0]       = vEnd - vStart;
5338:   depthSizeOld[depth-1] = fEnd - fStart;
5339:   depthSizeOld[1]       = eEnd - eStart;

5341:   PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5342:   PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);
5343:   for (n = 0; n < numNeighbors; ++n) {
5344:     GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);
5345:   }
5346:   MPI_Type_free(&depthType);
5347:   PetscSFDestroy(&sfProcess);
5348:   /* Calculate new point SF */
5349:   PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);
5350:   PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);
5351:   ISGetIndices(processRanks, &neighbors);
5352:   for (l = 0, m = 0; l < numLeaves; ++l) {
5353:     PetscInt    p     = localPoints[l];
5354:     PetscInt    rp    = remotePoints[l].index, n;
5355:     PetscMPIInt rrank = remotePoints[l].rank;

5357:     PetscFindInt(rrank, numNeighbors, neighbors, &n);
5358:     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5359:     switch (refiner) {
5360:     case 1:
5361:       /* Simplicial 2D */
5362:       if ((p >= vStart) && (p < vEnd)) {
5363:         /* Old vertices stay the same */
5364:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5365:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5366:         remotePointsNew[m].rank  = rrank;
5367:         ++m;
5368:       } else if ((p >= fStart) && (p < fEnd)) {
5369:         /* Old faces add new faces and vertex */
5370:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5371:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5372:         remotePointsNew[m].rank  = rrank;
5373:         ++m;
5374:         for (r = 0; r < 2; ++r, ++m) {
5375:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5376:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5377:           remotePointsNew[m].rank  = rrank;
5378:         }
5379:       } else if ((p >= cStart) && (p < cEnd)) {
5380:         /* Old cells add new cells and interior faces */
5381:         for (r = 0; r < 4; ++r, ++m) {
5382:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5383:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5384:           remotePointsNew[m].rank  = rrank;
5385:         }
5386:         for (r = 0; r < 3; ++r, ++m) {
5387:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5388:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5389:           remotePointsNew[m].rank  = rrank;
5390:         }
5391:       }
5392:       break;
5393:     case 2:
5394:       /* Hex 2D */
5395:       if ((p >= vStart) && (p < vEnd)) {
5396:         /* Old vertices stay the same */
5397:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5398:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5399:         remotePointsNew[m].rank  = rrank;
5400:         ++m;
5401:       } else if ((p >= fStart) && (p < fEnd)) {
5402:         /* Old faces add new faces and vertex */
5403:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5404:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5405:         remotePointsNew[m].rank  = rrank;
5406:         ++m;
5407:         for (r = 0; r < 2; ++r, ++m) {
5408:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5409:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5410:           remotePointsNew[m].rank  = rrank;
5411:         }
5412:       } else if ((p >= cStart) && (p < cEnd)) {
5413:         /* Old cells add new cells and interior faces */
5414:         for (r = 0; r < 4; ++r, ++m) {
5415:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5416:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5417:           remotePointsNew[m].rank  = rrank;
5418:         }
5419:         for (r = 0; r < 4; ++r, ++m) {
5420:           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5421:           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5422:           remotePointsNew[m].rank  = rrank;
5423:         }
5424:       }
5425:       break;
5426:     case 3:
5427:       /* Hybrid simplicial 2D */
5428:       if ((p >= vStart) && (p < vEnd)) {
5429:         /* Old vertices stay the same */
5430:         localPointsNew[m]        = vStartNew     + (p  - vStart);
5431:         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5432:         remotePointsNew[m].rank  = rrank;
5433:         ++m;
5434:       } else if ((p >= fStart) && (p < fMax)) {
5435:         /* Old interior faces add new faces and vertex */
5436:         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5437:         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5438:         remotePointsNew[m].rank  = rrank;
5439:         ++m;
5440:         for (r = 0; r < 2; ++r, ++m) {
5441:           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5442:           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5443:           remotePointsNew[m].rank  = rrank;
5444:         }
5445:       } else if ((p >= fMax) && (p < fEnd)) {
5446:         /* Old hybrid faces stay the same */
5447:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5448:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5449:         remotePointsNew[m].rank  = rrank;
5450:         ++m;
5451:       } else if ((p >= cStart) && (p < cMax)) {
5452:         /* Old interior cells add new cells and interior faces */
5453:         for (r = 0; r < 4; ++r, ++m) {
5454:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5455:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5456:           remotePointsNew[m].rank  = rrank;
5457:         }
5458:         for (r = 0; r < 3; ++r, ++m) {
5459:           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5460:           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5461:           remotePointsNew[m].rank  = rrank;
5462:         }
5463:       } else if ((p >= cStart) && (p < cMax)) {
5464:         /* Old hybrid cells add new cells and hybrid face */
5465:         for (r = 0; r < 2; ++r, ++m) {
5466:           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5467:           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5468:           remotePointsNew[m].rank  = rrank;
5469:         }
5470:         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5471:         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5472:         remotePointsNew[m].rank  = rrank;
5473:         ++m;
5474:       }
5475:       break;
5476:     default:
5477:       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5478:     }
5479:   }
5480:   ISRestoreIndices(processRanks, &neighbors);
5481:   ISDestroy(&processRanks);
5482:   PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);
5483:   PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);
5484:   PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);
5485:   return(0);
5486: }

5490: PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5491: {
5492:   PetscInt       numLabels, l;
5493:   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;

5497:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
5498:   DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);
5499:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5500:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);

5502:   cStartNew = 0;
5503:   vStartNew = depthSize[2];
5504:   fStartNew = depthSize[2] + depthSize[0];

5506:   DMPlexGetNumLabels(dm, &numLabels);
5507:   DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);
5508:   switch (refiner) {
5509:   case 3:
5510:     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5511:     cMax = PetscMin(cEnd, cMax);
5512:     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5513:     fMax = PetscMin(fEnd, fMax);
5514:   }
5515:   for (l = 0; l < numLabels; ++l) {
5516:     DMLabel         label, labelNew;
5517:     const char     *lname;
5518:     PetscBool       isDepth;
5519:     IS              valueIS;
5520:     const PetscInt *values;
5521:     PetscInt        numValues, val;

5523:     DMPlexGetLabelName(dm, l, &lname);
5524:     PetscStrcmp(lname, "depth", &isDepth);
5525:     if (isDepth) continue;
5526:     DMPlexCreateLabel(rdm, lname);
5527:     DMPlexGetLabel(dm, lname, &label);
5528:     DMPlexGetLabel(rdm, lname, &labelNew);
5529:     DMLabelGetValueIS(label, &valueIS);
5530:     ISGetLocalSize(valueIS, &numValues);
5531:     ISGetIndices(valueIS, &values);
5532:     for (val = 0; val < numValues; ++val) {
5533:       IS              pointIS;
5534:       const PetscInt *points;
5535:       PetscInt        numPoints, n;

5537:       DMLabelGetStratumIS(label, values[val], &pointIS);
5538:       ISGetLocalSize(pointIS, &numPoints);
5539:       ISGetIndices(pointIS, &points);
5540:       for (n = 0; n < numPoints; ++n) {
5541:         const PetscInt p = points[n];
5542:         switch (refiner) {
5543:         case 1:
5544:           /* Simplicial 2D */
5545:           if ((p >= vStart) && (p < vEnd)) {
5546:             /* Old vertices stay the same */
5547:             newp = vStartNew + (p - vStart);
5548:             DMLabelSetValue(labelNew, newp, values[val]);
5549:           } else if ((p >= fStart) && (p < fEnd)) {
5550:             /* Old faces add new faces and vertex */
5551:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5552:             DMLabelSetValue(labelNew, newp, values[val]);
5553:             for (r = 0; r < 2; ++r) {
5554:               newp = fStartNew + (p - fStart)*2 + r;
5555:               DMLabelSetValue(labelNew, newp, values[val]);
5556:             }
5557:           } else if ((p >= cStart) && (p < cEnd)) {
5558:             /* Old cells add new cells and interior faces */
5559:             for (r = 0; r < 4; ++r) {
5560:               newp = cStartNew + (p - cStart)*4 + r;
5561:               DMLabelSetValue(labelNew, newp, values[val]);
5562:             }
5563:             for (r = 0; r < 3; ++r) {
5564:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5565:               DMLabelSetValue(labelNew, newp, values[val]);
5566:             }
5567:           }
5568:           break;
5569:         case 2:
5570:           /* Hex 2D */
5571:           if ((p >= vStart) && (p < vEnd)) {
5572:             /* Old vertices stay the same */
5573:             newp = vStartNew + (p - vStart);
5574:             DMLabelSetValue(labelNew, newp, values[val]);
5575:           } else if ((p >= fStart) && (p < fEnd)) {
5576:             /* Old faces add new faces and vertex */
5577:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5578:             DMLabelSetValue(labelNew, newp, values[val]);
5579:             for (r = 0; r < 2; ++r) {
5580:               newp = fStartNew + (p - fStart)*2 + r;
5581:               DMLabelSetValue(labelNew, newp, values[val]);
5582:             }
5583:           } else if ((p >= cStart) && (p < cEnd)) {
5584:             /* Old cells add new cells and interior faces and vertex */
5585:             for (r = 0; r < 4; ++r) {
5586:               newp = cStartNew + (p - cStart)*4 + r;
5587:               DMLabelSetValue(labelNew, newp, values[val]);
5588:             }
5589:             for (r = 0; r < 4; ++r) {
5590:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5591:               DMLabelSetValue(labelNew, newp, values[val]);
5592:             }
5593:             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5594:             DMLabelSetValue(labelNew, newp, values[val]);
5595:           }
5596:           break;
5597:         case 3:
5598:           /* Hybrid simplicial 2D */
5599:           if ((p >= vStart) && (p < vEnd)) {
5600:             /* Old vertices stay the same */
5601:             newp = vStartNew + (p - vStart);
5602:             DMLabelSetValue(labelNew, newp, values[val]);
5603:           } else if ((p >= fStart) && (p < fMax)) {
5604:             /* Old interior faces add new faces and vertex */
5605:             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5606:             DMLabelSetValue(labelNew, newp, values[val]);
5607:             for (r = 0; r < 2; ++r) {
5608:               newp = fStartNew + (p - fStart)*2 + r;
5609:               DMLabelSetValue(labelNew, newp, values[val]);
5610:             }
5611:           } else if ((p >= fMax) && (p < fEnd)) {
5612:             /* Old hybrid faces stay the same */
5613:             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5614:             DMLabelSetValue(labelNew, newp, values[val]);
5615:           } else if ((p >= cStart) && (p < cMax)) {
5616:             /* Old interior cells add new cells and interior faces */
5617:             for (r = 0; r < 4; ++r) {
5618:               newp = cStartNew + (p - cStart)*4 + r;
5619:               DMLabelSetValue(labelNew, newp, values[val]);
5620:             }
5621:             for (r = 0; r < 3; ++r) {
5622:               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5623:               DMLabelSetValue(labelNew, newp, values[val]);
5624:             }
5625:           } else if ((p >= cMax) && (p < cEnd)) {
5626:             /* Old hybrid cells add new cells and hybrid face */
5627:             for (r = 0; r < 2; ++r) {
5628:               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5629:               DMLabelSetValue(labelNew, newp, values[val]);
5630:             }
5631:             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5632:             DMLabelSetValue(labelNew, newp, values[val]);
5633:           }
5634:           break;
5635:         default:
5636:           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5637:         }
5638:       }
5639:       ISRestoreIndices(pointIS, &points);
5640:       ISDestroy(&pointIS);
5641:     }
5642:     ISRestoreIndices(valueIS, &values);
5643:     ISDestroy(&valueIS);
5644:     if (0) {
5645:       PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);
5646:       DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);
5647:       PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);
5648:     }
5649:   }
5650:   return(0);
5651: }

5655: /* This will only work for interpolated meshes */
5656: PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5657: {
5658:   DM             rdm;
5659:   PetscInt      *depthSize;
5660:   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;

5664:   DMCreate(PetscObjectComm((PetscObject)dm), &rdm);
5665:   DMSetType(rdm, DMPLEX);
5666:   DMPlexGetDimension(dm, &dim);
5667:   DMPlexSetDimension(rdm, dim);
5668:   /* Calculate number of new points of each depth */
5669:   DMPlexGetDepth(dm, &depth);
5670:   PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);
5671:   PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));
5672:   CellRefinerGetSizes(cellRefiner, dm, depthSize);
5673:   /* Step 1: Set chart */
5674:   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5675:   DMPlexSetChart(rdm, pStart, pEnd);
5676:   /* Step 2: Set cone/support sizes */
5677:   CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);
5678:   /* Step 3: Setup refined DM */
5679:   DMSetUp(rdm);
5680:   /* Step 4: Set cones and supports */
5681:   CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);
5682:   /* Step 5: Stratify */
5683:   DMPlexStratify(rdm);
5684:   /* Step 6: Set coordinates for vertices */
5685:   CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);
5686:   /* Step 7: Create pointSF */
5687:   CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);
5688:   /* Step 8: Create labels */
5689:   CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);
5690:   PetscFree(depthSize);

5692:   *dmRefined = rdm;
5693:   return(0);
5694: }

5698: PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5699: {
5700:   DM_Plex *mesh = (DM_Plex*) dm->data;

5704:   mesh->refinementUniform = refinementUniform;
5705:   return(0);
5706: }

5710: PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5711: {
5712:   DM_Plex *mesh = (DM_Plex*) dm->data;

5717:   *refinementUniform = mesh->refinementUniform;
5718:   return(0);
5719: }

5723: PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5724: {
5725:   DM_Plex *mesh = (DM_Plex*) dm->data;

5729:   mesh->refinementLimit = refinementLimit;
5730:   return(0);
5731: }

5735: PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5736: {
5737:   DM_Plex *mesh = (DM_Plex*) dm->data;

5742:   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5743:   *refinementLimit = mesh->refinementLimit;
5744:   return(0);
5745: }

5749: PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5750: {
5751:   PetscInt       dim, cStart, coneSize, cMax;

5755:   DMPlexGetDimension(dm, &dim);
5756:   DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5757:   DMPlexGetConeSize(dm, cStart, &coneSize);
5758:   DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
5759:   switch (dim) {
5760:   case 2:
5761:     switch (coneSize) {
5762:     case 3:
5763:       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5764:       else *cellRefiner = 1; /* Triangular */
5765:       break;
5766:     case 4:
5767:       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5768:       else *cellRefiner = 2; /* Quadrilateral */
5769:       break;
5770:     default:
5771:       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5772:     }
5773:     break;
5774:   default:
5775:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5776:   }
5777:   return(0);
5778: }

5782: PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5783: {
5784:   PetscReal      refinementLimit;
5785:   PetscInt       dim, cStart, cEnd;
5786:   char           genname[1024], *name = NULL;
5787:   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;

5791:   DMPlexGetRefinementUniform(dm, &isUniform);
5792:   if (isUniform) {
5793:     CellRefiner cellRefiner;

5795:     DMPlexGetCellRefiner_Private(dm, &cellRefiner);
5796:     DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);
5797:     return(0);
5798:   }
5799:   DMPlexGetRefinementLimit(dm, &refinementLimit);
5800:   if (refinementLimit == 0.0) return(0);
5801:   DMPlexGetDimension(dm, &dim);
5802:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
5803:   PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);
5804:   if (flg) name = genname;
5805:   if (name) {
5806:     PetscStrcmp(name, "triangle", &isTriangle);
5807:     PetscStrcmp(name, "tetgen",   &isTetgen);
5808:     PetscStrcmp(name, "ctetgen",  &isCTetgen);
5809:   }
5810:   switch (dim) {
5811:   case 2:
5812:     if (!name || isTriangle) {
5813: #if defined(PETSC_HAVE_TRIANGLE)
5814:       double  *maxVolumes;
5815:       PetscInt c;

5817:       PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);
5818:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5819:       DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);
5820: #else
5821:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5822: #endif
5823:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5824:     break;
5825:   case 3:
5826:     if (!name || isCTetgen) {
5827: #if defined(PETSC_HAVE_CTETGEN)
5828:       PetscReal *maxVolumes;
5829:       PetscInt   c;

5831:       PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);
5832:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5833:       DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);
5834: #else
5835:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5836: #endif
5837:     } else if (isTetgen) {
5838: #if defined(PETSC_HAVE_TETGEN)
5839:       double  *maxVolumes;
5840:       PetscInt c;

5842:       PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);
5843:       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5844:       DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);
5845: #else
5846:       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5847: #endif
5848:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5849:     break;
5850:   default:
5851:     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5852:   }
5853:   return(0);
5854: }

5858: /*@
5859:   DMPlexGetDepth - get the number of strata

5861:   Not Collective

5863:   Input Parameters:
5864: . dm           - The DMPlex object

5866:   Output Parameters:
5867: . depth - number of strata

5869:   Level: developer

5871:   Notes:
5872:   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).

5874: .keywords: mesh, points
5875: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5876: @*/
5877: PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5878: {
5879:   PetscInt       d;

5885:   DMPlexGetLabelSize(dm, "depth", &d);
5886:   *depth = d-1;
5887:   return(0);
5888: }

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

5895:   Not Collective

5897:   Input Parameters:
5898: + dm           - The DMPlex object
5899: - stratumValue - The requested depth

5901:   Output Parameters:
5902: + start - The first point at this depth
5903: - end   - One beyond the last point at this depth

5905:   Level: developer

5907: .keywords: mesh, points
5908: .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5909: @*/
5910: PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5911: {
5912:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5913:   DMLabel        next  = mesh->labels;
5914:   PetscBool      flg   = PETSC_FALSE;
5915:   PetscInt       depth;

5920:   if (stratumValue < 0) {
5921:     DMPlexGetChart(dm, start, end);
5922:     return(0);
5923:   } else {
5924:     PetscInt pStart, pEnd;

5926:     if (start) *start = 0;
5927:     if (end)   *end   = 0;
5928:     DMPlexGetChart(dm, &pStart, &pEnd);
5929:     if (pStart == pEnd) return(0);
5930:   }
5931:   DMPlexHasLabel(dm, "depth", &flg);
5932:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5933:   /* We should have a generic GetLabel() and a Label class */
5934:   while (next) {
5935:     PetscStrcmp("depth", next->name, &flg);
5936:     if (flg) break;
5937:     next = next->next;
5938:   }
5939:   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5940:   depth = stratumValue;
5941:   if ((depth < 0) || (depth >= next->numStrata)) {
5942:     if (start) *start = 0;
5943:     if (end)   *end   = 0;
5944:   } else {
5945:     if (start) *start = next->points[next->stratumOffsets[depth]];
5946:     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5947:   }
5948:   return(0);
5949: }

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

5956:   Not Collective

5958:   Input Parameters:
5959: + dm           - The DMPlex object
5960: - stratumValue - The requested height

5962:   Output Parameters:
5963: + start - The first point at this height
5964: - end   - One beyond the last point at this height

5966:   Level: developer

5968: .keywords: mesh, points
5969: .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5970: @*/
5971: PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5972: {
5973:   DM_Plex       *mesh = (DM_Plex*) dm->data;
5974:   DMLabel        next  = mesh->labels;
5975:   PetscBool      flg   = PETSC_FALSE;
5976:   PetscInt       depth;

5981:   if (stratumValue < 0) {
5982:     DMPlexGetChart(dm, start, end);
5983:   } else {
5984:     PetscInt pStart, pEnd;

5986:     if (start) *start = 0;
5987:     if (end)   *end   = 0;
5988:     DMPlexGetChart(dm, &pStart, &pEnd);
5989:     if (pStart == pEnd) return(0);
5990:   }
5991:   DMPlexHasLabel(dm, "depth", &flg);
5992:   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");
5993:   /* We should have a generic GetLabel() and a Label class */
5994:   while (next) {
5995:     PetscStrcmp("depth", next->name, &flg);
5996:     if (flg) break;
5997:     next = next->next;
5998:   }
5999:   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6000:   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6001:   if ((depth < 0) || (depth >= next->numStrata)) {
6002:     if (start) *start = 0;
6003:     if (end)   *end   = 0;
6004:   } else {
6005:     if (start) *start = next->points[next->stratumOffsets[depth]];
6006:     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
6007:   }
6008:   return(0);
6009: }

6013: /* Set the number of dof on each point and separate by fields */
6014: PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
6015: {
6016:   PetscInt      *numDofTot;
6017:   PetscInt       pStart = 0, pEnd = 0;
6018:   PetscInt       p, d, f;

6022:   PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);
6023:   for (d = 0; d <= dim; ++d) {
6024:     numDofTot[d] = 0;
6025:     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
6026:   }
6027:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);
6028:   if (numFields > 0) {
6029:     PetscSectionSetNumFields(*section, numFields);
6030:     if (numComp) {
6031:       for (f = 0; f < numFields; ++f) {
6032:         PetscSectionSetFieldComponents(*section, f, numComp[f]);
6033:       }
6034:     }
6035:   }
6036:   DMPlexGetChart(dm, &pStart, &pEnd);
6037:   PetscSectionSetChart(*section, pStart, pEnd);
6038:   for (d = 0; d <= dim; ++d) {
6039:     DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);
6040:     for (p = pStart; p < pEnd; ++p) {
6041:       for (f = 0; f < numFields; ++f) {
6042:         PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);
6043:       }
6044:       PetscSectionSetDof(*section, p, numDofTot[d]);
6045:     }
6046:   }
6047:   PetscFree(numDofTot);
6048:   return(0);
6049: }

6053: /* Set the number of dof on each point and separate by fields
6054:    If constDof is PETSC_DETERMINE, constrain every dof on the point
6055: */
6056: PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
6057: {
6058:   PetscInt       numFields;
6059:   PetscInt       bc;

6063:   PetscSectionGetNumFields(section, &numFields);
6064:   for (bc = 0; bc < numBC; ++bc) {
6065:     PetscInt        field = 0;
6066:     const PetscInt *idx;
6067:     PetscInt        n, i;

6069:     if (numFields) field = bcField[bc];
6070:     ISGetLocalSize(bcPoints[bc], &n);
6071:     ISGetIndices(bcPoints[bc], &idx);
6072:     for (i = 0; i < n; ++i) {
6073:       const PetscInt p        = idx[i];
6074:       PetscInt       numConst = constDof;

6076:       /* Constrain every dof on the point */
6077:       if (numConst < 0) {
6078:         if (numFields) {
6079:           PetscSectionGetFieldDof(section, p, field, &numConst);
6080:         } else {
6081:           PetscSectionGetDof(section, p, &numConst);
6082:         }
6083:       }
6084:       if (numFields) {
6085:         PetscSectionAddFieldConstraintDof(section, p, field, numConst);
6086:       }
6087:       PetscSectionAddConstraintDof(section, p, numConst);
6088:     }
6089:     ISRestoreIndices(bcPoints[bc], &idx);
6090:   }
6091:   return(0);
6092: }

6096: /* Set the constrained indices on each point and separate by fields */
6097: PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
6098: {
6099:   PetscInt      *maxConstraints;
6100:   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;

6104:   PetscSectionGetNumFields(section, &numFields);
6105:   PetscSectionGetChart(section, &pStart, &pEnd);
6106:   PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);
6107:   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
6108:   for (p = pStart; p < pEnd; ++p) {
6109:     PetscInt cdof;

6111:     if (numFields) {
6112:       for (f = 0; f < numFields; ++f) {
6113:         PetscSectionGetFieldConstraintDof(section, p, f, &cdof);
6114:         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6115:       }
6116:     } else {
6117:       PetscSectionGetConstraintDof(section, p, &cdof);
6118:       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6119:     }
6120:   }
6121:   for (f = 0; f < numFields; ++f) {
6122:     maxConstraints[numFields] += maxConstraints[f];
6123:   }
6124:   if (maxConstraints[numFields]) {
6125:     PetscInt *indices;

6127:     PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);
6128:     for (p = pStart; p < pEnd; ++p) {
6129:       PetscInt cdof, d;

6131:       PetscSectionGetConstraintDof(section, p, &cdof);
6132:       if (cdof) {
6133:         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6134:         if (numFields) {
6135:           PetscInt numConst = 0, foff = 0;

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

6140:             PetscSectionGetFieldDof(section, p, f, &fdof);
6141:             PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);
6142:             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6143:             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6144:             PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);
6145:             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6146:             numConst += cfdof;
6147:             foff     += fdof;
6148:           }
6149:           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6150:         } else {
6151:           for (d = 0; d < cdof; ++d) indices[d] = d;
6152:         }
6153:         PetscSectionSetConstraintIndices(section, p, indices);
6154:       }
6155:     }
6156:     PetscFree(indices);
6157:   }
6158:   PetscFree(maxConstraints);
6159:   return(0);
6160: }

6164: /* Set the constrained field indices on each point */
6165: PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6166: {
6167:   const PetscInt *points, *indices;
6168:   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6169:   PetscErrorCode  ierr;

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

6175:   ISGetLocalSize(bcPoints, &numPoints);
6176:   ISGetIndices(bcPoints, &points);
6177:   if (!constraintIndices) {
6178:     PetscInt *idx, i;

6180:     PetscSectionGetMaxDof(section, &maxDof);
6181:     PetscMalloc(maxDof * sizeof(PetscInt), &idx);
6182:     for (i = 0; i < maxDof; ++i) idx[i] = i;
6183:     for (p = 0; p < numPoints; ++p) {
6184:       PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);
6185:     }
6186:     PetscFree(idx);
6187:   } else {
6188:     ISGetLocalSize(constraintIndices, &numConstraints);
6189:     ISGetIndices(constraintIndices, &indices);
6190:     for (p = 0; p < numPoints; ++p) {
6191:       PetscInt fcdof;

6193:       PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);
6194:       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);
6195:       PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);
6196:     }
6197:     ISRestoreIndices(constraintIndices, &indices);
6198:   }
6199:   ISRestoreIndices(bcPoints, &points);
6200:   return(0);
6201: }

6205: /* Set the constrained indices on each point and separate by fields */
6206: PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6207: {
6208:   PetscInt      *indices;
6209:   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;

6213:   PetscSectionGetMaxDof(section, &maxDof);
6214:   PetscMalloc(maxDof * sizeof(PetscInt), &indices);
6215:   PetscSectionGetNumFields(section, &numFields);
6216:   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6217:   PetscSectionGetChart(section, &pStart, &pEnd);
6218:   for (p = pStart; p < pEnd; ++p) {
6219:     PetscInt cdof, d;

6221:     PetscSectionGetConstraintDof(section, p, &cdof);
6222:     if (cdof) {
6223:       PetscInt numConst = 0, foff = 0;

6225:       for (f = 0; f < numFields; ++f) {
6226:         const PetscInt *fcind;
6227:         PetscInt        fdof, fcdof;

6229:         PetscSectionGetFieldDof(section, p, f, &fdof);
6230:         PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
6231:         if (fcdof) {PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);}
6232:         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6233:         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6234:         foff     += fdof;
6235:         numConst += fcdof;
6236:       }
6237:       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6238:       PetscSectionSetConstraintIndices(section, p, indices);
6239:     }
6240:   }
6241:   PetscFree(indices);
6242:   return(0);
6243: }

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

6250:   Not Collective

6252:   Input Parameters:
6253: + dm        - The DMPlex object
6254: . dim       - The spatial dimension of the problem
6255: . numFields - The number of fields in the problem
6256: . numComp   - An array of size numFields that holds the number of components for each field
6257: . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6258: . numBC     - The number of boundary conditions
6259: . bcField   - An array of size numBC giving the field number for each boundry condition
6260: - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies

6262:   Output Parameter:
6263: . section - The PetscSection object

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

6268:   Level: developer

6270:   Fortran Notes:
6271:   A Fortran 90 version is available as DMPlexCreateSectionF90()

6273: .keywords: mesh, elements
6274: .seealso: DMPlexCreate(), PetscSectionCreate()
6275: @*/
6276: PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6277: {

6281:   DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);
6282:   DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);
6283:   PetscSectionSetUp(*section);
6284:   if (numBC) {DMPlexCreateSectionBCIndicesAll(dm, *section);}
6285:   {
6286:     PetscBool view = PETSC_FALSE;

6288:     PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);
6289:     if (view) {PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);}
6290:   }
6291:   return(0);
6292: }

6296: PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6297: {
6298:   PetscSection   section;

6302:   DMPlexClone(dm, cdm);
6303:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
6304:   DMSetDefaultSection(*cdm, section);
6305:   PetscSectionDestroy(&section);
6306:   return(0);
6307: }

6311: /*@
6312:   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6314:   Not Collective

6316:   Input Parameter:
6317: . dm - The DMPlex object

6319:   Output Parameter:
6320: . section - The PetscSection object

6322:   Level: intermediate

6324: .keywords: mesh, coordinates
6325: .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6326: @*/
6327: PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6328: {
6329:   DM             cdm;

6335:   DMGetCoordinateDM(dm, &cdm);
6336:   DMGetDefaultSection(cdm, section);
6337:   return(0);
6338: }

6342: /*@
6343:   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.

6345:   Not Collective

6347:   Input Parameters:
6348: + dm      - The DMPlex object
6349: - section - The PetscSection object

6351:   Level: intermediate

6353: .keywords: mesh, coordinates
6354: .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6355: @*/
6356: PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6357: {
6358:   DM             cdm;

6364:   DMGetCoordinateDM(dm, &cdm);
6365:   DMSetDefaultSection(cdm, section);
6366:   return(0);
6367: }

6371: PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6372: {
6373:   DM_Plex *mesh = (DM_Plex*) dm->data;

6377:   if (section) *section = mesh->coneSection;
6378:   return(0);
6379: }

6383: PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6384: {
6385:   DM_Plex *mesh = (DM_Plex*) dm->data;

6389:   if (cones) *cones = mesh->cones;
6390:   return(0);
6391: }

6395: PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6396: {
6397:   DM_Plex *mesh = (DM_Plex*) dm->data;

6401:   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6402:   return(0);
6403: }

6405: /******************************** FEM Support **********************************/

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

6412:   Not collective

6414:   Input Parameters:
6415: + dm - The DM
6416: . section - The section describing the layout in v, or NULL to use the default section
6417: . v - The local vector
6418: - point - The sieve point in the DM

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

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

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

6430:   Level: intermediate

6432: .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6433: @*/
6434: PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6435: {
6436:   PetscScalar   *array, *vArray;
6437:   PetscInt      *points = NULL;
6438:   PetscInt       offsets[32];
6439:   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;

6445:   if (!section) {
6446:     DMGetDefaultSection(dm, &section);
6447:   }
6448:   PetscSectionGetNumFields(section, &numFields);
6449:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6450:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
6451:   DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
6452:   /* Compress out points not in the section */
6453:   PetscSectionGetChart(section, &pStart, &pEnd);
6454:   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6455:     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6456:       points[q*2]   = points[p];
6457:       points[q*2+1] = points[p+1];
6458:       ++q;
6459:     }
6460:   }
6461:   numPoints = q;
6462:   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6463:     PetscInt dof, fdof;

6465:     PetscSectionGetDof(section, points[p], &dof);
6466:     for (f = 0; f < numFields; ++f) {
6467:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6468:       offsets[f+1] += fdof;
6469:     }
6470:     size += dof;
6471:   }
6472:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6473:   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6474:   DMGetWorkArray(dm, size, PETSC_SCALAR, &array);
6475:   VecGetArray(v, &vArray);
6476:   for (p = 0; p < numPoints*2; p += 2) {
6477:     PetscInt     o = points[p+1];
6478:     PetscInt     dof, off, d;
6479:     PetscScalar *varr;

6481:     PetscSectionGetDof(section, points[p], &dof);
6482:     PetscSectionGetOffset(section, points[p], &off);
6483:     varr = &vArray[off];
6484:     if (numFields) {
6485:       PetscInt fdof, foff, fcomp, f, c;

6487:       for (f = 0, foff = 0; f < numFields; ++f) {
6488:         PetscSectionGetFieldDof(section, points[p], f, &fdof);
6489:         if (o >= 0) {
6490:           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6491:             array[offsets[f]] = varr[foff+d];
6492:           }
6493:         } else {
6494:           PetscSectionGetFieldComponents(section, f, &fcomp);
6495:           for (d = fdof/fcomp-1; d >= 0; --d) {
6496:             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6497:               array[offsets[f]] = varr[foff+d*fcomp+c];
6498:             }
6499:           }
6500:         }
6501:         foff += fdof;
6502:       }
6503:     } else {
6504:       if (o >= 0) {
6505:         for (d = 0; d < dof; ++d, ++offsets[0]) {
6506:           array[offsets[0]] = varr[d];
6507:         }
6508:       } else {
6509:         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6510:           array[offsets[0]] = varr[d];
6511:         }
6512:       }
6513:     }
6514:   }
6515:   DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
6516:   VecRestoreArray(v, &vArray);
6517:   if (csize) *csize = size;
6518:   *values = array;
6519:   return(0);
6520: }

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

6527:   Not collective

6529:   Input Parameters:
6530: + dm - The DM
6531: . section - The section describing the layout in v, or NULL to use the default section
6532: . v - The local vector
6533: . point - The sieve point in the DM
6534: . csize - The number of values in the closure, or NULL
6535: - values - The array of values, which is a borrowed array and should not be freed

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

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

6543:   Level: intermediate

6545: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6546: @*/
6547: PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6548: {
6549:   PetscInt       size = 0;

6553:   /* Should work without recalculating size */
6554:   DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);
6555:   return(0);
6556: }

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

6563: PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6564: {
6565:   PetscInt        cdof;   /* The number of constraints on this point */
6566:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6567:   PetscScalar    *a;
6568:   PetscInt        off, cind = 0, k;
6569:   PetscErrorCode  ierr;

6572:   PetscSectionGetConstraintDof(section, point, &cdof);
6573:   PetscSectionGetOffset(section, point, &off);
6574:   a    = &array[off];
6575:   if (!cdof || setBC) {
6576:     if (orientation >= 0) {
6577:       for (k = 0; k < dof; ++k) {
6578:         fuse(&a[k], values[k]);
6579:       }
6580:     } else {
6581:       for (k = 0; k < dof; ++k) {
6582:         fuse(&a[k], values[dof-k-1]);
6583:       }
6584:     }
6585:   } else {
6586:     PetscSectionGetConstraintIndices(section, point, &cdofs);
6587:     if (orientation >= 0) {
6588:       for (k = 0; k < dof; ++k) {
6589:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6590:         fuse(&a[k], values[k]);
6591:       }
6592:     } else {
6593:       for (k = 0; k < dof; ++k) {
6594:         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6595:         fuse(&a[k], values[dof-k-1]);
6596:       }
6597:     }
6598:   }
6599:   return(0);
6600: }

6604: PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6605: {
6606:   PetscScalar   *a;
6607:   PetscInt       numFields, off, foff, f;

6611:   PetscSectionGetNumFields(section, &numFields);
6612:   PetscSectionGetOffset(section, point, &off);
6613:   a    = &array[off];
6614:   for (f = 0, foff = 0; f < numFields; ++f) {
6615:     PetscInt        fdof, fcomp, fcdof;
6616:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6617:     PetscInt        cind = 0, k, c;

6619:     PetscSectionGetFieldComponents(section, f, &fcomp);
6620:     PetscSectionGetFieldDof(section, point, f, &fdof);
6621:     PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);
6622:     if (!fcdof || setBC) {
6623:       if (orientation >= 0) {
6624:         for (k = 0; k < fdof; ++k) {
6625:           fuse(&a[foff+k], values[foffs[f]+k]);
6626:         }
6627:       } else {
6628:         for (k = fdof/fcomp-1; k >= 0; --k) {
6629:           for (c = 0; c < fcomp; ++c) {
6630:             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6631:           }
6632:         }
6633:       }
6634:     } else {
6635:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
6636:       if (orientation >= 0) {
6637:         for (k = 0; k < fdof; ++k) {
6638:           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6639:           fuse(&a[foff+k], values[foffs[f]+k]);
6640:         }
6641:       } else {
6642:         for (k = fdof/fcomp-1; k >= 0; --k) {
6643:           for (c = 0; c < fcomp; ++c) {
6644:             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6645:             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6646:           }
6647:         }
6648:       }
6649:     }
6650:     foff     += fdof;
6651:     foffs[f] += fdof;
6652:   }
6653:   return(0);
6654: }

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

6661:   Not collective

6663:   Input Parameters:
6664: + dm - The DM
6665: . section - The section describing the layout in v, or NULL to use the default section
6666: . v - The local vector
6667: . point - The sieve point in the DM
6668: . values - The array of values
6669: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

6674:   Level: intermediate

6676: .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6677: @*/
6678: PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6679: {
6680:   PetscScalar   *array;
6681:   PetscInt      *points = NULL;
6682:   PetscInt       offsets[32];
6683:   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;

6689:   if (!section) {
6690:     DMGetDefaultSection(dm, &section);
6691:   }
6692:   PetscSectionGetNumFields(section, &numFields);
6693:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6694:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
6695:   DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
6696:   /* Compress out points not in the section */
6697:   PetscSectionGetChart(section, &pStart, &pEnd);
6698:   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6699:     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6700:       points[q*2]   = points[p];
6701:       points[q*2+1] = points[p+1];
6702:       ++q;
6703:     }
6704:   }
6705:   numPoints = q;
6706:   for (p = 0; p < numPoints*2; p += 2) {
6707:     PetscInt fdof;

6709:     for (f = 0; f < numFields; ++f) {
6710:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6711:       offsets[f+1] += fdof;
6712:     }
6713:   }
6714:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6715:   VecGetArray(v, &array);
6716:   if (numFields) {
6717:     switch (mode) {
6718:     case INSERT_VALUES:
6719:       for (p = 0; p < numPoints*2; p += 2) {
6720:         PetscInt o = points[p+1];
6721:         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6722:       } break;
6723:     case INSERT_ALL_VALUES:
6724:       for (p = 0; p < numPoints*2; p += 2) {
6725:         PetscInt o = points[p+1];
6726:         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6727:       } break;
6728:     case ADD_VALUES:
6729:       for (p = 0; p < numPoints*2; p += 2) {
6730:         PetscInt o = points[p+1];
6731:         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6732:       } break;
6733:     case ADD_ALL_VALUES:
6734:       for (p = 0; p < numPoints*2; p += 2) {
6735:         PetscInt o = points[p+1];
6736:         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6737:       } break;
6738:     default:
6739:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6740:     }
6741:   } else {
6742:     switch (mode) {
6743:     case INSERT_VALUES:
6744:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6745:         PetscInt o = points[p+1];
6746:         PetscSectionGetDof(section, points[p], &dof);
6747:         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6748:       } break;
6749:     case INSERT_ALL_VALUES:
6750:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6751:         PetscInt o = points[p+1];
6752:         PetscSectionGetDof(section, points[p], &dof);
6753:         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6754:       } break;
6755:     case ADD_VALUES:
6756:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6757:         PetscInt o = points[p+1];
6758:         PetscSectionGetDof(section, points[p], &dof);
6759:         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6760:       } break;
6761:     case ADD_ALL_VALUES:
6762:       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6763:         PetscInt o = points[p+1];
6764:         PetscSectionGetDof(section, points[p], &dof);
6765:         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6766:       } break;
6767:     default:
6768:       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6769:     }
6770:   }
6771:   DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
6772:   VecRestoreArray(v, &array);
6773:   return(0);
6774: }

6778: PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6779: {
6780:   PetscMPIInt    rank;
6781:   PetscInt       i, j;

6785:   MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);
6786:   PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);
6787:   for (i = 0; i < numIndices; i++) {
6788:     PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);
6789:   }
6790:   for (i = 0; i < numIndices; i++) {
6791:     PetscViewerASCIIPrintf(viewer, "[%D]", rank);
6792:     for (j = 0; j < numIndices; j++) {
6793: #if defined(PETSC_USE_COMPLEX)
6794:       PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));
6795: #else
6796:       PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);
6797: #endif
6798:     }
6799:     PetscViewerASCIIPrintf(viewer, "\n");
6800:   }
6801:   return(0);
6802: }

6806: /* . off - The global offset of this point */
6807: PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6808: {
6809:   PetscInt        dof;    /* The number of unknowns on this point */
6810:   PetscInt        cdof;   /* The number of constraints on this point */
6811:   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6812:   PetscInt        cind = 0, k;
6813:   PetscErrorCode  ierr;

6816:   PetscSectionGetDof(section, point, &dof);
6817:   PetscSectionGetConstraintDof(section, point, &cdof);
6818:   if (!cdof || setBC) {
6819:     if (orientation >= 0) {
6820:       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6821:     } else {
6822:       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6823:     }
6824:   } else {
6825:     PetscSectionGetConstraintIndices(section, point, &cdofs);
6826:     if (orientation >= 0) {
6827:       for (k = 0; k < dof; ++k) {
6828:         if ((cind < cdof) && (k == cdofs[cind])) {
6829:           /* Insert check for returning constrained indices */
6830:           indices[*loff+k] = -(off+k+1);
6831:           ++cind;
6832:         } else {
6833:           indices[*loff+k] = off+k-cind;
6834:         }
6835:       }
6836:     } else {
6837:       for (k = 0; k < dof; ++k) {
6838:         if ((cind < cdof) && (k == cdofs[cind])) {
6839:           /* Insert check for returning constrained indices */
6840:           indices[*loff+dof-k-1] = -(off+k+1);
6841:           ++cind;
6842:         } else {
6843:           indices[*loff+dof-k-1] = off+k-cind;
6844:         }
6845:       }
6846:     }
6847:   }
6848:   *loff += dof;
6849:   return(0);
6850: }

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

6861:   PetscSectionGetNumFields(section, &numFields);
6862:   for (f = 0, foff = 0; f < numFields; ++f) {
6863:     PetscInt        fdof, fcomp, cfdof;
6864:     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6865:     PetscInt        cind = 0, k, c;

6867:     PetscSectionGetFieldComponents(section, f, &fcomp);
6868:     PetscSectionGetFieldDof(section, point, f, &fdof);
6869:     PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);
6870:     if (!cfdof || setBC) {
6871:       if (orientation >= 0) {
6872:         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6873:       } else {
6874:         for (k = fdof/fcomp-1; k >= 0; --k) {
6875:           for (c = 0; c < fcomp; ++c) {
6876:             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6877:           }
6878:         }
6879:       }
6880:     } else {
6881:       PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);
6882:       if (orientation >= 0) {
6883:         for (k = 0; k < fdof; ++k) {
6884:           if ((cind < cfdof) && (k == fcdofs[cind])) {
6885:             indices[foffs[f]+k] = -(off+foff+k+1);
6886:             ++cind;
6887:           } else {
6888:             indices[foffs[f]+k] = off+foff+k-cind;
6889:           }
6890:         }
6891:       } else {
6892:         for (k = fdof/fcomp-1; k >= 0; --k) {
6893:           for (c = 0; c < fcomp; ++c) {
6894:             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6895:               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6896:               ++cind;
6897:             } else {
6898:               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6899:             }
6900:           }
6901:         }
6902:       }
6903:     }
6904:     foff     += fdof - cfdof;
6905:     foffs[f] += fdof;
6906:   }
6907:   return(0);
6908: }

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

6915:   Not collective

6917:   Input Parameters:
6918: + dm - The DM
6919: . section - The section describing the layout in v, or NULL to use the default section
6920: . globalSection - The section describing the layout in v, or NULL to use the default section
6921: . A - The matrix
6922: . point - The sieve point in the DM
6923: . values - The array of values
6924: - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions

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

6929:   Level: intermediate

6931: .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure()
6932: @*/
6933: PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6934: {
6935:   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6936:   PetscInt      *points = NULL;
6937:   PetscInt      *indices;
6938:   PetscInt       offsets[32];
6939:   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6940:   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6941:   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;

6947:   if (useDefault) {
6948:     DMGetDefaultSection(dm, &section);
6949:   }
6950:   if (useGlobalDefault) {
6951:     if (useDefault) {
6952:       DMGetDefaultGlobalSection(dm, &globalSection);
6953:     } else {
6954:       PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);
6955:     }
6956:   }
6957:   PetscSectionGetNumFields(section, &numFields);
6958:   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6959:   PetscMemzero(offsets, 32 * sizeof(PetscInt));
6960:   DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
6961:   /* Compress out points not in the section */
6962:   PetscSectionGetChart(section, &pStart, &pEnd);
6963:   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6964:     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6965:       points[q*2]   = points[p];
6966:       points[q*2+1] = points[p+1];
6967:       ++q;
6968:     }
6969:   }
6970:   numPoints = q;
6971:   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6972:     PetscInt fdof;

6974:     PetscSectionGetDof(section, points[p], &dof);
6975:     for (f = 0; f < numFields; ++f) {
6976:       PetscSectionGetFieldDof(section, points[p], f, &fdof);
6977:       offsets[f+1] += fdof;
6978:     }
6979:     numIndices += dof;
6980:   }
6981:   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];

6983:   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
6984:   DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);
6985:   if (numFields) {
6986:     for (p = 0; p < numPoints*2; p += 2) {
6987:       PetscInt o = points[p+1];
6988:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
6989:       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
6990:     }
6991:   } else {
6992:     for (p = 0, off = 0; p < numPoints*2; p += 2) {
6993:       PetscInt o = points[p+1];
6994:       PetscSectionGetOffset(globalSection, points[p], &globalOff);
6995:       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
6996:     }
6997:   }
6998:   if (useGlobalDefault && !useDefault) {
6999:     PetscSectionDestroy(&globalSection);
7000:   }
7001:   if (mesh->printSetValues) {DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);}
7002:   MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
7003:   if (ierr) {
7004:     PetscMPIInt    rank;
7005:     PetscErrorCode ierr2;

7007:     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
7008:     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
7009:     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
7010:     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
7011: 
7012:   }
7013:   DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);
7014:   DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);
7015:   return(0);
7016: }

7020: PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
7021: {
7022:   DM_Plex       *mesh = (DM_Plex*) dm->data;
7023:   PetscInt       dim;

7028:   DMPlexGetDimension(dm, &dim);
7029:   if (cMax) *cMax = mesh->hybridPointMax[dim];
7030:   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
7031:   if (eMax) *eMax = mesh->hybridPointMax[1];
7032:   if (vMax) *vMax = mesh->hybridPointMax[0];
7033:   return(0);
7034: }

7038: PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
7039: {
7040:   DM_Plex       *mesh = (DM_Plex*) dm->data;
7041:   PetscInt       dim;

7046:   DMPlexGetDimension(dm, &dim);
7047:   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
7048:   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
7049:   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
7050:   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
7051:   return(0);
7052: }

7056: PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
7057: {
7058:   DM_Plex *mesh = (DM_Plex*) dm->data;

7063:   *cellHeight = mesh->vtkCellHeight;
7064:   return(0);
7065: }

7069: PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
7070: {
7071:   DM_Plex *mesh = (DM_Plex*) dm->data;

7075:   mesh->vtkCellHeight = cellHeight;
7076:   return(0);
7077: }

7081: /* We can easily have a form that takes an IS instead */
7082: PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
7083: {
7084:   PetscSection   section, globalSection;
7085:   PetscInt      *numbers, p;

7089:   PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);
7090:   PetscSectionSetChart(section, pStart, pEnd);
7091:   for (p = pStart; p < pEnd; ++p) {
7092:     PetscSectionSetDof(section, p, 1);
7093:   }
7094:   PetscSectionSetUp(section);
7095:   PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);
7096:   PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);
7097:   for (p = pStart; p < pEnd; ++p) {
7098:     PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);
7099:   }
7100:   ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);
7101:   PetscSectionDestroy(&section);
7102:   PetscSectionDestroy(&globalSection);
7103:   return(0);
7104: }

7108: PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
7109: {
7110:   DM_Plex       *mesh = (DM_Plex*) dm->data;
7111:   PetscInt       cellHeight, cStart, cEnd, cMax;

7116:   if (!mesh->globalCellNumbers) {
7117:     DMPlexGetVTKCellHeight(dm, &cellHeight);
7118:     DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
7119:     DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);
7120:     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
7121:     DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);
7122:   }
7123:   *globalCellNumbers = mesh->globalCellNumbers;
7124:   return(0);
7125: }

7129: PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
7130: {
7131:   DM_Plex       *mesh = (DM_Plex*) dm->data;
7132:   PetscInt       vStart, vEnd, vMax;

7137:   if (!mesh->globalVertexNumbers) {
7138:     DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
7139:     DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);
7140:     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
7141:     DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);
7142:   }
7143:   *globalVertexNumbers = mesh->globalVertexNumbers;
7144:   return(0);
7145: }


7150: /*@C
7151:   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7152:   the local section and an SF describing the section point overlap.

7154:   Input Parameters:
7155:   + s - The PetscSection for the local field layout
7156:   . sf - The SF describing parallel layout of the section points
7157:   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7158:   . label - The label specifying the points
7159:   - labelValue - The label stratum specifying the points

7161:   Output Parameter:
7162:   . gsection - The PetscSection for the global field layout

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

7166:   Level: developer

7168: .seealso: PetscSectionCreate()
7169: @*/
7170: PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7171: {
7172:   PetscInt      *neg;
7173:   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;

7177:   PetscSectionCreate(s->atlasLayout.comm, gsection);
7178:   PetscSectionGetChart(s, &pStart, &pEnd);
7179:   PetscSectionSetChart(*gsection, pStart, pEnd);
7180:   PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);
7181:   /* Mark ghost points with negative dof */
7182:   for (p = pStart; p < pEnd; ++p) {
7183:     PetscInt value;

7185:     DMLabelGetValue(label, p, &value);
7186:     if (value != labelValue) continue;
7187:     PetscSectionGetDof(s, p, &dof);
7188:     PetscSectionSetDof(*gsection, p, dof);
7189:     PetscSectionGetConstraintDof(s, p, &cdof);
7190:     if (!includeConstraints && cdof > 0) {PetscSectionSetConstraintDof(*gsection, p, cdof);}
7191:     neg[p-pStart] = -(dof+1);
7192:   }
7193:   PetscSectionSetUpBC(*gsection);
7194:   PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);
7195:   if (nroots >= 0) {
7196:     if (nroots > pEnd - pStart) {
7197:       PetscInt *tmpDof;
7198:       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7199:       PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);
7200:       PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);
7201:       PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);
7202:       for (p = pStart; p < pEnd; ++p) {
7203:         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7204:       }
7205:       PetscFree(tmpDof);
7206:     } else {
7207:       PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);
7208:       PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);
7209:     }
7210:   }
7211:   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7212:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7213:     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;

7215:     (*gsection)->atlasOff[p] = off;

7217:     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7218:   }
7219:   MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);
7220:   globalOff -= off;
7221:   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7222:     (*gsection)->atlasOff[p] += globalOff;

7224:     neg[p] = -((*gsection)->atlasOff[p]+1);
7225:   }
7226:   /* Put in negative offsets for ghost points */
7227:   if (nroots >= 0) {
7228:     if (nroots > pEnd - pStart) {
7229:       PetscInt *tmpOff;
7230:       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7231:       PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);
7232:       PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);
7233:       PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);
7234:       for (p = pStart; p < pEnd; ++p) {
7235:         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7236:       }
7237:       PetscFree(tmpOff);
7238:     } else {
7239:       PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);
7240:       PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);
7241:     }
7242:   }
7243:   PetscFree(neg);
7244:   return(0);
7245: }