Actual source code: ex2.c

  1: static char help[] = "Create a mesh, refine and coarsen simultaneously, and transfer a field\n\n";

  3: #include <petscds.h>
  4: #include <petscdmplex.h>
  5: #include <petscdmforest.h>
  6: #include <petscoptions.h>

  8: static PetscErrorCode AddIdentityLabel(DM dm)
  9: {
 10:   PetscInt pStart, pEnd, p;

 12:   DMCreateLabel(dm, "identity");
 13:   DMPlexGetChart(dm, &pStart, &pEnd);
 14:   for (p = pStart; p < pEnd; p++) DMSetLabelValue(dm, "identity", p, p);
 15:   return 0;
 16: }

 18: static PetscErrorCode CreateAdaptivityLabel(DM forest, DMLabel *adaptLabel)
 19: {
 20:   DMLabel  identLabel;
 21:   PetscInt cStart, cEnd, c;

 23:   DMLabelCreate(PETSC_COMM_SELF, "adapt", adaptLabel);
 24:   DMLabelSetDefaultValue(*adaptLabel, DM_ADAPT_COARSEN);
 25:   DMGetLabel(forest, "identity", &identLabel);
 26:   DMForestGetCellChart(forest, &cStart, &cEnd);
 27:   for (c = cStart; c < cEnd; c++) {
 28:     PetscInt basePoint;

 30:     DMLabelGetValue(identLabel, c, &basePoint);
 31:     if (!basePoint) DMLabelSetValue(*adaptLabel, c, DM_ADAPT_REFINE);
 32:   }
 33:   return 0;
 34: }

 36: static PetscErrorCode LinearFunction(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx)
 37: {
 39:   u[0] = (x[0] * 2.0 + 1.) + (x[1] * 20.0 + 10.) + ((dim == 3) ? (x[2] * 200.0 + 100.) : 0.);
 40:   return 0;
 41: }

 43: static PetscErrorCode MultiaffineFunction(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx)
 44: {
 46:   u[0] = (x[0] * 1.0 + 2.0) * (x[1] * 3.0 - 4.0) * ((dim == 3) ? (x[2] * 5.0 + 6.0) : 1.);
 47:   return 0;
 48: }

 50: static PetscErrorCode CoordsFunction(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx)
 51: {
 52:   PetscInt f;

 55:   for (f = 0; f < Nf; f++) u[f] = x[f];
 56:   return 0;
 57: }

 59: typedef struct _bc_func_ctx {
 60:   PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
 61:   PetscInt dim;
 62:   PetscInt Nf;
 63:   void    *ctx;
 64: } bc_func_ctx;

 66: static PetscErrorCode bc_func_fv(PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, void *ctx)
 67: {
 68:   bc_func_ctx *bcCtx;

 70:   bcCtx = (bc_func_ctx *)ctx;
 71:   (bcCtx->func)(bcCtx->dim, time, c, bcCtx->Nf, xG, bcCtx->ctx);
 72:   return 0;
 73: }

 75: static PetscErrorCode IdentifyBadPoints(DM dm, Vec vec, PetscReal tol)
 76: {
 77:   DM           dmplex;
 78:   PetscInt     p, pStart, pEnd, maxDof;
 79:   Vec          vecLocal;
 80:   DMLabel      depthLabel;
 81:   PetscSection section;

 83:   DMCreateLocalVector(dm, &vecLocal);
 84:   DMGlobalToLocalBegin(dm, vec, INSERT_VALUES, vecLocal);
 85:   DMGlobalToLocalEnd(dm, vec, INSERT_VALUES, vecLocal);
 86:   DMConvert(dm, DMPLEX, &dmplex);
 87:   DMPlexGetChart(dmplex, &pStart, &pEnd);
 88:   DMPlexGetDepthLabel(dmplex, &depthLabel);
 89:   DMGetLocalSection(dmplex, &section);
 90:   PetscSectionGetMaxDof(section, &maxDof);
 91:   for (p = pStart; p < pEnd; p++) {
 92:     PetscInt     s, c, cSize, parent, childID, numChildren;
 93:     PetscInt     cl, closureSize, *closure = NULL;
 94:     PetscScalar *values = NULL;
 95:     PetscBool    bad    = PETSC_FALSE;

 97:     VecGetValuesSection(vecLocal, section, p, &values);
 98:     PetscSectionGetDof(section, p, &cSize);
 99:     for (c = 0; c < cSize; c++) {
100:       PetscReal absDiff = PetscAbsScalar(values[c]);
101:       if (absDiff > tol) {
102:         bad = PETSC_TRUE;
103:         break;
104:       }
105:     }
106:     if (!bad) continue;
107:     PetscPrintf(PETSC_COMM_SELF, "Bad point %" PetscInt_FMT "\n", p);
108:     DMLabelGetValue(depthLabel, p, &s);
109:     PetscPrintf(PETSC_COMM_SELF, "  Depth %" PetscInt_FMT "\n", s);
110:     DMPlexGetTransitiveClosure(dmplex, p, PETSC_TRUE, &closureSize, &closure);
111:     for (cl = 0; cl < closureSize; cl++) {
112:       PetscInt cp = closure[2 * cl];
113:       DMPlexGetTreeParent(dmplex, cp, &parent, &childID);
114:       if (parent != cp) PetscPrintf(PETSC_COMM_SELF, "  Closure point %" PetscInt_FMT " (%" PetscInt_FMT ") child of %" PetscInt_FMT " (ID %" PetscInt_FMT ")\n", cl, cp, parent, childID);
115:       DMPlexGetTreeChildren(dmplex, cp, &numChildren, NULL);
116:       if (numChildren) PetscPrintf(PETSC_COMM_SELF, "  Closure point %" PetscInt_FMT " (%" PetscInt_FMT ") is parent\n", cl, cp);
117:     }
118:     DMPlexRestoreTransitiveClosure(dmplex, p, PETSC_TRUE, &closureSize, &closure);
119:     for (c = 0; c < cSize; c++) {
120:       PetscReal absDiff = PetscAbsScalar(values[c]);
121:       if (absDiff > tol) PetscPrintf(PETSC_COMM_SELF, "  Bad dof %" PetscInt_FMT "\n", c);
122:     }
123:   }
124:   DMDestroy(&dmplex);
125:   VecDestroy(&vecLocal);
126:   return 0;
127: }

