Actual source code: dmadapt.c

  1: #include <petscdmadaptor.h>
  2: #include <petscdmplex.h>
  3: #include <petscdmforest.h>
  4: #include <petscds.h>
  5: #include <petscblaslapack.h>

  7: #include <petsc/private/dmadaptorimpl.h>
  8: #include <petsc/private/dmpleximpl.h>
  9: #include <petsc/private/petscfeimpl.h>

 11: static PetscErrorCode DMAdaptorSimpleErrorIndicator_Private(DMAdaptor, PetscInt, PetscInt, const PetscScalar *, const PetscScalar *, const PetscFVCellGeom *, PetscReal *, void *);

 13: static PetscErrorCode DMAdaptorTransferSolution_Exact_Private(DMAdaptor adaptor, DM dm, Vec u, DM adm, Vec au, void *ctx)
 14: {
 16:   DMProjectFunction(adm, 0.0, adaptor->exactSol, adaptor->exactCtx, INSERT_ALL_VALUES, au);
 17:   return 0;
 18: }

 20: /*@
 21:   DMAdaptorCreate - Create a DMAdaptor object. Its purpose is to construct a adaptation DMLabel or metric Vec that can be used to modify the DM.

 23:   Collective

 25:   Input Parameter:
 26: . comm - The communicator for the DMAdaptor object

 28:   Output Parameter:
 29: . adaptor   - The DMAdaptor object

 31:   Level: beginner

 33: .seealso: DMAdaptorDestroy(), DMAdaptorAdapt()
 34: @*/
 35: PetscErrorCode DMAdaptorCreate(MPI_Comm comm, DMAdaptor *adaptor)
 36: {
 37:   VecTaggerBox     refineBox, coarsenBox;

 40:   PetscSysInitializePackage();
 41:   PetscHeaderCreate(*adaptor, DM_CLASSID, "DMAdaptor", "DM Adaptor", "SNES", comm, DMAdaptorDestroy, DMAdaptorView);

 43:   (*adaptor)->monitor = PETSC_FALSE;
 44:   (*adaptor)->adaptCriterion = DM_ADAPTATION_NONE;
 45:   (*adaptor)->numSeq = 1;
 46:   (*adaptor)->Nadapt = -1;
 47:   (*adaptor)->refinementFactor = 2.0;
 48:   (*adaptor)->ops->computeerrorindicator = DMAdaptorSimpleErrorIndicator_Private;
 49:   refineBox.min = refineBox.max = PETSC_MAX_REAL;
 50:   VecTaggerCreate(PetscObjectComm((PetscObject) *adaptor), &(*adaptor)->refineTag);
 51:   PetscObjectSetOptionsPrefix((PetscObject) (*adaptor)->refineTag, "refine_");
 52:   VecTaggerSetType((*adaptor)->refineTag, VECTAGGERABSOLUTE);
 53:   VecTaggerAbsoluteSetBox((*adaptor)->refineTag, &refineBox);
 54:   coarsenBox.min = coarsenBox.max = PETSC_MAX_REAL;
 55:   VecTaggerCreate(PetscObjectComm((PetscObject) *adaptor), &(*adaptor)->coarsenTag);
 56:   PetscObjectSetOptionsPrefix((PetscObject) (*adaptor)->coarsenTag, "coarsen_");
 57:   VecTaggerSetType((*adaptor)->coarsenTag, VECTAGGERABSOLUTE);
 58:   VecTaggerAbsoluteSetBox((*adaptor)->coarsenTag, &coarsenBox);
 59:   return 0;
 60: }

 62: /*@
 63:   DMAdaptorDestroy - Destroys a DMAdaptor object

 65:   Collective on DMAdaptor

 67:   Input Parameter:
 68: . adaptor - The DMAdaptor object

 70:   Level: beginner

 72: .seealso: DMAdaptorCreate(), DMAdaptorAdapt()
 73: @*/
 74: PetscErrorCode DMAdaptorDestroy(DMAdaptor *adaptor)
 75: {
 76:   if (!*adaptor) return 0;
 78:   if (--((PetscObject)(*adaptor))->refct > 0) {
 79:     *adaptor = NULL;
 80:     return 0;
 81:   }
 82:   VecTaggerDestroy(&(*adaptor)->refineTag);
 83:   VecTaggerDestroy(&(*adaptor)->coarsenTag);
 84:   PetscFree2((*adaptor)->exactSol, (*adaptor)->exactCtx);
 85:   PetscHeaderDestroy(adaptor);
 86:   return 0;
 87: }

 89: /*@
 90:   DMAdaptorSetFromOptions - Sets a DMAdaptor object from options

 92:   Collective on DMAdaptor

 94:   Input Parameter:
 95: . adaptor - The DMAdaptor object

 97:   Options Database Keys:
 98: + -adaptor_monitor <bool>        - Monitor the adaptation process
 99: . -adaptor_sequence_num <num>    - Number of adaptations to generate an optimal grid
100: . -adaptor_target_num <num>      - Set the target number of vertices N_adapt, -1 for automatic determination
101: - -adaptor_refinement_factor <r> - Set r such that N_adapt = r^dim N_orig

103:   Level: beginner

105: .seealso: DMAdaptorCreate(), DMAdaptorAdapt()
106: @*/
107: PetscErrorCode DMAdaptorSetFromOptions(DMAdaptor adaptor)
108: {

111:   PetscOptionsBegin(PetscObjectComm((PetscObject) adaptor), "", "DM Adaptor Options", "DMAdaptor");
112:   PetscOptionsBool("-adaptor_monitor", "Monitor the adaptation process", "DMAdaptorMonitor", adaptor->monitor, &adaptor->monitor, NULL);
113:   PetscOptionsInt("-adaptor_sequence_num", "Number of adaptations to generate an optimal grid", "DMAdaptorSetSequenceLength", adaptor->numSeq, &adaptor->numSeq, NULL);
114:   PetscOptionsInt("-adaptor_target_num", "Set the target number of vertices N_adapt, -1 for automatic determination", "DMAdaptor", adaptor->Nadapt, &adaptor->Nadapt, NULL);
115:   PetscOptionsReal("-adaptor_refinement_factor", "Set r such that N_adapt = r^dim N_orig", "DMAdaptor", adaptor->refinementFactor, &adaptor->refinementFactor, NULL);
116:   PetscOptionsEnd();
117:   VecTaggerSetFromOptions(adaptor->refineTag);
118:   VecTaggerSetFromOptions(adaptor->coarsenTag);
119:   return 0;
120: }