129: int main(int argc, char **argv)
130: {
131:   MPI_Comm comm;
132:   DM       base, preForest, postForest;
133:   PetscInt dim, Nf          = 1;
134:   PetscInt step, adaptSteps = 1;
135:   PetscInt preCount, postCount;
136:   Vec      preVec, postVecTransfer, postVecExact;
137:   PetscErrorCode (*funcs[1])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *) = {MultiaffineFunction};
138:   void       *ctxs[1]                                                                                 = {NULL};
139:   PetscReal   diff, tol = PETSC_SMALL;
140:   PetscBool   linear                = PETSC_FALSE;
141:   PetscBool   coords                = PETSC_FALSE;
142:   PetscBool   useFV                 = PETSC_FALSE;
143:   PetscBool   conv                  = PETSC_FALSE;
144:   PetscBool   transfer_from_base[2] = {PETSC_TRUE, PETSC_FALSE};
145:   PetscBool   use_bcs               = PETSC_TRUE;
146:   bc_func_ctx bcCtx;
147:   DMLabel     adaptLabel;

150:   PetscInitialize(&argc, &argv, NULL, help);
151:   comm = PETSC_COMM_WORLD;
152:   PetscOptionsBegin(comm, "", "DMForestTransferVec() Test Options", "DMFOREST");
153:   PetscOptionsBool("-linear", "Transfer a simple linear function", "ex2.c", linear, &linear, NULL);
154:   PetscOptionsBool("-coords", "Transfer a simple coordinate function", "ex2.c", coords, &coords, NULL);
155:   PetscOptionsBool("-use_fv", "Use a finite volume approximation", "ex2.c", useFV, &useFV, NULL);
156:   PetscOptionsBool("-test_convert", "Test conversion to DMPLEX", NULL, conv, &conv, NULL);
157:   PetscOptionsBool("-transfer_from_base", "Transfer a vector from base DM to DMForest", "ex2.c", transfer_from_base[0], &transfer_from_base[0], NULL);
158:   transfer_from_base[1] = transfer_from_base[0];
159:   PetscOptionsBool("-transfer_from_base_steps", "Transfer a vector from base DM to the latest DMForest after the adaptivity steps", "ex2.c", transfer_from_base[1], &transfer_from_base[1], NULL);
160:   PetscOptionsBool("-use_bcs", "Use dirichlet boundary conditions", "ex2.c", use_bcs, &use_bcs, NULL);
161:   PetscOptionsBoundedInt("-adapt_steps", "Number of adaptivity steps", "ex2.c", adaptSteps, &adaptSteps, NULL, 0);
162:   PetscOptionsEnd();