122: /*@
123:   DMAdaptorView - Views a DMAdaptor object

125:   Collective on DMAdaptor

127:   Input Parameters:
128: + adaptor     - The DMAdaptor object
129: - viewer - The PetscViewer object

131:   Level: beginner

133: .seealso: DMAdaptorCreate(), DMAdaptorAdapt()
134: @*/
135: PetscErrorCode DMAdaptorView(DMAdaptor adaptor, PetscViewer viewer)
136: {
137:   PetscObjectPrintClassNamePrefixType((PetscObject) adaptor, viewer);
138:   PetscViewerASCIIPrintf(viewer, "DM Adaptor\n");
139:   PetscViewerASCIIPrintf(viewer, "  sequence length: %D\n", adaptor->numSeq);
140:   VecTaggerView(adaptor->refineTag,  viewer);
141:   VecTaggerView(adaptor->coarsenTag, viewer);
142:   return 0;
143: }

145: /*@
146:   DMAdaptorGetSolver - Gets the solver used to produce discrete solutions

148:   Not collective

150:   Input Parameter:
151: . adaptor   - The DMAdaptor object

153:   Output Parameter:
154: . snes - The solver

156:   Level: intermediate

158: .seealso: DMAdaptorSetSolver(), DMAdaptorCreate(), DMAdaptorAdapt()
159: @*/
160: PetscErrorCode DMAdaptorGetSolver(DMAdaptor adaptor, SNES *snes)
161: {
164:   *snes = adaptor->snes;
165:   return 0;
166: }

168: /*@
169:   DMAdaptorSetSolver - Sets the solver used to produce discrete solutions

171:   Not collective

173:   Input Parameters:
174: + adaptor   - The DMAdaptor object
175: - snes - The solver

177:   Level: intermediate

179:   Note: The solver MUST have an attached DM/DS, so that we know the exact solution

181: .seealso: DMAdaptorGetSolver(), DMAdaptorCreate(), DMAdaptorAdapt()
182: @*/
183: PetscErrorCode DMAdaptorSetSolver(DMAdaptor adaptor, SNES snes)
184: {
187:   adaptor->snes = snes;
188:   SNESGetDM(adaptor->snes, &adaptor->idm);
189:   return 0;
190: }

192: /*@
193:   DMAdaptorGetSequenceLength - Gets the number of sequential adaptations

195:   Not collective

197:   Input Parameter:
198: . adaptor - The DMAdaptor object

200:   Output Parameter:
201: . num - The number of adaptations

203:   Level: intermediate

205: .seealso: DMAdaptorSetSequenceLength(), DMAdaptorCreate(), DMAdaptorAdapt()
206: @*/
207: PetscErrorCode DMAdaptorGetSequenceLength(DMAdaptor adaptor, PetscInt *num)
208: {
211:   *num = adaptor->numSeq;
212:   return 0;
213: }

215: /*@
216:   DMAdaptorSetSequenceLength - Sets the number of sequential adaptations

218:   Not collective

220:   Input Parameters:
221: + adaptor - The DMAdaptor object
222: - num - The number of adaptations

224:   Level: intermediate

226: .seealso: DMAdaptorGetSequenceLength(), DMAdaptorCreate(), DMAdaptorAdapt()
227: @*/
228: PetscErrorCode DMAdaptorSetSequenceLength(DMAdaptor adaptor, PetscInt num)
229: {
231:   adaptor->numSeq = num;
232:   return 0;
233: }