164:   tol = PetscMax(1.e-10, tol); /* XXX fix for quadruple precision -> why do I need to do this? */

166:   /* the base mesh */
167:   DMCreate(comm, &base);
168:   DMSetType(base, DMPLEX);
169:   DMSetFromOptions(base);

171:   AddIdentityLabel(base);
172:   DMGetDimension(base, &dim);

174:   if (linear) funcs[0] = LinearFunction;
175:   if (coords) {
176:     funcs[0] = CoordsFunction;
177:     Nf       = dim;
178:   }

180:   bcCtx.func = funcs[0];
181:   bcCtx.dim  = dim;
182:   bcCtx.Nf   = Nf;
183:   bcCtx.ctx  = NULL;

185:   if (useFV) {
186:     PetscFV      fv;
187:     PetscLimiter limiter;
188:     DM           baseFV;

190:     DMPlexConstructGhostCells(base, NULL, NULL, &baseFV);
191:     DMViewFromOptions(baseFV, NULL, "-fv_dm_view");
192:     DMDestroy(&base);
193:     base = baseFV;
194:     PetscFVCreate(PETSC_COMM_SELF, &fv);
195:     PetscFVSetSpatialDimension(fv, dim);
196:     PetscFVSetType(fv, PETSCFVLEASTSQUARES);
197:     PetscFVSetNumComponents(fv, Nf);
198:     PetscLimiterCreate(comm, &limiter);
199:     PetscLimiterSetType(limiter, PETSCLIMITERNONE);
200:     PetscFVSetLimiter(fv, limiter);
201:     PetscLimiterDestroy(&limiter);
202:     PetscFVSetFromOptions(fv);
203:     DMSetField(base, 0, NULL, (PetscObject)fv);
204:     PetscFVDestroy(&fv);
205:   } else {
206:     PetscFE fe;

208:     PetscFECreateDefault(comm, dim, Nf, PETSC_FALSE, NULL, PETSC_DEFAULT, &fe);
209:     DMSetField(base, 0, NULL, (PetscObject)fe);
210:     PetscFEDestroy(&fe);
211:   }
212:   DMCreateDS(base);

214:   if (use_bcs) {
215:     PetscInt ids[] = {1, 2, 3, 4, 5, 6};
216:     DMLabel  label;

218:     DMGetLabel(base, "marker", &label);
219:     DMAddBoundary(base, DM_BC_ESSENTIAL, "bc", label, 2 * dim, ids, 0, 0, NULL, useFV ? (void (*)(void))bc_func_fv : (void (*)(void))funcs[0], NULL, useFV ? (void *)&bcCtx : NULL, NULL);
220:   }
221:   DMViewFromOptions(base, NULL, "-dm_base_view");

223:   /* the pre adaptivity forest */
224:   DMCreate(comm, &preForest);
225:   DMSetType(preForest, (dim == 2) ? DMP4EST : DMP8EST);
226:   DMCopyDisc(base, preForest);
227:   DMForestSetBaseDM(preForest, base);
228:   DMForestSetMinimumRefinement(preForest, 0);
229:   DMForestSetInitialRefinement(preForest, 1);
230:   DMSetFromOptions(preForest);
231:   DMSetUp(preForest);
232:   DMViewFromOptions(preForest, NULL, "-dm_pre_view");

234:   /* the pre adaptivity field */
235:   DMCreateGlobalVector(preForest, &preVec);
236:   DMProjectFunction(preForest, 0., funcs, ctxs, INSERT_VALUES, preVec);
237:   VecViewFromOptions(preVec, NULL, "-vec_pre_view");

239:   /* communicate between base and pre adaptivity forest */
240:   if (transfer_from_base[0]) {
241:     Vec baseVec, baseVecMapped;

243:     DMGetGlobalVector(base, &baseVec);
244:     DMProjectFunction(base, 0., funcs, ctxs, INSERT_VALUES, baseVec);
245:     PetscObjectSetName((PetscObject)baseVec, "Function Base");
246:     VecViewFromOptions(baseVec, NULL, "-vec_base_view");

248:     DMGetGlobalVector(preForest, &baseVecMapped);
249:     DMForestTransferVecFromBase(preForest, baseVec, baseVecMapped);
250:     VecViewFromOptions(baseVecMapped, NULL, "-vec_map_base_view");

252:     /* compare */
253:     VecAXPY(baseVecMapped, -1., preVec);
254:     VecViewFromOptions(baseVecMapped, NULL, "-vec_map_diff_view");
255:     VecNorm(baseVecMapped, NORM_2, &diff);

257:     /* output */
258:     if (diff < tol) {
259:       PetscPrintf(comm, "DMForestTransferVecFromBase() passes.\n");
260:     } else {
261:       PetscPrintf(comm, "DMForestTransferVecFromBase() fails with error %g and tolerance %g\n", (double)diff, (double)tol);
262:     }

264:     DMRestoreGlobalVector(base, &baseVec);
265:     DMRestoreGlobalVector(preForest, &baseVecMapped);
266:   }