235: /*@
236:   DMAdaptorSetUp - After the solver is specified, we create structures for controlling adaptivity

238:   Collective on DMAdaptor

240:   Input Parameters:
241: . adaptor - The DMAdaptor object

243:   Level: beginner

245: .seealso: DMAdaptorCreate(), DMAdaptorAdapt()
246: @*/
247: PetscErrorCode DMAdaptorSetUp(DMAdaptor adaptor)
248: {
249:   PetscDS        prob;
250:   PetscInt       Nf, f;

252:   DMGetDS(adaptor->idm, &prob);
253:   VecTaggerSetUp(adaptor->refineTag);
254:   VecTaggerSetUp(adaptor->coarsenTag);
255:   PetscDSGetNumFields(prob, &Nf);
256:   PetscMalloc2(Nf, &adaptor->exactSol, Nf, &adaptor->exactCtx);
257:   for (f = 0; f < Nf; ++f) {
258:     PetscDSGetExactSolution(prob, f, &adaptor->exactSol[f], &adaptor->exactCtx[f]);
259:     /* TODO Have a flag that forces projection rather than using the exact solution */
260:     if (adaptor->exactSol[0]) DMAdaptorSetTransferFunction(adaptor, DMAdaptorTransferSolution_Exact_Private);
261:   }
262:   return 0;
263: }

265: PetscErrorCode DMAdaptorGetTransferFunction(DMAdaptor adaptor, PetscErrorCode (**tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *))
266: {
267:   *tfunc = adaptor->ops->transfersolution;
268:   return 0;
269: }

271: PetscErrorCode DMAdaptorSetTransferFunction(DMAdaptor adaptor, PetscErrorCode (*tfunc)(DMAdaptor, DM, Vec, DM, Vec, void *))
272: {
273:   adaptor->ops->transfersolution = tfunc;
274:   return 0;
275: }

277: PetscErrorCode DMAdaptorPreAdapt(DMAdaptor adaptor, Vec locX)
278: {
279:   DM             plex;
280:   PetscDS        prob;
281:   PetscObject    obj;
282:   PetscClassId   id;
283:   PetscBool      isForest;

285:   DMConvert(adaptor->idm, DMPLEX, &plex);
286:   DMGetDS(adaptor->idm, &prob);
287:   PetscDSGetDiscretization(prob, 0, &obj);
288:   PetscObjectGetClassId(obj, &id);
289:   DMIsForest(adaptor->idm, &isForest);
290:   if (adaptor->adaptCriterion == DM_ADAPTATION_NONE) {
291:     if (isForest) {adaptor->adaptCriterion = DM_ADAPTATION_LABEL;}
292: #if defined(PETSC_HAVE_PRAGMATIC)
293:     else          {adaptor->adaptCriterion = DM_ADAPTATION_METRIC;}
294: #elif defined(PETSC_HAVE_MMG)
295:     else          {adaptor->adaptCriterion = DM_ADAPTATION_METRIC;}
296: #elif defined(PETSC_HAVE_PARMMG)
297:     else          {adaptor->adaptCriterion = DM_ADAPTATION_METRIC;}
298: #else
299:     else          {adaptor->adaptCriterion = DM_ADAPTATION_REFINE;}
300: #endif
301:   }
302:   if (id == PETSCFV_CLASSID) {adaptor->femType = PETSC_FALSE;}
303:   else                       {adaptor->femType = PETSC_TRUE;}
304:   if (adaptor->femType) {
305:     /* Compute local solution bc */
306:     DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL);
307:   } else {
308:     PetscFV      fvm = (PetscFV) obj;
309:     PetscLimiter noneLimiter;
310:     Vec          grad;

312:     PetscFVGetComputeGradients(fvm, &adaptor->computeGradient);
313:     PetscFVSetComputeGradients(fvm, PETSC_TRUE);
314:     /* Use no limiting when reconstructing gradients for adaptivity */
315:     PetscFVGetLimiter(fvm, &adaptor->limiter);
316:     PetscObjectReference((PetscObject) adaptor->limiter);
317:     PetscLimiterCreate(PetscObjectComm((PetscObject) fvm), &noneLimiter);
318:     PetscLimiterSetType(noneLimiter, PETSCLIMITERNONE);
319:     PetscFVSetLimiter(fvm, noneLimiter);
320:     /* Get FVM data */
321:     DMPlexGetDataFVM(plex, fvm, &adaptor->cellGeom, &adaptor->faceGeom, &adaptor->gradDM);
322:     VecGetDM(adaptor->cellGeom, &adaptor->cellDM);
323:     VecGetArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray);
324:     /* Compute local solution bc */
325:     DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, adaptor->faceGeom, adaptor->cellGeom, NULL);
326:     /* Compute gradients */
327:     DMCreateGlobalVector(adaptor->gradDM, &grad);
328:     DMPlexReconstructGradientsFVM(plex, locX, grad);
329:     DMGetLocalVector(adaptor->gradDM, &adaptor->cellGrad);
330:     DMGlobalToLocalBegin(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad);
331:     DMGlobalToLocalEnd(adaptor->gradDM, grad, INSERT_VALUES, adaptor->cellGrad);
332:     VecDestroy(&grad);
333:     VecGetArrayRead(adaptor->cellGrad, &adaptor->cellGradArray);
334:   }
335:   DMDestroy(&plex);
336:   return 0;
337: }