268:   for (step = 0; step < adaptSteps; ++step) {
269:     if (!transfer_from_base[1]) PetscObjectGetReference((PetscObject)preForest, &preCount);

271:     /* adapt */
272:     CreateAdaptivityLabel(preForest, &adaptLabel);
273:     DMForestTemplate(preForest, comm, &postForest);
274:     if (step) DMForestSetAdaptivityLabel(postForest, adaptLabel);
275:     DMLabelDestroy(&adaptLabel);
276:     DMSetUp(postForest);
277:     DMViewFromOptions(postForest, NULL, "-dm_post_view");

279:     /* transfer */
280:     DMCreateGlobalVector(postForest, &postVecTransfer);
281:     DMForestTransferVec(preForest, preVec, postForest, postVecTransfer, PETSC_TRUE, 0.0);
282:     VecViewFromOptions(postVecTransfer, NULL, "-vec_post_transfer_view");

284:     /* the exact post adaptivity field */
285:     DMCreateGlobalVector(postForest, &postVecExact);
286:     DMProjectFunction(postForest, 0., funcs, ctxs, INSERT_VALUES, postVecExact);
287:     VecViewFromOptions(postVecExact, NULL, "-vec_post_exact_view");

289:     /* compare */
290:     VecAXPY(postVecExact, -1., postVecTransfer);
291:     VecViewFromOptions(postVecExact, NULL, "-vec_diff_view");
292:     VecNorm(postVecExact, NORM_2, &diff);

294:     /* output */
295:     if (diff < tol) {
296:       PetscPrintf(comm, "DMForestTransferVec() passes.\n");
297:     } else {
298:       PetscPrintf(comm, "DMForestTransferVec() fails with error %g and tolerance %g\n", (double)diff, (double)tol);
299:       IdentifyBadPoints(postForest, postVecExact, tol);
300:     }
301:     VecDestroy(&postVecExact);

303:     /* disconnect preForest from postForest if we don't test the transfer throughout the entire refinement process */
304:     if (!transfer_from_base[1]) {
305:       DMForestSetAdaptivityForest(postForest, NULL);
306:       PetscObjectGetReference((PetscObject)preForest, &postCount);
308:     }

310:     if (conv) {
311:       DM dmConv;

313:       DMConvert(postForest, DMPLEX, &dmConv);
314:       DMViewFromOptions(dmConv, NULL, "-dm_conv_view");
315:       DMPlexCheckCellShape(dmConv, PETSC_TRUE, PETSC_DETERMINE);
316:       DMDestroy(&dmConv);
317:     }

319:     VecDestroy(&preVec);
320:     DMDestroy(&preForest);

322:     preVec    = postVecTransfer;
323:     preForest = postForest;
324:   }

326:   if (transfer_from_base[1]) {
327:     Vec baseVec, baseVecMapped;

329:     /* communicate between base and last adapted forest */
330:     DMGetGlobalVector(base, &baseVec);
331:     DMProjectFunction(base, 0., funcs, ctxs, INSERT_VALUES, baseVec);
332:     PetscObjectSetName((PetscObject)baseVec, "Function Base");
333:     VecViewFromOptions(baseVec, NULL, "-vec_base_view");

335:     DMGetGlobalVector(preForest, &baseVecMapped);
336:     DMForestTransferVecFromBase(preForest, baseVec, baseVecMapped);
337:     VecViewFromOptions(baseVecMapped, NULL, "-vec_map_base_view");

339:     /* compare */
340:     VecAXPY(baseVecMapped, -1., preVec);
341:     VecViewFromOptions(baseVecMapped, NULL, "-vec_map_diff_view");
342:     VecNorm(baseVecMapped, NORM_2, &diff);

344:     /* output */
345:     if (diff < tol) {
346:       PetscPrintf(comm, "DMForestTransferVecFromBase() passes.\n");
347:     } else {
348:       PetscPrintf(comm, "DMForestTransferVecFromBase() fails with error %g and tolerance %g\n", (double)diff, (double)tol);
349:     }

351:     DMRestoreGlobalVector(base, &baseVec);
352:     DMRestoreGlobalVector(preForest, &baseVecMapped);
353:   }