339: PetscErrorCode DMAdaptorTransferSolution(DMAdaptor adaptor, DM dm, Vec x, DM adm, Vec ax)
340: {
341:   PetscReal      time = 0.0;
342:   Mat            interp;
343:   void          *ctx;

345:   DMGetApplicationContext(dm, &ctx);
346:   if (adaptor->ops->transfersolution) {
347:     (*adaptor->ops->transfersolution)(adaptor, dm, x, adm, ax, ctx);
348:   } else {
349:     switch (adaptor->adaptCriterion) {
350:     case DM_ADAPTATION_LABEL:
351:       DMForestTransferVec(dm, x, adm, ax, PETSC_TRUE, time);
352:       break;
353:     case DM_ADAPTATION_REFINE:
354:     case DM_ADAPTATION_METRIC:
355:       DMCreateInterpolation(dm, adm, &interp, NULL);
356:       MatInterpolate(interp, x, ax);
357:       DMInterpolate(dm, interp, adm);
358:       MatDestroy(&interp);
359:       break;
360:     default: SETERRQ(PetscObjectComm((PetscObject) adaptor), PETSC_ERR_SUP, "No built-in projection for this adaptation criterion: %D", adaptor->adaptCriterion);
361:     }
362:   }
363:   return 0;
364: }

366: PetscErrorCode DMAdaptorPostAdapt(DMAdaptor adaptor)
367: {
368:   PetscDS        prob;
369:   PetscObject    obj;
370:   PetscClassId   id;

372:   DMGetDS(adaptor->idm, &prob);
373:   PetscDSGetDiscretization(prob, 0, &obj);
374:   PetscObjectGetClassId(obj, &id);
375:   if (id == PETSCFV_CLASSID) {
376:     PetscFV fvm = (PetscFV) obj;

378:     PetscFVSetComputeGradients(fvm, adaptor->computeGradient);
379:     /* Restore original limiter */
380:     PetscFVSetLimiter(fvm, adaptor->limiter);

382:     VecRestoreArrayRead(adaptor->cellGeom, &adaptor->cellGeomArray);
383:     VecRestoreArrayRead(adaptor->cellGrad, &adaptor->cellGradArray);
384:     DMRestoreLocalVector(adaptor->gradDM, &adaptor->cellGrad);
385:   }
386:   return 0;
387: }

389: /*
390:   DMAdaptorSimpleErrorIndicator - Just use the integrated gradient as an error indicator

392:   Input Parameters:
393: + adaptor  - The DMAdaptor object
394: . dim      - The topological dimension
395: . cell     - The cell
396: . field    - The field integrated over the cell
397: . gradient - The gradient integrated over the cell
398: . cg       - A PetscFVCellGeom struct
399: - ctx      - A user context

401:   Output Parameter:
402: . errInd   - The error indicator

404: .seealso: DMAdaptorComputeErrorIndicator()
405: */
406: static PetscErrorCode DMAdaptorSimpleErrorIndicator_Private(DMAdaptor adaptor, PetscInt dim, PetscInt Nc, const PetscScalar *field, const PetscScalar *gradient, const PetscFVCellGeom *cg, PetscReal *errInd, void *ctx)
407: {
408:   PetscReal err = 0.;
409:   PetscInt  c, d;

412:   for (c = 0; c < Nc; c++) {
413:     for (d = 0; d < dim; ++d) {
414:       err += PetscSqr(PetscRealPart(gradient[c*dim+d]));
415:     }
416:   }
417:   *errInd = cg->volume * err;
418:   return 0;
419: }

421: static PetscErrorCode DMAdaptorComputeErrorIndicator_Private(DMAdaptor adaptor, DM plex, PetscInt cell, Vec locX, PetscReal *errInd)
422: {
423:   PetscDS         prob;
424:   PetscObject     obj;
425:   PetscClassId    id;
426:   void           *ctx;
427:   PetscQuadrature quad;
428:   PetscInt        dim, d, cdim, Nc;

430:   *errInd = 0.;
431:   DMGetDimension(plex, &dim);
432:   DMGetCoordinateDim(plex, &cdim);
433:   DMGetApplicationContext(plex, &ctx);
434:   DMGetDS(plex, &prob);
435:   PetscDSGetDiscretization(prob, 0, &obj);
436:   PetscObjectGetClassId(obj, &id);
437:   if (id == PETSCFV_CLASSID) {
438:     const PetscScalar *pointSols;
439:     const PetscScalar *pointSol;
440:     const PetscScalar *pointGrad;
441:     PetscFVCellGeom   *cg;

443:     PetscFVGetNumComponents((PetscFV) obj, &Nc);
444:     VecGetArrayRead(locX, &pointSols);
445:     DMPlexPointLocalRead(plex, cell, pointSols, (void *) &pointSol);
446:     DMPlexPointLocalRead(adaptor->gradDM, cell, adaptor->cellGradArray, (void *) &pointGrad);
447:     DMPlexPointLocalRead(adaptor->cellDM, cell, adaptor->cellGeomArray, &cg);
448:     (*adaptor->ops->computeerrorindicator)(adaptor, dim, Nc, pointSol, pointGrad, cg, errInd, ctx);
449:     VecRestoreArrayRead(locX, &pointSols);
450:   } else {
451:     PetscScalar     *x = NULL, *field, *gradient, *interpolant, *interpolantGrad;
452:     PetscFVCellGeom  cg;
453:     PetscFEGeom      fegeom;
454:     const PetscReal *quadWeights;
455:     PetscReal       *coords;
456:     PetscInt         Nb, fc, Nq, qNc, Nf, f, fieldOffset;

458:     fegeom.dim      = dim;
459:     fegeom.dimEmbed = cdim;
460:     PetscDSGetNumFields(prob, &Nf);
461:     PetscFEGetQuadrature((PetscFE) obj, &quad);
462:     DMPlexVecGetClosure(plex, NULL, locX, cell, NULL, &x);
463:     PetscFEGetDimension((PetscFE) obj, &Nb);
464:     PetscFEGetNumComponents((PetscFE) obj, &Nc);
465:     PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
466:     PetscMalloc6(Nc,&field,cdim*Nc,&gradient,cdim*Nq,&coords,Nq,&fegeom.detJ,cdim*cdim*Nq,&fegeom.J,cdim*cdim*Nq,&fegeom.invJ);
467:     PetscMalloc2(Nc, &interpolant, cdim*Nc, &interpolantGrad);
468:     DMPlexComputeCellGeometryFEM(plex, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
469:     DMPlexComputeCellGeometryFVM(plex, cell, &cg.volume, NULL, NULL);
470:     PetscArrayzero(gradient, cdim*Nc);
471:     for (f = 0, fieldOffset = 0; f < Nf; ++f) {
472:       PetscInt qc = 0, q;

474:       PetscDSGetDiscretization(prob, f, &obj);
475:       PetscArrayzero(interpolant,Nc);
476:       PetscArrayzero(interpolantGrad, cdim*Nc);
477:       for (q = 0; q < Nq; ++q) {
478:         PetscFEInterpolateFieldAndGradient_Static((PetscFE) obj, 1, x, &fegeom, q, interpolant, interpolantGrad);
479:         for (fc = 0; fc < Nc; ++fc) {
480:           const PetscReal wt = quadWeights[q*qNc+qc+fc];

482:           field[fc] += interpolant[fc]*wt*fegeom.detJ[q];
483:           for (d = 0; d < cdim; ++d) gradient[fc*cdim+d] += interpolantGrad[fc*dim+d]*wt*fegeom.detJ[q];
484:         }
485:       }
486:       fieldOffset += Nb;
487:       qc          += Nc;
488:     }
489:     PetscFree2(interpolant, interpolantGrad);
490:     DMPlexVecRestoreClosure(plex, NULL, locX, cell, NULL, &x);
491:     for (fc = 0; fc < Nc; ++fc) {
492:       field[fc] /= cg.volume;
493:       for (d = 0; d < cdim; ++d) gradient[fc*cdim+d] /= cg.volume;
494:     }
495:     (*adaptor->ops->computeerrorindicator)(adaptor, dim, Nc, field, gradient, &cg, errInd, ctx);
496:     PetscFree6(field,gradient,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
497:   }
498:   return 0;
499: }

501: static void identityFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
502:                          const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
503:                          const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
504:                          PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
505: {
506:   PetscInt i, j;

508:   for (i = 0; i < dim; ++i) {
509:     for (j = 0; j < dim; ++j) {
510:       f[i+dim*j] = u[i+dim*j];
511:     }
512:   }
513: }

515: static PetscErrorCode DMAdaptorAdapt_Sequence_Private(DMAdaptor adaptor, Vec inx, PetscBool doSolve, DM *adm, Vec *ax)
516: {
517:   PetscDS        prob;
518:   void          *ctx;
519:   MPI_Comm       comm;
520:   PetscInt       numAdapt = adaptor->numSeq, adaptIter;
521:   PetscInt       dim, coordDim, numFields, cStart, cEnd, c;

523:   DMViewFromOptions(adaptor->idm, NULL, "-dm_adapt_pre_view");
524:   VecViewFromOptions(inx, NULL, "-sol_adapt_pre_view");
525:   PetscObjectGetComm((PetscObject) adaptor, &comm);
526:   DMGetDimension(adaptor->idm, &dim);
527:   DMGetCoordinateDim(adaptor->idm, &coordDim);
528:   DMGetApplicationContext(adaptor->idm, &ctx);
529:   DMGetDS(adaptor->idm, &prob);
530:   PetscDSGetNumFields(prob, &numFields);

533:   /* Adapt until nothing changes */
534:   /* Adapt for a specified number of iterates */
535:   for (adaptIter = 0; adaptIter < numAdapt-1; ++adaptIter) PetscViewerASCIIPushTab(PETSC_VIEWER_STDOUT_(comm));
536:   for (adaptIter = 0; adaptIter < numAdapt;   ++adaptIter) {
537:     PetscBool adapted = PETSC_FALSE;
538:     DM        dm      = adaptIter ? *adm : adaptor->idm, odm;
539:     Vec       x       = adaptIter ? *ax  : inx, locX, ox;

541:     DMGetLocalVector(dm, &locX);
542:     DMGlobalToLocalBegin(dm, adaptIter ? *ax : x, INSERT_VALUES, locX);
543:     DMGlobalToLocalEnd(dm, adaptIter ? *ax : x, INSERT_VALUES, locX);
544:     DMAdaptorPreAdapt(adaptor, locX);
545:     if (doSolve) {
546:       SNES snes;

548:       DMAdaptorGetSolver(adaptor, &snes);
549:       SNESSolve(snes, NULL, adaptIter ? *ax : x);
550:     }
551:     /* DMAdaptorMonitor(adaptor);
552:        Print iterate, memory used, DM, solution */
553:     switch (adaptor->adaptCriterion) {
554:     case DM_ADAPTATION_REFINE:
555:       DMRefine(dm, comm, &odm);
557:       adapted = PETSC_TRUE;
558:       break;
559:     case DM_ADAPTATION_LABEL:
560:     {
561:       /* Adapt DM
562:            Create local solution
563:            Reconstruct gradients (FVM) or solve adjoint equation (FEM)
564:            Produce cellwise error indicator */
565:       DM                 plex;
566:       DMLabel            adaptLabel;
567:       IS                 refineIS, coarsenIS;
568:       Vec                errVec;
569:       PetscScalar       *errArray;
570:       const PetscScalar *pointSols;
571:       PetscReal          minMaxInd[2] = {PETSC_MAX_REAL, PETSC_MIN_REAL}, minMaxIndGlobal[2];
572:       PetscInt           nRefine, nCoarsen;

574:       DMConvert(dm, DMPLEX, &plex);
575:       DMLabelCreate(PETSC_COMM_SELF, "adapt", &adaptLabel);
576:       DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd);

578:       VecCreateMPI(PetscObjectComm((PetscObject) adaptor), cEnd-cStart, PETSC_DETERMINE, &errVec);
579:       VecSetUp(errVec);
580:       VecGetArray(errVec, &errArray);
581:       VecGetArrayRead(locX, &pointSols);
582:       for (c = cStart; c < cEnd; ++c) {
583:         PetscReal errInd;

585:         DMAdaptorComputeErrorIndicator_Private(adaptor, plex, c, locX, &errInd);
586:         errArray[c-cStart] = errInd;
587:         minMaxInd[0] = PetscMin(minMaxInd[0], errInd);
588:         minMaxInd[1] = PetscMax(minMaxInd[1], errInd);
589:       }
590:       VecRestoreArrayRead(locX, &pointSols);
591:       VecRestoreArray(errVec, &errArray);
592:       PetscGlobalMinMaxReal(PetscObjectComm((PetscObject) adaptor), minMaxInd, minMaxIndGlobal);
593:       PetscInfo(adaptor, "DMAdaptor: error indicator range (%E, %E)\n", minMaxIndGlobal[0], minMaxIndGlobal[1]);
594:       /*     Compute IS from VecTagger */
595:       VecTaggerComputeIS(adaptor->refineTag, errVec, &refineIS,NULL);
596:       VecTaggerComputeIS(adaptor->coarsenTag, errVec, &coarsenIS,NULL);
597:       ISGetSize(refineIS, &nRefine);
598:       ISGetSize(coarsenIS, &nCoarsen);
599:       PetscInfo(adaptor, "DMAdaptor: numRefine %D, numCoarsen %D\n", nRefine, nCoarsen);
600:       if (nRefine)  DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE,  refineIS);
601:       if (nCoarsen) DMLabelSetStratumIS(adaptLabel, DM_ADAPT_COARSEN, coarsenIS);
602:       ISDestroy(&coarsenIS);
603:       ISDestroy(&refineIS);
604:       VecDestroy(&errVec);
605:       /*     Adapt DM from label */
606:       if (nRefine || nCoarsen) {
607:         DMAdaptLabel(dm, adaptLabel, &odm);
608:         adapted = PETSC_TRUE;
609:       }
610:       DMLabelDestroy(&adaptLabel);
611:       DMDestroy(&plex);
612:     }
613:     break;
614:     case DM_ADAPTATION_METRIC:
615:     {
616:       DM           dmGrad, dmHess, dmMetric;
617:       Vec          xGrad, xHess, metric;
618:       PetscReal    N;
619:       DMLabel      bdLabel = NULL, rgLabel = NULL;
620:       PetscBool    higherOrder = PETSC_FALSE;
621:       PetscInt     Nd = coordDim*coordDim, f, vStart, vEnd;
622:       void       (**funcs)(PetscInt, PetscInt, PetscInt,
623:                            const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
624:                            const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
625:                            PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);

627:       PetscMalloc(1, &funcs);
628:       funcs[0] = identityFunc;

630:       /*     Setup finite element spaces */
631:       DMClone(dm, &dmGrad);
632:       DMClone(dm, &dmHess);
634:       for (f = 0; f < numFields; ++f) {
635:         PetscFE         fe, feGrad, feHess;
636:         PetscDualSpace  Q;
637:         PetscSpace      space;
638:         DM              K;
639:         PetscQuadrature q;
640:         PetscInt        Nc, qorder, p;
641:         const char     *prefix;

643:         PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
644:         PetscFEGetNumComponents(fe, &Nc);
646:         PetscFEGetBasisSpace(fe, &space);
647:         PetscSpaceGetDegree(space, NULL, &p);
648:         if (p > 1) higherOrder = PETSC_TRUE;
649:         PetscFEGetDualSpace(fe, &Q);
650:         PetscDualSpaceGetDM(Q, &K);
651:         DMPlexGetDepthStratum(K, 0, &vStart, &vEnd);
652:         PetscFEGetQuadrature(fe, &q);
653:         PetscQuadratureGetOrder(q, &qorder);
654:         PetscObjectGetOptionsPrefix((PetscObject) fe, &prefix);
655:         PetscFECreateDefault(PetscObjectComm((PetscObject) dmGrad), dim, Nc*coordDim, PETSC_TRUE, prefix, qorder, &feGrad);
656:         PetscFECreateDefault(PetscObjectComm((PetscObject) dmHess), dim, Nc*Nd, PETSC_TRUE, prefix, qorder, &feHess);
657:         DMSetField(dmGrad, f, NULL, (PetscObject)feGrad);
658:         DMSetField(dmHess, f, NULL, (PetscObject)feHess);
659:         DMCreateDS(dmGrad);
660:         DMCreateDS(dmHess);
661:         PetscFEDestroy(&feGrad);
662:         PetscFEDestroy(&feHess);
663:       }
664:       /*     Compute vertexwise gradients from cellwise gradients */
665:       DMCreateLocalVector(dmGrad, &xGrad);
666:       VecViewFromOptions(locX, NULL, "-sol_adapt_loc_pre_view");
667:       DMPlexComputeGradientClementInterpolant(dm, locX, xGrad);
668:       VecViewFromOptions(xGrad, NULL, "-adapt_gradient_view");
669:       /*     Compute vertexwise Hessians from cellwise Hessians */
670:       DMCreateLocalVector(dmHess, &xHess);
671:       DMPlexComputeGradientClementInterpolant(dmGrad, xGrad, xHess);
672:       VecViewFromOptions(xHess, NULL, "-adapt_hessian_view");
673:       VecDestroy(&xGrad);
674:       DMDestroy(&dmGrad);
675:       /*     Compute L-p normalized metric */
676:       DMClone(dm, &dmMetric);
677:       N    = adaptor->Nadapt >= 0 ? adaptor->Nadapt : PetscPowRealInt(adaptor->refinementFactor, dim)*((PetscReal) (vEnd - vStart));
678:       if (adaptor->monitor) {
679:         PetscMPIInt rank, size;
680:         MPI_Comm_rank(comm, &size);
681:         MPI_Comm_rank(comm, &rank);
682:         PetscPrintf(PETSC_COMM_SELF, "[%D] N_orig: %D N_adapt: %g\n", rank, vEnd - vStart, N);
683:       }
684:       DMPlexMetricSetTargetComplexity(dmMetric, (PetscReal) N);
685:       if (higherOrder) {
686:         /*   Project Hessian into P1 space, if required */
687:         DMPlexMetricCreate(dmMetric, 0, &metric);
688:         DMProjectFieldLocal(dmMetric, 0.0, xHess, funcs, INSERT_ALL_VALUES, metric);
689:         VecDestroy(&xHess);
690:         xHess = metric;
691:       }
692:       PetscFree(funcs);
693:       DMPlexMetricNormalize(dmMetric, xHess, PETSC_TRUE, PETSC_TRUE, &metric);
694:       VecDestroy(&xHess);
695:       DMDestroy(&dmHess);
696:       /*     Adapt DM from metric */
697:       DMGetLabel(dm, "marker", &bdLabel);
698:       DMAdaptMetric(dm, metric, bdLabel, rgLabel, &odm);
699:       adapted = PETSC_TRUE;
700:       /*     Cleanup */
701:       VecDestroy(&metric);
702:       DMDestroy(&dmMetric);
703:     }
704:     break;
705:     default: SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid adaptation type: %D", adaptor->adaptCriterion);
706:     }
707:     DMAdaptorPostAdapt(adaptor);
708:     DMRestoreLocalVector(dm, &locX);
709:     /* If DM was adapted, replace objects and recreate solution */
710:     if (adapted) {
711:       const char *name;

713:       PetscObjectGetName((PetscObject) dm, &name);
714:       PetscObjectSetName((PetscObject) odm, name);
715:       /* Reconfigure solver */
716:       SNESReset(adaptor->snes);
717:       SNESSetDM(adaptor->snes, odm);
718:       DMAdaptorSetSolver(adaptor, adaptor->snes);
719:       DMPlexSetSNESLocalFEM(odm, ctx, ctx, ctx);
720:       SNESSetFromOptions(adaptor->snes);
721:       /* Transfer system */
722:       DMCopyDisc(dm, odm);
723:       /* Transfer solution */
724:       DMCreateGlobalVector(odm, &ox);
725:       PetscObjectGetName((PetscObject) x, &name);
726:       PetscObjectSetName((PetscObject) ox, name);
727:       DMAdaptorTransferSolution(adaptor, dm, x, odm, ox);
728:       /* Cleanup adaptivity info */
729:       if (adaptIter > 0) PetscViewerASCIIPopTab(PETSC_VIEWER_STDOUT_(comm));
730:       DMForestSetAdaptivityForest(dm, NULL); /* clear internal references to the previous dm */
731:       DMDestroy(&dm);
732:       VecDestroy(&x);
733:       *adm = odm;
734:       *ax  = ox;
735:     } else {
736:       *adm = dm;
737:       *ax  = x;
738:       adaptIter = numAdapt;
739:     }
740:     if (adaptIter < numAdapt-1) {
741:       DMViewFromOptions(odm, NULL, "-dm_adapt_iter_view");
742:       VecViewFromOptions(ox, NULL, "-sol_adapt_iter_view");
743:     }
744:   }
745:   DMViewFromOptions(*adm, NULL, "-dm_adapt_view");
746:   VecViewFromOptions(*ax, NULL, "-sol_adapt_view");
747:   return 0;
748: }