355:   /* cleanup */
356:   VecDestroy(&preVec);
357:   DMDestroy(&preForest);
358:   DMDestroy(&base);
359:   PetscFinalize();
360:   return 0;
361: }

363: /*TEST
364:   testset:
365:     args: -dm_plex_simplex 0 -dm_plex_box_faces 3,3,3 -petscspace_type tensor

367:     test:
368:       output_file: output/ex2_2d.out
369:       suffix: p4est_2d
370:       args: -petscspace_degree 2
371:       nsize: 3
372:       requires: p4est !single

374:     test:
375:       output_file: output/ex2_2d.out
376:       suffix: p4est_2d_deg4
377:       args: -petscspace_degree 4
378:       requires: p4est !single

380:     test:
381:       output_file: output/ex2_2d.out
382:       suffix: p4est_2d_deg8
383:       args: -petscspace_degree 8
384:       requires: p4est !single

386:     test:
387:       output_file: output/ex2_steps2.out
388:       suffix: p4est_2d_deg2_steps2
389:       args: -petscspace_degree 2 -coords -adapt_steps 2
390:       nsize: 3
391:       requires: p4est !single

393:     test:
394:       output_file: output/ex2_steps3.out
395:       suffix: p4est_2d_deg3_steps3
396:       args: -petscspace_degree 3 -coords -adapt_steps 3 -petscdualspace_lagrange_node_type equispaced -petscdualspace_lagrange_node_endpoints 1
397:       nsize: 3
398:       requires: p4est !single

400:     test:
401:       output_file: output/ex2_steps3.out
402:       suffix: p4est_2d_deg3_steps3_L2_periodic
403:       args: -petscspace_degree 3 -petscdualspace_lagrange_continuity 0 -coords -adapt_steps 3 -dm_plex_box_bd periodic,periodic -use_bcs 0 -petscdualspace_lagrange_node_type equispaced
404:       nsize: 3
405:       requires: p4est !single

407:     test:
408:       output_file: output/ex2_steps3.out
409:       suffix: p4est_3d_deg2_steps3_L2_periodic
410:       args: -dm_plex_dim 3 -petscspace_degree 2 -petscdualspace_lagrange_continuity 0 -coords -adapt_steps 3 -dm_plex_box_bd periodic,periodic,periodic -use_bcs 0
411:       nsize: 3
412:       requires: p4est !single

414:     test:
415:       output_file: output/ex2_steps2.out
416:       suffix: p4est_3d_deg2_steps2
417:       args: -dm_plex_dim 3 -petscspace_degree 2 -coords -adapt_steps 2
418:       nsize: 3
419:       requires: p4est !single

421:     test:
422:       output_file: output/ex2_steps3.out
423:       suffix: p4est_3d_deg3_steps3
424:       args: -dm_plex_dim 3 -petscspace_degree 3 -coords -adapt_steps 3 -petscdualspace_lagrange_node_type equispaced -petscdualspace_lagrange_node_endpoints 1
425:       nsize: 3
426:       requires: p4est !single

428:     test:
429:       output_file: output/ex2_3d.out
430:       suffix: p4est_3d
431:       args: -dm_plex_dim 3 -petscspace_degree 1
432:       nsize: 3
433:       requires: p4est !single

435:     test:
436:       output_file: output/ex2_3d.out
437:       suffix: p4est_3d_deg3
438:       args: -dm_plex_dim 3 -petscspace_degree 3
439:       nsize: 3
440:       requires: p4est !single

442:     test:
443:       output_file: output/ex2_2d.out
444:       suffix: p4est_2d_deg2_coords
445:       args: -petscspace_degree 2 -coords
446:       nsize: 3
447:       requires: p4est !single

449:     test:
450:       output_file: output/ex2_3d.out
451:       suffix: p4est_3d_deg2_coords
452:       args: -dm_plex_dim 3 -petscspace_degree 2 -coords
453:       nsize: 3
454:       requires: p4est !single

456:     test:
457:       suffix: p4est_3d_nans
458:       args: -dm_plex_dim 3 -dm_forest_partition_overlap 1 -test_convert -petscspace_degree 1
459:       nsize: 2
460:       requires: p4est !single

462:     test:
463:       TODO: not broken, but the 3D case below is broken, so I do not trust this one
464:       output_file: output/ex2_steps2.out
465:       suffix: p4est_2d_tfb_distributed_nc
466:       args: -petscspace_degree 3 -dm_forest_maximum_refinement 2 -dm_p4est_refine_pattern hash -use_bcs 0 -coords -adapt_steps 2 -petscpartitioner_type shell -petscpartitioner_shell_random
467:       nsize: 3
468:       requires: p4est !single

470:     test:
471:       TODO: broken
472:       output_file: output/ex2_steps2.out
473:       suffix: p4est_3d_tfb_distributed_nc
474:       args: -dm_plex_dim 3 -petscspace_degree 2 -dm_forest_maximum_refinement 2 -dm_p4est_refine_pattern hash -use_bcs 0 -coords -adapt_steps 2 -petscpartitioner_type shell -petscpartitioner_shell_random
475:       nsize: 3
476:       requires: p4est !single

478:   testset:
479:     args: -petscspace_type tensor -dm_coord_space 0 -dm_plex_transform_type refine_tobox

481:     test:
482:       TODO: broken
483:       output_file: output/ex2_3d.out
484:       suffix: p4est_3d_transfer_fails
485:       args: -petscspace_degree 1 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/doublet-tet.msh -adapt_steps 1 -dm_forest_initial_refinement 1 -use_bcs 0 -dm_refine
486:       requires: p4est !single

488:     test:
489:       TODO: broken
490:       output_file: output/ex2_steps2_notfb.out
491:       suffix: p4est_3d_transfer_fails_2
492:       args: -petscspace_degree 1 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/doublet-tet.msh -adapt_steps 2 -dm_forest_initial_refinement 0 -transfer_from_base 0 -use_bcs 0 -dm_refine
493:       requires: p4est !single

495:     test:
496:       output_file: output/ex2_steps2.out
497:       suffix: p4est_3d_multi_transfer_s2t
498:       args: -petscspace_degree 3 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/doublet-tet.msh -adapt_steps 2 -dm_forest_initial_refinement 1 -petscdualspace_lagrange_continuity 0 -use_bcs 0 -dm_refine 1
499:       requires: p4est !single

501:     test:
502:       output_file: output/ex2_steps2.out
503:       suffix: p4est_3d_coords_transfer_s2t
504:       args: -petscspace_degree 3 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/doublet-tet.msh -adapt_steps 2 -dm_forest_initial_refinement 1 -petscdualspace_lagrange_continuity 0 -coords -use_bcs 0 -dm_refine 1
505:       requires: p4est !single

507:   testset:
508:     args: -dm_plex_simplex 0 -dm_plex_box_faces 3,3,3

510:     test:
511:       output_file: output/ex2_2d_fv.out
512:       suffix: p4est_2d_fv
513:       args: -transfer_from_base 0 -use_fv -linear -dm_forest_partition_overlap 1
514:       nsize: 3
515:       requires: p4est !single

517:     test:
518:       TODO: broken (codimension adjacency)
519:       output_file: output/ex2_2d_fv.out
520:       suffix: p4est_2d_fv_adjcodim
521:       args: -transfer_from_base 0 -use_fv -linear -dm_forest_partition_overlap 1 -dm_forest_adjacency_codimension 1
522:       nsize: 2
523:       requires: p4est !single

525:     test:
526:       TODO: broken (dimension adjacency)
527:       output_file: output/ex2_2d_fv.out
528:       suffix: p4est_2d_fv_adjdim
529:       args: -transfer_from_base 0 -use_fv -linear -dm_forest_partition_overlap 1 -dm_forest_adjacency_dimension 1
530:       nsize: 2
531:       requires: p4est !single

533:     test:
534:       output_file: output/ex2_2d_fv.out
535:       suffix: p4est_2d_fv_zerocells
536:       args: -transfer_from_base 0 -use_fv -linear -dm_forest_partition_overlap 1
537:       nsize: 10
538:       requires: p4est !single

540:     test:
541:       output_file: output/ex2_3d_fv.out
542:       suffix: p4est_3d_fv
543:       args: -dm_plex_dim 3 -transfer_from_base 0 -use_fv -linear -dm_forest_partition_overlap 1
544:       nsize: 3
545:       requires: p4est !single

547: TEST*/