750: /*@
751:   DMAdaptorAdapt - Creates a new DM that is adapted to the problem

753:   Not collective

755:   Input Parameters:
756: + adaptor  - The DMAdaptor object
757: . x        - The global approximate solution
758: - strategy - The adaptation strategy

760:   Output Parameters:
761: + adm - The adapted DM
762: - ax  - The adapted solution

764:   Options database keys:
765: + -snes_adapt <strategy> - initial, sequential, multigrid
766: . -adapt_gradient_view - View the Clement interpolant of the solution gradient
767: . -adapt_hessian_view - View the Clement interpolant of the solution Hessian
768: - -adapt_metric_view - View the metric tensor for adaptive mesh refinement

770:   Note: The available adaptation strategies are:
771: $ 1) Adapt the initial mesh until a quality metric, e.g., a priori error bound, is satisfied
772: $ 2) Solve the problem on a series of adapted meshes until a quality metric, e.g. a posteriori error bound, is satisfied
773: $ 3) Solve the problem on a hierarchy of adapted meshes generated to satisfy a quality metric using multigrid

775:   Level: intermediate

777: .seealso: DMAdaptorSetSolver(), DMAdaptorCreate(), DMAdaptorAdapt()
778: @*/
779: PetscErrorCode DMAdaptorAdapt(DMAdaptor adaptor, Vec x, DMAdaptationStrategy strategy, DM *adm, Vec *ax)
780: {
781:   switch (strategy)
782:   {
783:   case DM_ADAPTATION_INITIAL:
784:     DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_FALSE, adm, ax);
785:     break;
786:   case DM_ADAPTATION_SEQUENTIAL:
787:     DMAdaptorAdapt_Sequence_Private(adaptor, x, PETSC_TRUE, adm, ax);
788:     break;
789:   default: SETERRQ(PetscObjectComm((PetscObject) adaptor), PETSC_ERR_ARG_WRONG, "Unrecognized adaptation strategy %d", strategy);
790:   }
791:   return 0;
792: }