Actual source code: dm.c

petsc-master 2020-09-19
Report Typos and Errors
  1: #include <petsc/private/dmimpl.h>
  2: #include <petsc/private/dmlabelimpl.h>
  3: #include <petsc/private/petscdsimpl.h>
  4: #include <petscdmplex.h>
  5: #include <petscdmfield.h>
  6: #include <petscsf.h>
  7: #include <petscds.h>

  9: #if defined(PETSC_HAVE_VALGRIND)
 10: #  include <valgrind/memcheck.h>
 11: #endif

 13: PetscClassId  DM_CLASSID;
 14: PetscClassId  DMLABEL_CLASSID;
 15: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load, DM_AdaptInterpolator;

 17: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
 18: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
 19: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
 20: /*@
 21:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

 23:    If you never  call DMSetType()  it will generate an
 24:    error when you try to use the vector.

 26:   Collective

 28:   Input Parameter:
 29: . comm - The communicator for the DM object

 31:   Output Parameter:
 32: . dm - The DM object

 34:   Level: beginner

 36: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
 37: @*/
 38: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
 39: {
 40:   DM             v;
 41:   PetscDS        ds;

 46:   *dm = NULL;
 47:   DMInitializePackage();

 49:   PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);

 51:   v->setupcalled              = PETSC_FALSE;
 52:   v->setfromoptionscalled     = PETSC_FALSE;
 53:   v->ltogmap                  = NULL;
 54:   v->bs                       = 1;
 55:   v->coloringtype             = IS_COLORING_GLOBAL;
 56:   PetscSFCreate(comm, &v->sf);
 57:   PetscSFCreate(comm, &v->sectionSF);
 58:   v->labels                   = NULL;
 59:   v->adjacency[0]             = PETSC_FALSE;
 60:   v->adjacency[1]             = PETSC_TRUE;
 61:   v->depthLabel               = NULL;
 62:   v->celltypeLabel            = NULL;
 63:   v->localSection             = NULL;
 64:   v->globalSection            = NULL;
 65:   v->defaultConstraintSection = NULL;
 66:   v->defaultConstraintMat     = NULL;
 67:   v->L                        = NULL;
 68:   v->maxCell                  = NULL;
 69:   v->bdtype                   = NULL;
 70:   v->dimEmbed                 = PETSC_DEFAULT;
 71:   v->dim                      = PETSC_DETERMINE;
 72:   {
 73:     PetscInt i;
 74:     for (i = 0; i < 10; ++i) {
 75:       v->nullspaceConstructors[i] = NULL;
 76:       v->nearnullspaceConstructors[i] = NULL;
 77:     }
 78:   }
 79:   PetscDSCreate(PetscObjectComm((PetscObject) v), &ds);
 80:   DMSetRegionDS(v, NULL, NULL, ds);
 81:   PetscDSDestroy(&ds);
 82:   v->dmBC = NULL;
 83:   v->coarseMesh = NULL;
 84:   v->outputSequenceNum = -1;
 85:   v->outputSequenceVal = 0.0;
 86:   DMSetVecType(v,VECSTANDARD);
 87:   DMSetMatType(v,MATAIJ);

 89:   *dm = v;
 90:   return(0);
 91: }

 93: /*@
 94:   DMClone - Creates a DM object with the same topology as the original.

 96:   Collective

 98:   Input Parameter:
 99: . dm - The original DM object

101:   Output Parameter:
102: . newdm  - The new DM object

104:   Level: beginner

106:   Notes:
107:   For some DM implementations this is a shallow clone, the result of which may share (referent counted) information with its parent. For example,
108:   DMClone() applied to a DMPLEX object will result in a new DMPLEX that shares the topology with the original DMPLEX. It does not
109:   share the PetscSection of the original DM.

111:   The clone is considered set up iff the original is.

113: .seealso: DMDestroy(), DMCreate(), DMSetType(), DMSetLocalSection(), DMSetGlobalSection()

115: @*/
116: PetscErrorCode DMClone(DM dm, DM *newdm)
117: {
118:   PetscSF        sf;
119:   Vec            coords;
120:   void          *ctx;
121:   PetscInt       dim, cdim;

127:   DMCreate(PetscObjectComm((PetscObject) dm), newdm);
128:   DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
129:   (*newdm)->leveldown  = dm->leveldown;
130:   (*newdm)->levelup    = dm->levelup;
131:   DMGetDimension(dm, &dim);
132:   DMSetDimension(*newdm, dim);
133:   if (dm->ops->clone) {
134:     (*dm->ops->clone)(dm, newdm);
135:   }
136:   (*newdm)->setupcalled = dm->setupcalled;
137:   DMGetPointSF(dm, &sf);
138:   DMSetPointSF(*newdm, sf);
139:   DMGetApplicationContext(dm, &ctx);
140:   DMSetApplicationContext(*newdm, ctx);
141:   if (dm->coordinateDM) {
142:     DM           ncdm;
143:     PetscSection cs;
144:     PetscInt     pEnd = -1, pEndMax = -1;

146:     DMGetLocalSection(dm->coordinateDM, &cs);
147:     if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
148:     MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
149:     if (pEndMax >= 0) {
150:       DMClone(dm->coordinateDM, &ncdm);
151:       DMCopyDisc(dm->coordinateDM, ncdm);
152:       DMSetLocalSection(ncdm, cs);
153:       DMSetCoordinateDM(*newdm, ncdm);
154:       DMDestroy(&ncdm);
155:     }
156:   }
157:   DMGetCoordinateDim(dm, &cdim);
158:   DMSetCoordinateDim(*newdm, cdim);
159:   DMGetCoordinatesLocal(dm, &coords);
160:   if (coords) {
161:     DMSetCoordinatesLocal(*newdm, coords);
162:   } else {
163:     DMGetCoordinates(dm, &coords);
164:     if (coords) {DMSetCoordinates(*newdm, coords);}
165:   }
166:   {
167:     PetscBool             isper;
168:     const PetscReal      *maxCell, *L;
169:     const DMBoundaryType *bd;
170:     DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
171:     DMSetPeriodicity(*newdm, isper, maxCell,  L,  bd);
172:   }
173:   {
174:     PetscBool useCone, useClosure;

176:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
177:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
178:   }
179:   return(0);
180: }

182: /*@C
183:        DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()

185:    Logically Collective on da

187:    Input Parameter:
188: +  da - initial distributed array
189: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

191:    Options Database:
192: .   -dm_vec_type ctype

194:    Level: intermediate

196: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
197: @*/
198: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
199: {

204:   PetscFree(da->vectype);
205:   PetscStrallocpy(ctype,(char**)&da->vectype);
206:   return(0);
207: }

209: /*@C
210:        DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()

212:    Logically Collective on da

214:    Input Parameter:
215: .  da - initial distributed array

217:    Output Parameter:
218: .  ctype - the vector type

220:    Level: intermediate

222: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
223: @*/
224: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
225: {
228:   *ctype = da->vectype;
229:   return(0);
230: }

232: /*@
233:   VecGetDM - Gets the DM defining the data layout of the vector

235:   Not collective

237:   Input Parameter:
238: . v - The Vec

240:   Output Parameter:
241: . dm - The DM

243:   Level: intermediate

245: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
246: @*/
247: PetscErrorCode VecGetDM(Vec v, DM *dm)
248: {

254:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
255:   return(0);
256: }

258: /*@
259:   VecSetDM - Sets the DM defining the data layout of the vector.

261:   Not collective

263:   Input Parameters:
264: + v - The Vec
265: - dm - The DM

267:   Note: This is NOT the same as DMCreateGlobalVector() since it does not change the view methods or perform other customization, but merely sets the DM member.

269:   Level: intermediate

271: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
272: @*/
273: PetscErrorCode VecSetDM(Vec v, DM dm)
274: {

280:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
281:   return(0);
282: }

284: /*@C
285:        DMSetISColoringType - Sets the type of coloring, global or local, that is created by the DM

287:    Logically Collective on dm

289:    Input Parameters:
290: +  dm - the DM context
291: -  ctype - the matrix type

293:    Options Database:
294: .   -dm_is_coloring_type - global or local

296:    Level: intermediate

298: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
299:           DMGetISColoringType()
300: @*/
301: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
302: {
305:   dm->coloringtype = ctype;
306:   return(0);
307: }

309: /*@C
310:        DMGetISColoringType - Gets the type of coloring, global or local, that is created by the DM

312:    Logically Collective on dm

314:    Input Parameter:
315: .  dm - the DM context

317:    Output Parameter:
318: .  ctype - the matrix type

320:    Options Database:
321: .   -dm_is_coloring_type - global or local

323:    Level: intermediate

325: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
326:           DMGetISColoringType()
327: @*/
328: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
329: {
332:   *ctype = dm->coloringtype;
333:   return(0);
334: }

336: /*@C
337:        DMSetMatType - Sets the type of matrix created with DMCreateMatrix()

339:    Logically Collective on dm

341:    Input Parameters:
342: +  dm - the DM context
343: -  ctype - the matrix type

345:    Options Database:
346: .   -dm_mat_type ctype

348:    Level: intermediate

350: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
351: @*/
352: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
353: {

358:   PetscFree(dm->mattype);
359:   PetscStrallocpy(ctype,(char**)&dm->mattype);
360:   return(0);
361: }

363: /*@C
364:        DMGetMatType - Gets the type of matrix created with DMCreateMatrix()

366:    Logically Collective on dm

368:    Input Parameter:
369: .  dm - the DM context

371:    Output Parameter:
372: .  ctype - the matrix type

374:    Options Database:
375: .   -dm_mat_type ctype

377:    Level: intermediate

379: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
380: @*/
381: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
382: {
385:   *ctype = dm->mattype;
386:   return(0);
387: }

389: /*@
390:   MatGetDM - Gets the DM defining the data layout of the matrix

392:   Not collective

394:   Input Parameter:
395: . A - The Mat

397:   Output Parameter:
398: . dm - The DM

400:   Level: intermediate

402:   Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
403:                   the Mat through a PetscObjectCompose() operation

405: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
406: @*/
407: PetscErrorCode MatGetDM(Mat A, DM *dm)
408: {

414:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
415:   return(0);
416: }

418: /*@
419:   MatSetDM - Sets the DM defining the data layout of the matrix

421:   Not collective

423:   Input Parameters:
424: + A - The Mat
425: - dm - The DM

427:   Level: intermediate

429:   Developer Note: Since the Mat class doesn't know about the DM class the DM object is associated with
430:                   the Mat through a PetscObjectCompose() operation


433: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
434: @*/
435: PetscErrorCode MatSetDM(Mat A, DM dm)
436: {

442:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
443:   return(0);
444: }

446: /*@C
447:    DMSetOptionsPrefix - Sets the prefix used for searching for all
448:    DM options in the database.

450:    Logically Collective on dm

452:    Input Parameter:
453: +  da - the DM context
454: -  prefix - the prefix to prepend to all option names

456:    Notes:
457:    A hyphen (-) must NOT be given at the beginning of the prefix name.
458:    The first character of all runtime options is AUTOMATICALLY the hyphen.

460:    Level: advanced

462: .seealso: DMSetFromOptions()
463: @*/
464: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
465: {

470:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
471:   if (dm->sf) {
472:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
473:   }
474:   if (dm->sectionSF) {
475:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
476:   }
477:   return(0);
478: }

480: /*@C
481:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
482:    DM options in the database.

484:    Logically Collective on dm

486:    Input Parameters:
487: +  dm - the DM context
488: -  prefix - the prefix string to prepend to all DM option requests

490:    Notes:
491:    A hyphen (-) must NOT be given at the beginning of the prefix name.
492:    The first character of all runtime options is AUTOMATICALLY the hyphen.

494:    Level: advanced

496: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
497: @*/
498: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
499: {

504:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
505:   return(0);
506: }

508: /*@C
509:    DMGetOptionsPrefix - Gets the prefix used for searching for all
510:    DM options in the database.

512:    Not Collective

514:    Input Parameters:
515: .  dm - the DM context

517:    Output Parameters:
518: .  prefix - pointer to the prefix string used is returned

520:    Notes:
521:     On the fortran side, the user should pass in a string 'prefix' of
522:    sufficient length to hold the prefix.

524:    Level: advanced

526: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
527: @*/
528: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
529: {

534:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
535:   return(0);
536: }

538: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
539: {
540:   PetscInt       refct = ((PetscObject) dm)->refct;

544:   *ncrefct = 0;
545:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
546:     refct--;
547:     if (recurseCoarse) {
548:       PetscInt coarseCount;

550:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
551:       refct += coarseCount;
552:     }
553:   }
554:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
555:     refct--;
556:     if (recurseFine) {
557:       PetscInt fineCount;

559:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
560:       refct += fineCount;
561:     }
562:   }
563:   *ncrefct = refct;
564:   return(0);
565: }

567: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
568: {
569:   DMLabelLink    next = dm->labels;

573:   /* destroy the labels */
574:   while (next) {
575:     DMLabelLink tmp = next->next;

577:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
578:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
579:     DMLabelDestroy(&next->label);
580:     PetscFree(next);
581:     next = tmp;
582:   }
583:   dm->labels = NULL;
584:   return(0);
585: }

587: /*@
588:     DMDestroy - Destroys a vector packer or DM.

590:     Collective on dm

592:     Input Parameter:
593: .   dm - the DM object to destroy

595:     Level: developer

597: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

599: @*/
600: PetscErrorCode  DMDestroy(DM *dm)
601: {
602:   PetscInt       cnt;
603:   DMNamedVecLink nlink,nnext;

607:   if (!*dm) return(0);

610:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
611:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
612:   --((PetscObject)(*dm))->refct;
613:   if (--cnt > 0) {*dm = NULL; return(0);}
614:   if (((PetscObject)(*dm))->refct < 0) return(0);
615:   ((PetscObject)(*dm))->refct = 0;

617:   DMClearGlobalVectors(*dm);
618:   DMClearLocalVectors(*dm);

620:   nnext=(*dm)->namedglobal;
621:   (*dm)->namedglobal = NULL;
622:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
623:     nnext = nlink->next;
624:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
625:     PetscFree(nlink->name);
626:     VecDestroy(&nlink->X);
627:     PetscFree(nlink);
628:   }
629:   nnext=(*dm)->namedlocal;
630:   (*dm)->namedlocal = NULL;
631:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
632:     nnext = nlink->next;
633:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
634:     PetscFree(nlink->name);
635:     VecDestroy(&nlink->X);
636:     PetscFree(nlink);
637:   }

639:   /* Destroy the list of hooks */
640:   {
641:     DMCoarsenHookLink link,next;
642:     for (link=(*dm)->coarsenhook; link; link=next) {
643:       next = link->next;
644:       PetscFree(link);
645:     }
646:     (*dm)->coarsenhook = NULL;
647:   }
648:   {
649:     DMRefineHookLink link,next;
650:     for (link=(*dm)->refinehook; link; link=next) {
651:       next = link->next;
652:       PetscFree(link);
653:     }
654:     (*dm)->refinehook = NULL;
655:   }
656:   {
657:     DMSubDomainHookLink link,next;
658:     for (link=(*dm)->subdomainhook; link; link=next) {
659:       next = link->next;
660:       PetscFree(link);
661:     }
662:     (*dm)->subdomainhook = NULL;
663:   }
664:   {
665:     DMGlobalToLocalHookLink link,next;
666:     for (link=(*dm)->gtolhook; link; link=next) {
667:       next = link->next;
668:       PetscFree(link);
669:     }
670:     (*dm)->gtolhook = NULL;
671:   }
672:   {
673:     DMLocalToGlobalHookLink link,next;
674:     for (link=(*dm)->ltoghook; link; link=next) {
675:       next = link->next;
676:       PetscFree(link);
677:     }
678:     (*dm)->ltoghook = NULL;
679:   }
680:   /* Destroy the work arrays */
681:   {
682:     DMWorkLink link,next;
683:     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
684:     for (link=(*dm)->workin; link; link=next) {
685:       next = link->next;
686:       PetscFree(link->mem);
687:       PetscFree(link);
688:     }
689:     (*dm)->workin = NULL;
690:   }
691:   /* destroy the labels */
692:   DMDestroyLabelLinkList_Internal(*dm);
693:   /* destroy the fields */
694:   DMClearFields(*dm);
695:   /* destroy the boundaries */
696:   {
697:     DMBoundary next = (*dm)->boundary;
698:     while (next) {
699:       DMBoundary b = next;

701:       next = b->next;
702:       PetscFree(b);
703:     }
704:   }

706:   PetscObjectDestroy(&(*dm)->dmksp);
707:   PetscObjectDestroy(&(*dm)->dmsnes);
708:   PetscObjectDestroy(&(*dm)->dmts);

710:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
711:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
712:   }
713:   MatFDColoringDestroy(&(*dm)->fd);
714:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
715:   PetscFree((*dm)->vectype);
716:   PetscFree((*dm)->mattype);

718:   PetscSectionDestroy(&(*dm)->localSection);
719:   PetscSectionDestroy(&(*dm)->globalSection);
720:   PetscLayoutDestroy(&(*dm)->map);
721:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
722:   MatDestroy(&(*dm)->defaultConstraintMat);
723:   PetscSFDestroy(&(*dm)->sf);
724:   PetscSFDestroy(&(*dm)->sectionSF);
725:   if ((*dm)->useNatural) {
726:     if ((*dm)->sfNatural) {
727:       PetscSFDestroy(&(*dm)->sfNatural);
728:     }
729:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
730:   }
731:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
732:     DMSetFineDM((*dm)->coarseMesh,NULL);
733:   }

735:   DMDestroy(&(*dm)->coarseMesh);
736:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
737:     DMSetCoarseDM((*dm)->fineMesh,NULL);
738:   }
739:   DMDestroy(&(*dm)->fineMesh);
740:   DMFieldDestroy(&(*dm)->coordinateField);
741:   DMDestroy(&(*dm)->coordinateDM);
742:   VecDestroy(&(*dm)->coordinates);
743:   VecDestroy(&(*dm)->coordinatesLocal);
744:   PetscFree((*dm)->L);
745:   PetscFree((*dm)->maxCell);
746:   PetscFree((*dm)->bdtype);
747:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
748:   DMDestroy(&(*dm)->transformDM);
749:   VecDestroy(&(*dm)->transform);

751:   DMClearDS(*dm);
752:   DMDestroy(&(*dm)->dmBC);
753:   /* if memory was published with SAWs then destroy it */
754:   PetscObjectSAWsViewOff((PetscObject)*dm);

756:   if ((*dm)->ops->destroy) {
757:     (*(*dm)->ops->destroy)(*dm);
758:   }
759:   DMMonitorCancel(*dm);
760:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
761:   PetscHeaderDestroy(dm);
762:   return(0);
763: }

765: /*@
766:     DMSetUp - sets up the data structures inside a DM object

768:     Collective on dm

770:     Input Parameter:
771: .   dm - the DM object to setup

773:     Level: developer

775: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

777: @*/
778: PetscErrorCode  DMSetUp(DM dm)
779: {

784:   if (dm->setupcalled) return(0);
785:   if (dm->ops->setup) {
786:     (*dm->ops->setup)(dm);
787:   }
788:   dm->setupcalled = PETSC_TRUE;
789:   return(0);
790: }

792: /*@
793:     DMSetFromOptions - sets parameters in a DM from the options database

795:     Collective on dm

797:     Input Parameter:
798: .   dm - the DM object to set options for

800:     Options Database:
801: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
802: .   -dm_vec_type <type>  - type of vector to create inside DM
803: .   -dm_mat_type <type>  - type of matrix to create inside DM
804: -   -dm_is_coloring_type - <global or local>

806:     DMPLEX Specific Checks
807: +   -dm_plex_check_symmetry        - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
808: .   -dm_plex_check_skeleton        - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
809: .   -dm_plex_check_faces           - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - DMPlexCheckFaces()
810: .   -dm_plex_check_geometry        - Check that cells have positive volume - DMPlexCheckGeometry()
811: .   -dm_plex_check_pointsf         - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
812: .   -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
813: -   -dm_plex_check_all             - Perform all the checks above

815:     Level: intermediate

817: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(),
818:     DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces(), DMPlexCheckGeometry(), DMPlexCheckPointSF(), DMPlexCheckInterfaceCones()

820: @*/
821: PetscErrorCode DMSetFromOptions(DM dm)
822: {
823:   char           typeName[256];
824:   PetscBool      flg;

829:   dm->setfromoptionscalled = PETSC_TRUE;
830:   if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
831:   if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
832:   PetscObjectOptionsBegin((PetscObject)dm);
833:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
834:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
835:   if (flg) {
836:     DMSetVecType(dm,typeName);
837:   }
838:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
839:   if (flg) {
840:     DMSetMatType(dm,typeName);
841:   }
842:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
843:   if (dm->ops->setfromoptions) {
844:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
845:   }
846:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
847:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
848:   PetscOptionsEnd();
849:   return(0);
850: }

852: /*@C
853:    DMViewFromOptions - View from Options

855:    Collective on DM

857:    Input Parameters:
858: +  dm - the DM object
859: .  obj - Optional object
860: -  name - command line option

862:    Level: intermediate
863: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
864: @*/
865: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
866: {

871:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
872:   return(0);
873: }

875: /*@C
876:     DMView - Views a DM

878:     Collective on dm

880:     Input Parameter:
881: +   dm - the DM object to view
882: -   v - the viewer

884:     Level: beginner

886: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

888: @*/
889: PetscErrorCode  DMView(DM dm,PetscViewer v)
890: {
891:   PetscErrorCode    ierr;
892:   PetscBool         isbinary;
893:   PetscMPIInt       size;
894:   PetscViewerFormat format;

898:   if (!v) {
899:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
900:   }
902:   /* Ideally, we would like to have this test on.
903:      However, it currently breaks socket viz via GLVis.
904:      During DMView(parallel_mesh,glvis_viewer), each
905:      process opens a sequential ASCII socket to visualize
906:      the local mesh, and PetscObjectView(dm,local_socket)
907:      is internally called inside VecView_GLVis, incurring
908:      in an error here */
910:   PetscViewerCheckWritable(v);

912:   PetscViewerGetFormat(v,&format);
913:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
914:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
915:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
916:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
917:   if (isbinary) {
918:     PetscInt classid = DM_FILE_CLASSID;
919:     char     type[256];

921:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
922:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
923:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
924:   }
925:   if (dm->ops->view) {
926:     (*dm->ops->view)(dm,v);
927:   }
928:   return(0);
929: }

931: /*@
932:     DMCreateGlobalVector - Creates a global vector from a DM object

934:     Collective on dm

936:     Input Parameter:
937: .   dm - the DM object

939:     Output Parameter:
940: .   vec - the global vector

942:     Level: beginner

944: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

946: @*/
947: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
948: {

954:   if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
955:   (*dm->ops->createglobalvector)(dm,vec);
956:   if (PetscDefined(USE_DEBUG)) {
957:     DM vdm;

959:     VecGetDM(*vec,&vdm);
960:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
961:   }
962:   return(0);
963: }

965: /*@
966:     DMCreateLocalVector - Creates a local vector from a DM object

968:     Not Collective

970:     Input Parameter:
971: .   dm - the DM object

973:     Output Parameter:
974: .   vec - the local vector

976:     Level: beginner

978: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

980: @*/
981: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
982: {

988:   if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
989:   (*dm->ops->createlocalvector)(dm,vec);
990:   if (PetscDefined(USE_DEBUG)) {
991:     DM vdm;

993:     VecGetDM(*vec,&vdm);
994:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
995:   }
996:   return(0);
997: }

999: /*@
1000:    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.

1002:    Collective on dm

1004:    Input Parameter:
1005: .  dm - the DM that provides the mapping

1007:    Output Parameter:
1008: .  ltog - the mapping

1010:    Level: intermediate

1012:    Notes:
1013:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1014:    MatSetLocalToGlobalMapping().

1016: .seealso: DMCreateLocalVector()
1017: @*/
1018: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1019: {
1020:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1026:   if (!dm->ltogmap) {
1027:     PetscSection section, sectionGlobal;

1029:     DMGetLocalSection(dm, &section);
1030:     if (section) {
1031:       const PetscInt *cdofs;
1032:       PetscInt       *ltog;
1033:       PetscInt        pStart, pEnd, n, p, k, l;

1035:       DMGetGlobalSection(dm, &sectionGlobal);
1036:       PetscSectionGetChart(section, &pStart, &pEnd);
1037:       PetscSectionGetStorageSize(section, &n);
1038:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1039:       for (p = pStart, l = 0; p < pEnd; ++p) {
1040:         PetscInt bdof, cdof, dof, off, c, cind = 0;

1042:         /* Should probably use constrained dofs */
1043:         PetscSectionGetDof(section, p, &dof);
1044:         PetscSectionGetConstraintDof(section, p, &cdof);
1045:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1046:         PetscSectionGetOffset(sectionGlobal, p, &off);
1047:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1048:         bdof = cdof && (dof-cdof) ? 1 : dof;
1049:         if (dof) {
1050:           if (bs < 0)          {bs = bdof;}
1051:           else if (bs != bdof) {bs = 1;}
1052:         }
1053:         for (c = 0; c < dof; ++c, ++l) {
1054:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1055:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
1056:         }
1057:       }
1058:       /* Must have same blocksize on all procs (some might have no points) */
1059:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1060:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1061:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1062:       else                            {bs = bsMinMax[0];}
1063:       bs = bs < 0 ? 1 : bs;
1064:       /* Must reduce indices by blocksize */
1065:       if (bs > 1) {
1066:         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1067:         n /= bs;
1068:       }
1069:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1070:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1071:     } else {
1072:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1073:       (*dm->ops->getlocaltoglobalmapping)(dm);
1074:     }
1075:   }
1076:   *ltog = dm->ltogmap;
1077:   return(0);
1078: }

1080: /*@
1081:    DMGetBlockSize - Gets the inherent block size associated with a DM

1083:    Not Collective

1085:    Input Parameter:
1086: .  dm - the DM with block structure

1088:    Output Parameter:
1089: .  bs - the block size, 1 implies no exploitable block structure

1091:    Level: intermediate

1093: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1094: @*/
1095: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1096: {
1100:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1101:   *bs = dm->bs;
1102:   return(0);
1103: }

1105: /*@
1106:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1108:     Collective on dmc

1110:     Input Parameter:
1111: +   dmc - the DM object
1112: -   dmf - the second, finer DM object

1114:     Output Parameter:
1115: +  mat - the interpolation
1116: -  vec - the scaling (optional)

1118:     Level: developer

1120:     Notes:
1121:     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1122:         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.

1124:         For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
1125:         EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.


1128: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolationScale()

1130: @*/
1131: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1132: {

1139:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1140:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1141:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1142:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1143:   return(0);
1144: }

1146: /*@
1147:     DMCreateInterpolationScale - Forms L = 1/(R*1) such that diag(L)*R preserves scale and is thus suitable for state (versus residual) restriction.

1149:   Input Parameters:
1150: +      dac - DM that defines a coarse mesh
1151: .      daf - DM that defines a fine mesh
1152: -      mat - the restriction (or interpolation operator) from fine to coarse

1154:   Output Parameter:
1155: .    scale - the scaled vector

1157:   Level: developer

1159: .seealso: DMCreateInterpolation()

1161: @*/
1162: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1163: {
1165:   Vec            fine;
1166:   PetscScalar    one = 1.0;

1169:   DMCreateGlobalVector(daf,&fine);
1170:   DMCreateGlobalVector(dac,scale);
1171:   VecSet(fine,one);
1172:   MatRestrict(mat,fine,*scale);
1173:   VecDestroy(&fine);
1174:   VecReciprocal(*scale);
1175:   return(0);
1176: }

1178: /*@
1179:     DMCreateRestriction - Gets restriction matrix between two DM objects

1181:     Collective on dmc

1183:     Input Parameter:
1184: +   dmc - the DM object
1185: -   dmf - the second, finer DM object

1187:     Output Parameter:
1188: .  mat - the restriction


1191:     Level: developer

1193:     Notes:
1194:     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1195:         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.


1198: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateInterpolation()

1200: @*/
1201: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1202: {

1209:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1210:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1211:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1212:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1213:   return(0);
1214: }

1216: /*@
1217:     DMCreateInjection - Gets injection matrix between two DM objects

1219:     Collective on dac

1221:     Input Parameter:
1222: +   dac - the DM object
1223: -   daf - the second, finer DM object

1225:     Output Parameter:
1226: .   mat - the injection

1228:     Level: developer

1230:    Notes:
1231:     For DMDA objects this only works for "uniform refinement", that is the refined mesh was obtained DMRefine() or the coarse mesh was obtained by
1232:         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.

1234: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()

1236: @*/
1237: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1238: {

1245:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1246:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1247:   (*dac->ops->createinjection)(dac,daf,mat);
1248:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1249:   return(0);
1250: }

1252: /*@
1253:   DMCreateMassMatrix - Gets mass matrix between two DM objects, M_ij = \int \phi_i \psi_j

1255:   Collective on dac

1257:   Input Parameter:
1258: + dac - the DM object
1259: - daf - the second, finer DM object

1261:   Output Parameter:
1262: . mat - the interpolation

1264:   Level: developer

1266: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1267: @*/
1268: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1269: {

1276:   if (!dac->ops->createmassmatrix) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMassMatrix",((PetscObject)dac)->type_name);
1277:   (*dac->ops->createmassmatrix)(dac, daf, mat);
1278:   return(0);
1279: }

1281: /*@
1282:     DMCreateColoring - Gets coloring for a DM

1284:     Collective on dm

1286:     Input Parameter:
1287: +   dm - the DM object
1288: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1290:     Output Parameter:
1291: .   coloring - the coloring

1293:     Notes:
1294:        Coloring of matrices can be computed directly from the sparse matrix nonzero structure via the MatColoring object or from the mesh from which the
1295:        matrix comes from. In general using the mesh produces a more optimal coloring (fewer colors).

1297:        This produces a coloring with the distance of 2, see MatSetColoringDistance() which can be used for efficiently computing Jacobians with MatFDColoringCreate()

1299:     Level: developer

1301: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType(), MatColoring, MatFDColoringCreate()

1303: @*/
1304: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1305: {

1311:   if (!dm->ops->getcoloring) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateColoring",((PetscObject)dm)->type_name);
1312:   (*dm->ops->getcoloring)(dm,ctype,coloring);
1313:   return(0);
1314: }

1316: /*@
1317:     DMCreateMatrix - Gets empty Jacobian for a DM

1319:     Collective on dm

1321:     Input Parameter:
1322: .   dm - the DM object

1324:     Output Parameter:
1325: .   mat - the empty Jacobian

1327:     Level: beginner

1329:     Notes:
1330:     This properly preallocates the number of nonzeros in the sparse matrix so you
1331:        do not need to do it yourself.

1333:        By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1334:        the nonzero pattern call DMSetMatrixPreallocateOnly()

1336:        For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1337:        internally by PETSc.

1339:        For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
1340:        the indices for the global numbering for DMDAs which is complicated.

1342: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()

1344: @*/
1345: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1346: {

1352:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1353:   MatInitializePackage();
1354:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1355:   (*dm->ops->creatematrix)(dm,mat);
1356:   if (PetscDefined(USE_DEBUG)) {
1357:     DM mdm;

1359:     MatGetDM(*mat,&mdm);
1360:     if (!mdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the matrix\n",((PetscObject)dm)->type_name);
1361:   }
1362:   /* Handle nullspace and near nullspace */
1363:   if (dm->Nf) {
1364:     MatNullSpace nullSpace;
1365:     PetscInt     Nf;

1367:     DMGetNumFields(dm, &Nf);
1368:     if (Nf == 1) {
1369:       if (dm->nullspaceConstructors[0]) {
1370:         (*dm->nullspaceConstructors[0])(dm, 0, 0, &nullSpace);
1371:         MatSetNullSpace(*mat, nullSpace);
1372:         MatNullSpaceDestroy(&nullSpace);
1373:       }
1374:       if (dm->nearnullspaceConstructors[0]) {
1375:         (*dm->nearnullspaceConstructors[0])(dm, 0, 0, &nullSpace);
1376:         MatSetNearNullSpace(*mat, nullSpace);
1377:         MatNullSpaceDestroy(&nullSpace);
1378:       }
1379:     }
1380:   }
1381:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1382:   return(0);
1383: }

1385: /*@
1386:   DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
1387:     preallocated but the nonzero structure and zero values will not be set.

1389:   Logically Collective on dm

1391:   Input Parameter:
1392: + dm - the DM
1393: - only - PETSC_TRUE if only want preallocation

1395:   Level: developer
1396: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1397: @*/
1398: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1399: {
1402:   dm->prealloc_only = only;
1403:   return(0);
1404: }

1406: /*@
1407:   DMSetMatrixStructureOnly - When DMCreateMatrix() is called, the matrix structure will be created
1408:     but the array for values will not be allocated.

1410:   Logically Collective on dm

1412:   Input Parameter:
1413: + dm - the DM
1414: - only - PETSC_TRUE if only want matrix stucture

1416:   Level: developer
1417: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1418: @*/
1419: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1420: {
1423:   dm->structure_only = only;
1424:   return(0);
1425: }

1427: /*@C
1428:   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()

1430:   Not Collective

1432:   Input Parameters:
1433: + dm - the DM object
1434: . count - The minium size
1435: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1437:   Output Parameter:
1438: . array - the work array

1440:   Level: developer

1442: .seealso DMDestroy(), DMCreate()
1443: @*/
1444: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1445: {
1447:   DMWorkLink     link;
1448:   PetscMPIInt    dsize;

1453:   if (dm->workin) {
1454:     link       = dm->workin;
1455:     dm->workin = dm->workin->next;
1456:   } else {
1457:     PetscNewLog(dm,&link);
1458:   }
1459:   MPI_Type_size(dtype,&dsize);
1460:   if (((size_t)dsize*count) > link->bytes) {
1461:     PetscFree(link->mem);
1462:     PetscMalloc(dsize*count,&link->mem);
1463:     link->bytes = dsize*count;
1464:   }
1465:   link->next   = dm->workout;
1466:   dm->workout  = link;
1467: #if defined(PETSC_HAVE_VALGRIND)
1468:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1469:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1470: #endif
1471:   *(void**)mem = link->mem;
1472:   return(0);
1473: }

1475: /*@C
1476:   DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()

1478:   Not Collective

1480:   Input Parameters:
1481: + dm - the DM object
1482: . count - The minium size
1483: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1485:   Output Parameter:
1486: . array - the work array

1488:   Level: developer

1490:   Developer Notes:
1491:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1492: .seealso DMDestroy(), DMCreate()
1493: @*/
1494: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1495: {
1496:   DMWorkLink *p,link;

1501:   for (p=&dm->workout; (link=*p); p=&link->next) {
1502:     if (link->mem == *(void**)mem) {
1503:       *p           = link->next;
1504:       link->next   = dm->workin;
1505:       dm->workin   = link;
1506:       *(void**)mem = NULL;
1507:       return(0);
1508:     }
1509:   }
1510:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1511: }

1513: /*@C
1514:   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field

1516:   Logically collective on DM

1518:   Input Parameters:
1519: + dm     - The DM
1520: . field  - The field number for the nullspace
1521: - nullsp - A callback to create the nullspace

1523:   Notes:
1524:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1525: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1526: $ dm        - The present DM
1527: $ origField - The field number given above, in the original DM
1528: $ field     - The field number in dm
1529: $ nullSpace - The nullspace for the given field

1531:   This function is currently not available from Fortran.

1533: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1534: */
1535: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1536: {
1539:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1540:   dm->nullspaceConstructors[field] = nullsp;
1541:   return(0);
1542: }

1544: /*@C
1545:   DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, or NULL

1547:   Not collective

1549:   Input Parameters:
1550: + dm     - The DM
1551: - field  - The field number for the nullspace

1553:   Output Parameter:
1554: . nullsp - A callback to create the nullspace

1556:   Notes:
1557:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1558: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1559: $ dm        - The present DM
1560: $ origField - The field number given above, in the original DM
1561: $ field     - The field number in dm
1562: $ nullSpace - The nullspace for the given field

1564:   This function is currently not available from Fortran.

1566: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1567: */
1568: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1569: {
1573:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1574:   *nullsp = dm->nullspaceConstructors[field];
1575:   return(0);
1576: }

1578: /*@C
1579:   DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field

1581:   Logically collective on DM

1583:   Input Parameters:
1584: + dm     - The DM
1585: . field  - The field number for the nullspace
1586: - nullsp - A callback to create the near-nullspace

1588:   Notes:
1589:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1590: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1591: $ dm        - The present DM
1592: $ origField - The field number given above, in the original DM
1593: $ field     - The field number in dm
1594: $ nullSpace - The nullspace for the given field

1596:   This function is currently not available from Fortran.

1598: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1599: */
1600: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1601: {
1604:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1605:   dm->nearnullspaceConstructors[field] = nullsp;
1606:   return(0);
1607: }

1609: /*@C
1610:   DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, or NULL

1612:   Not collective

1614:   Input Parameters:
1615: + dm     - The DM
1616: - field  - The field number for the nullspace

1618:   Output Parameter:
1619: . nullsp - A callback to create the near-nullspace

1621:   Notes:
1622:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1623: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1624: $ dm        - The present DM
1625: $ origField - The field number given above, in the original DM
1626: $ field     - The field number in dm
1627: $ nullSpace - The nullspace for the given field

1629:   This function is currently not available from Fortran.

1631: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1632: */
1633: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1634: {
1638:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1639:   *nullsp = dm->nearnullspaceConstructors[field];
1640:   return(0);
1641: }

1643: /*@C
1644:   DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field

1646:   Not collective

1648:   Input Parameter:
1649: . dm - the DM object

1651:   Output Parameters:
1652: + numFields  - The number of fields (or NULL if not requested)
1653: . fieldNames - The name for each field (or NULL if not requested)
1654: - fields     - The global indices for each field (or NULL if not requested)

1656:   Level: intermediate

1658:   Notes:
1659:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1660:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1661:   PetscFree().

1663: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1664: @*/
1665: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1666: {
1667:   PetscSection   section, sectionGlobal;

1672:   if (numFields) {
1674:     *numFields = 0;
1675:   }
1676:   if (fieldNames) {
1678:     *fieldNames = NULL;
1679:   }
1680:   if (fields) {
1682:     *fields = NULL;
1683:   }
1684:   DMGetLocalSection(dm, &section);
1685:   if (section) {
1686:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1687:     PetscInt nF, f, pStart, pEnd, p;

1689:     DMGetGlobalSection(dm, &sectionGlobal);
1690:     PetscSectionGetNumFields(section, &nF);
1691:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1692:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1693:     for (f = 0; f < nF; ++f) {
1694:       fieldSizes[f] = 0;
1695:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1696:     }
1697:     for (p = pStart; p < pEnd; ++p) {
1698:       PetscInt gdof;

1700:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1701:       if (gdof > 0) {
1702:         for (f = 0; f < nF; ++f) {
1703:           PetscInt fdof, fcdof, fpdof;

1705:           PetscSectionGetFieldDof(section, p, f, &fdof);
1706:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1707:           fpdof = fdof-fcdof;
1708:           if (fpdof && fpdof != fieldNc[f]) {
1709:             /* Layout does not admit a pointwise block size */
1710:             fieldNc[f] = 1;
1711:           }
1712:           fieldSizes[f] += fpdof;
1713:         }
1714:       }
1715:     }
1716:     for (f = 0; f < nF; ++f) {
1717:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1718:       fieldSizes[f] = 0;
1719:     }
1720:     for (p = pStart; p < pEnd; ++p) {
1721:       PetscInt gdof, goff;

1723:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1724:       if (gdof > 0) {
1725:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1726:         for (f = 0; f < nF; ++f) {
1727:           PetscInt fdof, fcdof, fc;

1729:           PetscSectionGetFieldDof(section, p, f, &fdof);
1730:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1731:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1732:             fieldIndices[f][fieldSizes[f]] = goff++;
1733:           }
1734:         }
1735:       }
1736:     }
1737:     if (numFields) *numFields = nF;
1738:     if (fieldNames) {
1739:       PetscMalloc1(nF, fieldNames);
1740:       for (f = 0; f < nF; ++f) {
1741:         const char *fieldName;

1743:         PetscSectionGetFieldName(section, f, &fieldName);
1744:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1745:       }
1746:     }
1747:     if (fields) {
1748:       PetscMalloc1(nF, fields);
1749:       for (f = 0; f < nF; ++f) {
1750:         PetscInt bs, in[2], out[2];

1752:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1753:         in[0] = -fieldNc[f];
1754:         in[1] = fieldNc[f];
1755:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1756:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1757:         ISSetBlockSize((*fields)[f], bs);
1758:       }
1759:     }
1760:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1761:   } else if (dm->ops->createfieldis) {
1762:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1763:   }
1764:   return(0);
1765: }


1768: /*@C
1769:   DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1770:                           corresponding to different fields: each IS contains the global indices of the dofs of the
1771:                           corresponding field. The optional list of DMs define the DM for each subproblem.
1772:                           Generalizes DMCreateFieldIS().

1774:   Not collective

1776:   Input Parameter:
1777: . dm - the DM object

1779:   Output Parameters:
1780: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1781: . namelist  - The name for each field (or NULL if not requested)
1782: . islist    - The global indices for each field (or NULL if not requested)
1783: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1785:   Level: intermediate

1787:   Notes:
1788:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1789:   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1790:   and all of the arrays should be freed with PetscFree().

1792: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1793: @*/
1794: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1795: {

1800:   if (len) {
1802:     *len = 0;
1803:   }
1804:   if (namelist) {
1806:     *namelist = NULL;
1807:   }
1808:   if (islist) {
1810:     *islist = NULL;
1811:   }
1812:   if (dmlist) {
1814:     *dmlist = NULL;
1815:   }
1816:   /*
1817:    Is it a good idea to apply the following check across all impls?
1818:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1819:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1820:    */
1821:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1822:   if (!dm->ops->createfielddecomposition) {
1823:     PetscSection section;
1824:     PetscInt     numFields, f;

1826:     DMGetLocalSection(dm, &section);
1827:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1828:     if (section && numFields && dm->ops->createsubdm) {
1829:       if (len) *len = numFields;
1830:       if (namelist) {PetscMalloc1(numFields,namelist);}
1831:       if (islist)   {PetscMalloc1(numFields,islist);}
1832:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1833:       for (f = 0; f < numFields; ++f) {
1834:         const char *fieldName;

1836:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1837:         if (namelist) {
1838:           PetscSectionGetFieldName(section, f, &fieldName);
1839:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1840:         }
1841:       }
1842:     } else {
1843:       DMCreateFieldIS(dm, len, namelist, islist);
1844:       /* By default there are no DMs associated with subproblems. */
1845:       if (dmlist) *dmlist = NULL;
1846:     }
1847:   } else {
1848:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1849:   }
1850:   return(0);
1851: }

1853: /*@
1854:   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1855:                   The fields are defined by DMCreateFieldIS().

1857:   Not collective

1859:   Input Parameters:
1860: + dm        - The DM object
1861: . numFields - The number of fields in this subproblem
1862: - fields    - The field numbers of the selected fields

1864:   Output Parameters:
1865: + is - The global indices for the subproblem
1866: - subdm - The DM for the subproblem

1868:   Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed

1870:   Level: intermediate

1872: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1873: @*/
1874: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1875: {

1883:   if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
1884:   (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1885:   return(0);
1886: }

1888: /*@C
1889:   DMCreateSuperDM - Returns an arrays of ISes and DM encapsulating a superproblem defined by the DMs passed in.

1891:   Not collective

1893:   Input Parameter:
1894: + dms - The DM objects
1895: - len - The number of DMs

1897:   Output Parameters:
1898: + is - The global indices for the subproblem, or NULL
1899: - superdm - The DM for the superproblem

1901:   Note: You need to call DMPlexSetMigrationSF() on the original DM if you want the Global-To-Natural map to be automatically constructed

1903:   Level: intermediate

1905: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1906: @*/
1907: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1908: {
1909:   PetscInt       i;

1917:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1918:   if (len) {
1919:     DM dm = dms[0];
1920:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1921:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1922:   }
1923:   return(0);
1924: }


1927: /*@C
1928:   DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1929:                           corresponding to restrictions to pairs nested subdomains: each IS contains the global
1930:                           indices of the dofs of the corresponding subdomains.  The inner subdomains conceptually
1931:                           define a nonoverlapping covering, while outer subdomains can overlap.
1932:                           The optional list of DMs define the DM for each subproblem.

1934:   Not collective

1936:   Input Parameter:
1937: . dm - the DM object

1939:   Output Parameters:
1940: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1941: . namelist    - The name for each subdomain (or NULL if not requested)
1942: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1943: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1944: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1946:   Level: intermediate

1948:   Notes:
1949:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1950:   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1951:   and all of the arrays should be freed with PetscFree().

1953: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1954: @*/
1955: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1956: {
1957:   PetscErrorCode      ierr;
1958:   DMSubDomainHookLink link;
1959:   PetscInt            i,l;

1968:   /*
1969:    Is it a good idea to apply the following check across all impls?
1970:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1971:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1972:    */
1973:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1974:   if (dm->ops->createdomaindecomposition) {
1975:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1976:     /* copy subdomain hooks and context over to the subdomain DMs */
1977:     if (dmlist && *dmlist) {
1978:       for (i = 0; i < l; i++) {
1979:         for (link=dm->subdomainhook; link; link=link->next) {
1980:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1981:         }
1982:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1983:       }
1984:     }
1985:     if (len) *len = l;
1986:   }
1987:   return(0);
1988: }


1991: /*@C
1992:   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector

1994:   Not collective

1996:   Input Parameters:
1997: + dm - the DM object
1998: . n  - the number of subdomain scatters
1999: - subdms - the local subdomains

2001:   Output Parameters:
2002: + n     - the number of scatters returned
2003: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2004: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2005: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

2007:   Notes:
2008:     This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
2009:   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
2010:   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2011:   solution and residual data.

2013:   Level: developer

2015: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2016: @*/
2017: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2018: {

2024:   if (!dm->ops->createddscatters) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateDomainDecompositionScatters",((PetscObject)dm)->type_name);
2025:   (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2026:   return(0);
2027: }

2029: /*@
2030:   DMRefine - Refines a DM object

2032:   Collective on dm

2034:   Input Parameter:
2035: + dm   - the DM object
2036: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2038:   Output Parameter:
2039: . dmf - the refined DM, or NULL

2041:   Options Dtabase Keys:
2042: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex

2044:   Note: If no refinement was done, the return value is NULL

2046:   Level: developer

2048: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2049: @*/
2050: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2051: {
2052:   PetscErrorCode   ierr;
2053:   DMRefineHookLink link;

2057:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2058:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
2059:   (*dm->ops->refine)(dm,comm,dmf);
2060:   if (*dmf) {
2061:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

2063:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);

2065:     (*dmf)->ctx       = dm->ctx;
2066:     (*dmf)->leveldown = dm->leveldown;
2067:     (*dmf)->levelup   = dm->levelup + 1;

2069:     DMSetMatType(*dmf,dm->mattype);
2070:     for (link=dm->refinehook; link; link=link->next) {
2071:       if (link->refinehook) {
2072:         (*link->refinehook)(dm,*dmf,link->ctx);
2073:       }
2074:     }
2075:   }
2076:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2077:   return(0);
2078: }

2080: /*@C
2081:    DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid

2083:    Logically Collective

2085:    Input Arguments:
2086: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2087: .  refinehook - function to run when setting up a coarser level
2088: .  interphook - function to run to update data on finer levels (once per SNESSolve())
2089: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2091:    Calling sequence of refinehook:
2092: $    refinehook(DM coarse,DM fine,void *ctx);

2094: +  coarse - coarse level DM
2095: .  fine - fine level DM to interpolate problem to
2096: -  ctx - optional user-defined function context

2098:    Calling sequence for interphook:
2099: $    interphook(DM coarse,Mat interp,DM fine,void *ctx)

2101: +  coarse - coarse level DM
2102: .  interp - matrix interpolating a coarse-level solution to the finer grid
2103: .  fine - fine level DM to update
2104: -  ctx - optional user-defined function context

2106:    Level: advanced

2108:    Notes:
2109:    This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing

2111:    If this function is called multiple times, the hooks will be run in the order they are added.

2113:    This function is currently not available from Fortran.

2115: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2116: @*/
2117: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2118: {
2119:   PetscErrorCode   ierr;
2120:   DMRefineHookLink link,*p;

2124:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2125:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2126:   }
2127:   PetscNew(&link);
2128:   link->refinehook = refinehook;
2129:   link->interphook = interphook;
2130:   link->ctx        = ctx;
2131:   link->next       = NULL;
2132:   *p               = link;
2133:   return(0);
2134: }

2136: /*@C
2137:    DMRefineHookRemove - remove a callback from the list of hooks to be run when interpolating a nonlinear problem to a finer grid

2139:    Logically Collective

2141:    Input Arguments:
2142: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2143: .  refinehook - function to run when setting up a coarser level
2144: .  interphook - function to run to update data on finer levels (once per SNESSolve())
2145: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2147:    Level: advanced

2149:    Notes:
2150:    This function does nothing if the hook is not in the list.

2152:    This function is currently not available from Fortran.

2154: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2155: @*/
2156: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2157: {
2158:   PetscErrorCode   ierr;
2159:   DMRefineHookLink link,*p;

2163:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2164:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2165:       link = *p;
2166:       *p = link->next;
2167:       PetscFree(link);
2168:       break;
2169:     }
2170:   }
2171:   return(0);
2172: }

2174: /*@
2175:    DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()

2177:    Collective if any hooks are

2179:    Input Arguments:
2180: +  coarse - coarser DM to use as a base
2181: .  interp - interpolation matrix, apply using MatInterpolate()
2182: -  fine - finer DM to update

2184:    Level: developer

2186: .seealso: DMRefineHookAdd(), MatInterpolate()
2187: @*/
2188: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2189: {
2190:   PetscErrorCode   ierr;
2191:   DMRefineHookLink link;

2194:   for (link=fine->refinehook; link; link=link->next) {
2195:     if (link->interphook) {
2196:       (*link->interphook)(coarse,interp,fine,link->ctx);
2197:     }
2198:   }
2199:   return(0);
2200: }

2202: /*@
2203:     DMGetRefineLevel - Get's the number of refinements that have generated this DM.

2205:     Not Collective

2207:     Input Parameter:
2208: .   dm - the DM object

2210:     Output Parameter:
2211: .   level - number of refinements

2213:     Level: developer

2215: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

2217: @*/
2218: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2219: {
2222:   *level = dm->levelup;
2223:   return(0);
2224: }

2226: /*@
2227:     DMSetRefineLevel - Set's the number of refinements that have generated this DM.

2229:     Not Collective

2231:     Input Parameter:
2232: +   dm - the DM object
2233: -   level - number of refinements

2235:     Level: advanced

2237:     Notes:
2238:     This value is used by PCMG to determine how many multigrid levels to use

2240: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

2242: @*/
2243: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2244: {
2247:   dm->levelup = level;
2248:   return(0);
2249: }

2251: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2252: {
2256:   *tdm = dm->transformDM;
2257:   return(0);
2258: }

2260: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2261: {
2265:   *tv = dm->transform;
2266:   return(0);
2267: }

2269: /*@
2270:   DMHasBasisTransform - Whether we employ a basis transformation from functions in global vectors to functions in local vectors

2272:   Input Parameter:
2273: . dm - The DM

2275:   Output Parameter:
2276: . flg - PETSC_TRUE if a basis transformation should be done

2278:   Level: developer

2280: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2281: @*/
2282: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2283: {
2284:   Vec            tv;

2290:   DMGetBasisTransformVec_Internal(dm, &tv);
2291:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2292:   return(0);
2293: }

2295: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2296: {
2297:   PetscSection   s, ts;
2298:   PetscScalar   *ta;
2299:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2303:   DMGetCoordinateDim(dm, &cdim);
2304:   DMGetLocalSection(dm, &s);
2305:   PetscSectionGetChart(s, &pStart, &pEnd);
2306:   PetscSectionGetNumFields(s, &Nf);
2307:   DMClone(dm, &dm->transformDM);
2308:   DMGetLocalSection(dm->transformDM, &ts);
2309:   PetscSectionSetNumFields(ts, Nf);
2310:   PetscSectionSetChart(ts, pStart, pEnd);
2311:   for (f = 0; f < Nf; ++f) {
2312:     PetscSectionGetFieldComponents(s, f, &Nc);
2313:     /* We could start to label fields by their transformation properties */
2314:     if (Nc != cdim) continue;
2315:     for (p = pStart; p < pEnd; ++p) {
2316:       PetscSectionGetFieldDof(s, p, f, &dof);
2317:       if (!dof) continue;
2318:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2319:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2320:     }
2321:   }
2322:   PetscSectionSetUp(ts);
2323:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2324:   VecGetArray(dm->transform, &ta);
2325:   for (p = pStart; p < pEnd; ++p) {
2326:     for (f = 0; f < Nf; ++f) {
2327:       PetscSectionGetFieldDof(ts, p, f, &dof);
2328:       if (dof) {
2329:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2330:         PetscScalar       *tva;
2331:         const PetscScalar *A;

2333:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2334:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2335:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2336:         PetscArraycpy(tva, A, PetscSqr(cdim));
2337:       }
2338:     }
2339:   }
2340:   VecRestoreArray(dm->transform, &ta);
2341:   return(0);
2342: }

2344: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2345: {

2351:   newdm->transformCtx       = dm->transformCtx;
2352:   newdm->transformSetUp     = dm->transformSetUp;
2353:   newdm->transformDestroy   = NULL;
2354:   newdm->transformGetMatrix = dm->transformGetMatrix;
2355:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2356:   return(0);
2357: }

2359: /*@C
2360:    DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called

2362:    Logically Collective

2364:    Input Arguments:
2365: +  dm - the DM
2366: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2367: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2368: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2370:    Calling sequence for beginhook:
2371: $    beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)

2373: +  dm - global DM
2374: .  g - global vector
2375: .  mode - mode
2376: .  l - local vector
2377: -  ctx - optional user-defined function context


2380:    Calling sequence for endhook:
2381: $    endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)

2383: +  global - global DM
2384: -  ctx - optional user-defined function context

2386:    Level: advanced

2388: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2389: @*/
2390: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2391: {
2392:   PetscErrorCode          ierr;
2393:   DMGlobalToLocalHookLink link,*p;

2397:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2398:   PetscNew(&link);
2399:   link->beginhook = beginhook;
2400:   link->endhook   = endhook;
2401:   link->ctx       = ctx;
2402:   link->next      = NULL;
2403:   *p              = link;
2404:   return(0);
2405: }

2407: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2408: {
2409:   Mat cMat;
2410:   Vec cVec;
2411:   PetscSection section, cSec;
2412:   PetscInt pStart, pEnd, p, dof;

2417:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2418:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2419:     PetscInt nRows;

2421:     MatGetSize(cMat,&nRows,NULL);
2422:     if (nRows <= 0) return(0);
2423:     DMGetLocalSection(dm,&section);
2424:     MatCreateVecs(cMat,NULL,&cVec);
2425:     MatMult(cMat,l,cVec);
2426:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2427:     for (p = pStart; p < pEnd; p++) {
2428:       PetscSectionGetDof(cSec,p,&dof);
2429:       if (dof) {
2430:         PetscScalar *vals;
2431:         VecGetValuesSection(cVec,cSec,p,&vals);
2432:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2433:       }
2434:     }
2435:     VecDestroy(&cVec);
2436:   }
2437:   return(0);
2438: }

2440: /*@
2441:     DMGlobalToLocal - update local vectors from global vector

2443:     Neighbor-wise Collective on dm

2445:     Input Parameters:
2446: +   dm - the DM object
2447: .   g - the global vector
2448: .   mode - INSERT_VALUES or ADD_VALUES
2449: -   l - the local vector

2451:     Notes:
2452:     The communication involved in this update can be overlapped with computation by using
2453:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2455:     Level: beginner

2457: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()

2459: @*/
2460: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2461: {

2465:   DMGlobalToLocalBegin(dm,g,mode,l);
2466:   DMGlobalToLocalEnd(dm,g,mode,l);
2467:   return(0);
2468: }

2470: /*@
2471:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2473:     Neighbor-wise Collective on dm

2475:     Input Parameters:
2476: +   dm - the DM object
2477: .   g - the global vector
2478: .   mode - INSERT_VALUES or ADD_VALUES
2479: -   l - the local vector

2481:     Level: intermediate

2483: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()

2485: @*/
2486: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2487: {
2488:   PetscSF                 sf;
2489:   PetscErrorCode          ierr;
2490:   DMGlobalToLocalHookLink link;

2494:   for (link=dm->gtolhook; link; link=link->next) {
2495:     if (link->beginhook) {
2496:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2497:     }
2498:   }
2499:   DMGetSectionSF(dm, &sf);
2500:   if (sf) {
2501:     const PetscScalar *gArray;
2502:     PetscScalar       *lArray;

2504:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2505:     VecGetArrayInPlace(l, &lArray);
2506:     VecGetArrayReadInPlace(g, &gArray);
2507:     PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
2508:     VecRestoreArrayInPlace(l, &lArray);
2509:     VecRestoreArrayReadInPlace(g, &gArray);
2510:   } else {
2511:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2512:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2513:   }
2514:   return(0);
2515: }

2517: /*@
2518:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2520:     Neighbor-wise Collective on dm

2522:     Input Parameters:
2523: +   dm - the DM object
2524: .   g - the global vector
2525: .   mode - INSERT_VALUES or ADD_VALUES
2526: -   l - the local vector

2528:     Level: intermediate

2530: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMLocalToGlobalBegin(), DMLocalToGlobal(), DMLocalToGlobalBegin(), DMLocalToGlobalEnd()

2532: @*/
2533: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2534: {
2535:   PetscSF                 sf;
2536:   PetscErrorCode          ierr;
2537:   const PetscScalar      *gArray;
2538:   PetscScalar            *lArray;
2539:   PetscBool               transform;
2540:   DMGlobalToLocalHookLink link;

2544:   DMGetSectionSF(dm, &sf);
2545:   DMHasBasisTransform(dm, &transform);
2546:   if (sf) {
2547:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2549:     VecGetArrayInPlace(l, &lArray);
2550:     VecGetArrayReadInPlace(g, &gArray);
2551:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2552:     VecRestoreArrayInPlace(l, &lArray);
2553:     VecRestoreArrayReadInPlace(g, &gArray);
2554:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2555:   } else {
2556:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2557:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2558:   }
2559:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2560:   for (link=dm->gtolhook; link; link=link->next) {
2561:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2562:   }
2563:   return(0);
2564: }

2566: /*@C
2567:    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called

2569:    Logically Collective

2571:    Input Arguments:
2572: +  dm - the DM
2573: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2574: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2575: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2577:    Calling sequence for beginhook:
2578: $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)

2580: +  dm - global DM
2581: .  l - local vector
2582: .  mode - mode
2583: .  g - global vector
2584: -  ctx - optional user-defined function context


2587:    Calling sequence for endhook:
2588: $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)

2590: +  global - global DM
2591: .  l - local vector
2592: .  mode - mode
2593: .  g - global vector
2594: -  ctx - optional user-defined function context

2596:    Level: advanced

2598: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2599: @*/
2600: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2601: {
2602:   PetscErrorCode          ierr;
2603:   DMLocalToGlobalHookLink link,*p;

2607:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2608:   PetscNew(&link);
2609:   link->beginhook = beginhook;
2610:   link->endhook   = endhook;
2611:   link->ctx       = ctx;
2612:   link->next      = NULL;
2613:   *p              = link;
2614:   return(0);
2615: }

2617: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2618: {
2619:   Mat cMat;
2620:   Vec cVec;
2621:   PetscSection section, cSec;
2622:   PetscInt pStart, pEnd, p, dof;

2627:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2628:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2629:     PetscInt nRows;

2631:     MatGetSize(cMat,&nRows,NULL);
2632:     if (nRows <= 0) return(0);
2633:     DMGetLocalSection(dm,&section);
2634:     MatCreateVecs(cMat,NULL,&cVec);
2635:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2636:     for (p = pStart; p < pEnd; p++) {
2637:       PetscSectionGetDof(cSec,p,&dof);
2638:       if (dof) {
2639:         PetscInt d;
2640:         PetscScalar *vals;
2641:         VecGetValuesSection(l,section,p,&vals);
2642:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2643:         /* for this to be the true transpose, we have to zero the values that
2644:          * we just extracted */
2645:         for (d = 0; d < dof; d++) {
2646:           vals[d] = 0.;
2647:         }
2648:       }
2649:     }
2650:     MatMultTransposeAdd(cMat,cVec,l,l);
2651:     VecDestroy(&cVec);
2652:   }
2653:   return(0);
2654: }
2655: /*@
2656:     DMLocalToGlobal - updates global vectors from local vectors

2658:     Neighbor-wise Collective on dm

2660:     Input Parameters:
2661: +   dm - the DM object
2662: .   l - the local vector
2663: .   mode - if INSERT_VALUES then no parallel communication is used, if ADD_VALUES then all ghost points from the same base point accumulate into that base point.
2664: -   g - the global vector

2666:     Notes:
2667:     The communication involved in this update can be overlapped with computation by using
2668:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

2670:     In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2671:            INSERT_VALUES is not supported for DMDA; in that case simply compute the values directly into a global vector instead of a local one.

2673:     Level: beginner

2675: .seealso DMLocalToGlobalBegin(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()

2677: @*/
2678: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2679: {

2683:   DMLocalToGlobalBegin(dm,l,mode,g);
2684:   DMLocalToGlobalEnd(dm,l,mode,g);
2685:   return(0);
2686: }

2688: /*@
2689:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2691:     Neighbor-wise Collective on dm

2693:     Input Parameters:
2694: +   dm - the DM object
2695: .   l - the local vector
2696: .   mode - if INSERT_VALUES then no parallel communication is used, if ADD_VALUES then all ghost points from the same base point accumulate into that base point.
2697: -   g - the global vector

2699:     Notes:
2700:     In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation.
2701:            INSERT_VALUES is not supported for DMDA, in that case simply compute the values directly into a global vector instead of a local one.

2703:     Level: intermediate

2705: .seealso DMLocalToGlobal(), DMLocalToGlobalEnd(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocal(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()

2707: @*/
2708: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2709: {
2710:   PetscSF                 sf;
2711:   PetscSection            s, gs;
2712:   DMLocalToGlobalHookLink link;
2713:   Vec                     tmpl;
2714:   const PetscScalar      *lArray;
2715:   PetscScalar            *gArray;
2716:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2717:   PetscErrorCode          ierr;

2721:   for (link=dm->ltoghook; link; link=link->next) {
2722:     if (link->beginhook) {
2723:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2724:     }
2725:   }
2726:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2727:   DMGetSectionSF(dm, &sf);
2728:   DMGetLocalSection(dm, &s);
2729:   switch (mode) {
2730:   case INSERT_VALUES:
2731:   case INSERT_ALL_VALUES:
2732:   case INSERT_BC_VALUES:
2733:     isInsert = PETSC_TRUE; break;
2734:   case ADD_VALUES:
2735:   case ADD_ALL_VALUES:
2736:   case ADD_BC_VALUES:
2737:     isInsert = PETSC_FALSE; break;
2738:   default:
2739:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2740:   }
2741:   if ((sf && !isInsert) || (s && isInsert)) {
2742:     DMHasBasisTransform(dm, &transform);
2743:     if (transform) {
2744:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2745:       VecCopy(l, tmpl);
2746:       DMPlexLocalToGlobalBasis(dm, tmpl);
2747:       VecGetArrayRead(tmpl, &lArray);
2748:     } else if (isInsert) {
2749:       VecGetArrayRead(l, &lArray);
2750:     } else {
2751:       VecGetArrayReadInPlace(l, &lArray);
2752:       l_inplace = PETSC_TRUE;
2753:     }
2754:     if (s && isInsert) {
2755:       VecGetArray(g, &gArray);
2756:     } else {
2757:       VecGetArrayInPlace(g, &gArray);
2758:       g_inplace = PETSC_TRUE;
2759:     }
2760:     if (sf && !isInsert) {
2761:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2762:     } else if (s && isInsert) {
2763:       PetscInt gStart, pStart, pEnd, p;

2765:       DMGetGlobalSection(dm, &gs);
2766:       PetscSectionGetChart(s, &pStart, &pEnd);
2767:       VecGetOwnershipRange(g, &gStart, NULL);
2768:       for (p = pStart; p < pEnd; ++p) {
2769:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2771:         PetscSectionGetDof(s, p, &dof);
2772:         PetscSectionGetDof(gs, p, &gdof);
2773:         PetscSectionGetConstraintDof(s, p, &cdof);
2774:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2775:         PetscSectionGetOffset(s, p, &off);
2776:         PetscSectionGetOffset(gs, p, &goff);
2777:         /* Ignore off-process data and points with no global data */
2778:         if (!gdof || goff < 0) continue;
2779:         if (dof != gdof) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
2780:         /* If no constraints are enforced in the global vector */
2781:         if (!gcdof) {
2782:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2783:           /* If constraints are enforced in the global vector */
2784:         } else if (cdof == gcdof) {
2785:           const PetscInt *cdofs;
2786:           PetscInt        cind = 0;

2788:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2789:           for (d = 0, e = 0; d < dof; ++d) {
2790:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2791:             gArray[goff-gStart+e++] = lArray[off+d];
2792:           }
2793:         } else SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
2794:       }
2795:     }
2796:     if (g_inplace) {
2797:       VecRestoreArrayInPlace(g, &gArray);
2798:     } else {
2799:       VecRestoreArray(g, &gArray);
2800:     }
2801:     if (transform) {
2802:       VecRestoreArrayRead(tmpl, &lArray);
2803:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2804:     } else if (l_inplace) {
2805:       VecRestoreArrayReadInPlace(l, &lArray);
2806:     } else {
2807:       VecRestoreArrayRead(l, &lArray);
2808:     }
2809:   } else {
2810:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2811:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2812:   }
2813:   return(0);
2814: }

2816: /*@
2817:     DMLocalToGlobalEnd - updates global vectors from local vectors

2819:     Neighbor-wise Collective on dm

2821:     Input Parameters:
2822: +   dm - the DM object
2823: .   l - the local vector
2824: .   mode - INSERT_VALUES or ADD_VALUES
2825: -   g - the global vector

2827:     Level: intermediate

2829: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()

2831: @*/
2832: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2833: {
2834:   PetscSF                 sf;
2835:   PetscSection            s;
2836:   DMLocalToGlobalHookLink link;
2837:   PetscBool               isInsert, transform;
2838:   PetscErrorCode          ierr;

2842:   DMGetSectionSF(dm, &sf);
2843:   DMGetLocalSection(dm, &s);
2844:   switch (mode) {
2845:   case INSERT_VALUES:
2846:   case INSERT_ALL_VALUES:
2847:     isInsert = PETSC_TRUE; break;
2848:   case ADD_VALUES:
2849:   case ADD_ALL_VALUES:
2850:     isInsert = PETSC_FALSE; break;
2851:   default:
2852:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2853:   }
2854:   if (sf && !isInsert) {
2855:     const PetscScalar *lArray;
2856:     PetscScalar       *gArray;
2857:     Vec                tmpl;

2859:     DMHasBasisTransform(dm, &transform);
2860:     if (transform) {
2861:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2862:       VecGetArrayRead(tmpl, &lArray);
2863:     } else {
2864:       VecGetArrayReadInPlace(l, &lArray);
2865:     }
2866:     VecGetArrayInPlace(g, &gArray);
2867:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2868:     if (transform) {
2869:       VecRestoreArrayRead(tmpl, &lArray);
2870:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2871:     } else {
2872:       VecRestoreArrayReadInPlace(l, &lArray);
2873:     }
2874:     VecRestoreArrayInPlace(g, &gArray);
2875:   } else if (s && isInsert) {
2876:   } else {
2877:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2878:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2879:   }
2880:   for (link=dm->ltoghook; link; link=link->next) {
2881:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2882:   }
2883:   return(0);
2884: }

2886: /*@
2887:    DMLocalToLocalBegin - Maps from a local vector (including ghost points
2888:    that contain irrelevant values) to another local vector where the ghost
2889:    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().

2891:    Neighbor-wise Collective on dm

2893:    Input Parameters:
2894: +  dm - the DM object
2895: .  g - the original local vector
2896: -  mode - one of INSERT_VALUES or ADD_VALUES

2898:    Output Parameter:
2899: .  l  - the local vector with correct ghost values

2901:    Level: intermediate

2903:    Notes:
2904:    The local vectors used here need not be the same as those
2905:    obtained from DMCreateLocalVector(), BUT they
2906:    must have the same parallel data layout; they could, for example, be
2907:    obtained with VecDuplicate() from the DM originating vectors.

2909: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()

2911: @*/
2912: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2913: {
2914:   PetscErrorCode          ierr;

2918:   if (!dm->ops->localtolocalbegin) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2919:   (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2920:   return(0);
2921: }

2923: /*@
2924:    DMLocalToLocalEnd - Maps from a local vector (including ghost points
2925:    that contain irrelevant values) to another local vector where the ghost
2926:    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().

2928:    Neighbor-wise Collective on dm

2930:    Input Parameters:
2931: +  da - the DM object
2932: .  g - the original local vector
2933: -  mode - one of INSERT_VALUES or ADD_VALUES

2935:    Output Parameter:
2936: .  l  - the local vector with correct ghost values

2938:    Level: intermediate

2940:    Notes:
2941:    The local vectors used here need not be the same as those
2942:    obtained from DMCreateLocalVector(), BUT they
2943:    must have the same parallel data layout; they could, for example, be
2944:    obtained with VecDuplicate() from the DM originating vectors.

2946: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()

2948: @*/
2949: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2950: {
2951:   PetscErrorCode          ierr;

2955:   if (!dm->ops->localtolocalend) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM does not support local to local maps");
2956:   (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2957:   return(0);
2958: }


2961: /*@
2962:     DMCoarsen - Coarsens a DM object

2964:     Collective on dm

2966:     Input Parameter:
2967: +   dm - the DM object
2968: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2970:     Output Parameter:
2971: .   dmc - the coarsened DM

2973:     Level: developer

2975: .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

2977: @*/
2978: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2979: {
2980:   PetscErrorCode    ierr;
2981:   DMCoarsenHookLink link;

2985:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
2986:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2987:   (*dm->ops->coarsen)(dm, comm, dmc);
2988:   if (*dmc) {
2989:     DMSetCoarseDM(dm,*dmc);
2990:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2991:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2992:     (*dmc)->ctx               = dm->ctx;
2993:     (*dmc)->levelup           = dm->levelup;
2994:     (*dmc)->leveldown         = dm->leveldown + 1;
2995:     DMSetMatType(*dmc,dm->mattype);
2996:     for (link=dm->coarsenhook; link; link=link->next) {
2997:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2998:     }
2999:   }
3000:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3001:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3002:   return(0);
3003: }

3005: /*@C
3006:    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid

3008:    Logically Collective

3010:    Input Arguments:
3011: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3012: .  coarsenhook - function to run when setting up a coarser level
3013: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3014: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3016:    Calling sequence of coarsenhook:
3017: $    coarsenhook(DM fine,DM coarse,void *ctx);

3019: +  fine - fine level DM
3020: .  coarse - coarse level DM to restrict problem to
3021: -  ctx - optional user-defined function context

3023:    Calling sequence for restricthook:
3024: $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)

3026: +  fine - fine level DM
3027: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
3028: .  rscale - scaling vector for restriction
3029: .  inject - matrix restricting by injection
3030: .  coarse - coarse level DM to update
3031: -  ctx - optional user-defined function context

3033:    Level: advanced

3035:    Notes:
3036:    This function is only needed if auxiliary data needs to be set up on coarse grids.

3038:    If this function is called multiple times, the hooks will be run in the order they are added.

3040:    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3041:    extract the finest level information from its context (instead of from the SNES).

3043:    This function is currently not available from Fortran.

3045: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3046: @*/
3047: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3048: {
3049:   PetscErrorCode    ierr;
3050:   DMCoarsenHookLink link,*p;

3054:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3055:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3056:   }
3057:   PetscNew(&link);
3058:   link->coarsenhook  = coarsenhook;
3059:   link->restricthook = restricthook;
3060:   link->ctx          = ctx;
3061:   link->next         = NULL;
3062:   *p                 = link;
3063:   return(0);
3064: }

3066: /*@C
3067:    DMCoarsenHookRemove - remove a callback from the list of hooks to be run when restricting a nonlinear problem to the coarse grid

3069:    Logically Collective

3071:    Input Arguments:
3072: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3073: .  coarsenhook - function to run when setting up a coarser level
3074: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3075: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3077:    Level: advanced

3079:    Notes:
3080:    This function does nothing if the hook is not in the list.

3082:    This function is currently not available from Fortran.

3084: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3085: @*/
3086: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3087: {
3088:   PetscErrorCode    ierr;
3089:   DMCoarsenHookLink link,*p;

3093:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3094:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3095:       link = *p;
3096:       *p = link->next;
3097:       PetscFree(link);
3098:       break;
3099:     }
3100:   }
3101:   return(0);
3102: }


3105: /*@
3106:    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()

3108:    Collective if any hooks are

3110:    Input Arguments:
3111: +  fine - finer DM to use as a base
3112: .  restrct - restriction matrix, apply using MatRestrict()
3113: .  rscale - scaling vector for restriction
3114: .  inject - injection matrix, also use MatRestrict()
3115: -  coarse - coarser DM to update

3117:    Level: developer

3119: .seealso: DMCoarsenHookAdd(), MatRestrict()
3120: @*/
3121: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3122: {
3123:   PetscErrorCode    ierr;
3124:   DMCoarsenHookLink link;

3127:   for (link=fine->coarsenhook; link; link=link->next) {
3128:     if (link->restricthook) {
3129:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3130:     }
3131:   }
3132:   return(0);
3133: }

3135: /*@C
3136:    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid

3138:    Logically Collective on global

3140:    Input Arguments:
3141: +  global - global DM
3142: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3143: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3144: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)


3147:    Calling sequence for ddhook:
3148: $    ddhook(DM global,DM block,void *ctx)

3150: +  global - global DM
3151: .  block  - block DM
3152: -  ctx - optional user-defined function context

3154:    Calling sequence for restricthook:
3155: $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)

3157: +  global - global DM
3158: .  out    - scatter to the outer (with ghost and overlap points) block vector
3159: .  in     - scatter to block vector values only owned locally
3160: .  block  - block DM
3161: -  ctx - optional user-defined function context

3163:    Level: advanced

3165:    Notes:
3166:    This function is only needed if auxiliary data needs to be set up on subdomain DMs.

3168:    If this function is called multiple times, the hooks will be run in the order they are added.

3170:    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3171:    extract the global information from its context (instead of from the SNES).

3173:    This function is currently not available from Fortran.

3175: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3176: @*/
3177: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3178: {
3179:   PetscErrorCode      ierr;
3180:   DMSubDomainHookLink link,*p;

3184:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3185:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3186:   }
3187:   PetscNew(&link);
3188:   link->restricthook = restricthook;
3189:   link->ddhook       = ddhook;
3190:   link->ctx          = ctx;
3191:   link->next         = NULL;
3192:   *p                 = link;
3193:   return(0);
3194: }

3196: /*@C
3197:    DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid

3199:    Logically Collective

3201:    Input Arguments:
3202: +  global - global DM
3203: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3204: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3205: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3207:    Level: advanced

3209:    Notes:

3211:    This function is currently not available from Fortran.

3213: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3214: @*/
3215: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3216: {
3217:   PetscErrorCode      ierr;
3218:   DMSubDomainHookLink link,*p;

3222:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3223:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3224:       link = *p;
3225:       *p = link->next;
3226:       PetscFree(link);
3227:       break;
3228:     }
3229:   }
3230:   return(0);
3231: }

3233: /*@
3234:    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()

3236:    Collective if any hooks are

3238:    Input Arguments:
3239: +  fine - finer DM to use as a base
3240: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3241: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3242: -  coarse - coarer DM to update

3244:    Level: developer

3246: .seealso: DMCoarsenHookAdd(), MatRestrict()
3247: @*/
3248: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3249: {
3250:   PetscErrorCode      ierr;
3251:   DMSubDomainHookLink link;

3254:   for (link=global->subdomainhook; link; link=link->next) {
3255:     if (link->restricthook) {
3256:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3257:     }
3258:   }
3259:   return(0);
3260: }

3262: /*@
3263:     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.

3265:     Not Collective

3267:     Input Parameter:
3268: .   dm - the DM object

3270:     Output Parameter:
3271: .   level - number of coarsenings

3273:     Level: developer

3275: .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

3277: @*/
3278: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3279: {
3283:   *level = dm->leveldown;
3284:   return(0);
3285: }

3287: /*@
3288:     DMSetCoarsenLevel - Sets the number of coarsenings that have generated this DM.

3290:     Not Collective

3292:     Input Parameters:
3293: +   dm - the DM object
3294: -   level - number of coarsenings

3296:     Level: developer

3298: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3299: @*/
3300: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3301: {
3304:   dm->leveldown = level;
3305:   return(0);
3306: }



3310: /*@C
3311:     DMRefineHierarchy - Refines a DM object, all levels at once

3313:     Collective on dm

3315:     Input Parameter:
3316: +   dm - the DM object
3317: -   nlevels - the number of levels of refinement

3319:     Output Parameter:
3320: .   dmf - the refined DM hierarchy

3322:     Level: developer

3324: .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

3326: @*/
3327: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3328: {

3333:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3334:   if (nlevels == 0) return(0);
3336:   if (dm->ops->refinehierarchy) {
3337:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3338:   } else if (dm->ops->refine) {
3339:     PetscInt i;

3341:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3342:     for (i=1; i<nlevels; i++) {
3343:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3344:     }
3345:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3346:   return(0);
3347: }

3349: /*@C
3350:     DMCoarsenHierarchy - Coarsens a DM object, all levels at once

3352:     Collective on dm

3354:     Input Parameter:
3355: +   dm - the DM object
3356: -   nlevels - the number of levels of coarsening

3358:     Output Parameter:
3359: .   dmc - the coarsened DM hierarchy

3361:     Level: developer

3363: .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()

3365: @*/
3366: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3367: {

3372:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3373:   if (nlevels == 0) return(0);
3375:   if (dm->ops->coarsenhierarchy) {
3376:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3377:   } else if (dm->ops->coarsen) {
3378:     PetscInt i;

3380:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3381:     for (i=1; i<nlevels; i++) {
3382:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3383:     }
3384:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3385:   return(0);
3386: }

3388: /*@C
3389:     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed

3391:     Not Collective

3393:     Input Parameters:
3394: +   dm - the DM object
3395: -   destroy - the destroy function

3397:     Level: intermediate

3399: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()

3401: @*/
3402: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3403: {
3406:   dm->ctxdestroy = destroy;
3407:   return(0);
3408: }

3410: /*@
3411:     DMSetApplicationContext - Set a user context into a DM object

3413:     Not Collective

3415:     Input Parameters:
3416: +   dm - the DM object
3417: -   ctx - the user context

3419:     Level: intermediate

3421: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()

3423: @*/
3424: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3425: {
3428:   dm->ctx = ctx;
3429:   return(0);
3430: }

3432: /*@
3433:     DMGetApplicationContext - Gets a user context from a DM object

3435:     Not Collective

3437:     Input Parameter:
3438: .   dm - the DM object

3440:     Output Parameter:
3441: .   ctx - the user context

3443:     Level: intermediate

3445: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()

3447: @*/
3448: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3449: {
3452:   *(void**)ctx = dm->ctx;
3453:   return(0);
3454: }

3456: /*@C
3457:     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.

3459:     Logically Collective on dm

3461:     Input Parameter:
3462: +   dm - the DM object
3463: -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)

3465:     Level: intermediate

3467: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3468:          DMSetJacobian()

3470: @*/
3471: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3472: {
3475:   dm->ops->computevariablebounds = f;
3476:   return(0);
3477: }

3479: /*@
3480:     DMHasVariableBounds - does the DM object have a variable bounds function?

3482:     Not Collective

3484:     Input Parameter:
3485: .   dm - the DM object to destroy

3487:     Output Parameter:
3488: .   flg - PETSC_TRUE if the variable bounds function exists

3490:     Level: developer

3492: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()

3494: @*/
3495: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3496: {
3500:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3501:   return(0);
3502: }

3504: /*@C
3505:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3507:     Logically Collective on dm

3509:     Input Parameters:
3510: .   dm - the DM object

3512:     Output parameters:
3513: +   xl - lower bound
3514: -   xu - upper bound

3516:     Level: advanced

3518:     Notes:
3519:     This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()

3521: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()

3523: @*/
3524: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3525: {

3532:   if (!dm->ops->computevariablebounds) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeVariableBounds",((PetscObject)dm)->type_name);
3533:   (*dm->ops->computevariablebounds)(dm, xl,xu);
3534:   return(0);
3535: }

3537: /*@
3538:     DMHasColoring - does the DM object have a method of providing a coloring?

3540:     Not Collective

3542:     Input Parameter:
3543: .   dm - the DM object

3545:     Output Parameter:
3546: .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().

3548:     Level: developer

3550: .seealso DMCreateColoring()

3552: @*/
3553: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3554: {
3558:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3559:   return(0);
3560: }

3562: /*@
3563:     DMHasCreateRestriction - does the DM object have a method of providing a restriction?

3565:     Not Collective

3567:     Input Parameter:
3568: .   dm - the DM object

3570:     Output Parameter:
3571: .   flg - PETSC_TRUE if the DM has facilities for DMCreateRestriction().

3573:     Level: developer

3575: .seealso DMCreateRestriction()

3577: @*/
3578: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3579: {
3583:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3584:   return(0);
3585: }


3588: /*@
3589:     DMHasCreateInjection - does the DM object have a method of providing an injection?

3591:     Not Collective

3593:     Input Parameter:
3594: .   dm - the DM object

3596:     Output Parameter:
3597: .   flg - PETSC_TRUE if the DM has facilities for DMCreateInjection().

3599:     Level: developer

3601: .seealso DMCreateInjection()

3603: @*/
3604: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3605: {

3611:   if (dm->ops->hascreateinjection) {
3612:     (*dm->ops->hascreateinjection)(dm,flg);
3613:   } else {
3614:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3615:   }
3616:   return(0);
3617: }

3619: PetscFunctionList DMList              = NULL;
3620: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3622: /*@C
3623:   DMSetType - Builds a DM, for a particular DM implementation.

3625:   Collective on dm

3627:   Input Parameters:
3628: + dm     - The DM object
3629: - method - The name of the DM type

3631:   Options Database Key:
3632: . -dm_type <type> - Sets the DM type; use -help for a list of available types

3634:   Notes:
3635:   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).

3637:   Level: intermediate

3639: .seealso: DMGetType(), DMCreate()
3640: @*/
3641: PetscErrorCode  DMSetType(DM dm, DMType method)
3642: {
3643:   PetscErrorCode (*r)(DM);
3644:   PetscBool      match;

3649:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3650:   if (match) return(0);

3652:   DMRegisterAll();
3653:   PetscFunctionListFind(DMList,method,&r);
3654:   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);

3656:   if (dm->ops->destroy) {
3657:     (*dm->ops->destroy)(dm);
3658:   }
3659:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3660:   PetscObjectChangeTypeName((PetscObject)dm,method);
3661:   (*r)(dm);
3662:   return(0);
3663: }

3665: /*@C
3666:   DMGetType - Gets the DM type name (as a string) from the DM.

3668:   Not Collective

3670:   Input Parameter:
3671: . dm  - The DM

3673:   Output Parameter:
3674: . type - The DM type name

3676:   Level: intermediate

3678: .seealso: DMSetType(), DMCreate()
3679: @*/
3680: PetscErrorCode  DMGetType(DM dm, DMType *type)
3681: {

3687:   DMRegisterAll();
3688:   *type = ((PetscObject)dm)->type_name;
3689:   return(0);
3690: }

3692: /*@C
3693:   DMConvert - Converts a DM to another DM, either of the same or different type.

3695:   Collective on dm

3697:   Input Parameters:
3698: + dm - the DM
3699: - newtype - new DM type (use "same" for the same type)

3701:   Output Parameter:
3702: . M - pointer to new DM

3704:   Notes:
3705:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3706:   the MPI communicator of the generated DM is always the same as the communicator
3707:   of the input DM.

3709:   Level: intermediate

3711: .seealso: DMCreate()
3712: @*/
3713: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3714: {
3715:   DM             B;
3716:   char           convname[256];
3717:   PetscBool      sametype/*, issame */;

3724:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3725:   /* PetscStrcmp(newtype, "same", &issame); */
3726:   if (sametype) {
3727:     *M   = dm;
3728:     PetscObjectReference((PetscObject) dm);
3729:     return(0);
3730:   } else {
3731:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3733:     /*
3734:        Order of precedence:
3735:        1) See if a specialized converter is known to the current DM.
3736:        2) See if a specialized converter is known to the desired DM class.
3737:        3) See if a good general converter is registered for the desired class
3738:        4) See if a good general converter is known for the current matrix.
3739:        5) Use a really basic converter.
3740:     */

3742:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3743:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3744:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3745:     PetscStrlcat(convname,"_",sizeof(convname));
3746:     PetscStrlcat(convname,newtype,sizeof(convname));
3747:     PetscStrlcat(convname,"_C",sizeof(convname));
3748:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3749:     if (conv) goto foundconv;

3751:     /* 2)  See if a specialized converter is known to the desired DM class. */
3752:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3753:     DMSetType(B, newtype);
3754:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3755:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3756:     PetscStrlcat(convname,"_",sizeof(convname));
3757:     PetscStrlcat(convname,newtype,sizeof(convname));
3758:     PetscStrlcat(convname,"_C",sizeof(convname));
3759:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3760:     if (conv) {
3761:       DMDestroy(&B);
3762:       goto foundconv;
3763:     }

3765: #if 0
3766:     /* 3) See if a good general converter is registered for the desired class */
3767:     conv = B->ops->convertfrom;
3768:     DMDestroy(&B);
3769:     if (conv) goto foundconv;

3771:     /* 4) See if a good general converter is known for the current matrix */
3772:     if (dm->ops->convert) {
3773:       conv = dm->ops->convert;
3774:     }
3775:     if (conv) goto foundconv;
3776: #endif

3778:     /* 5) Use a really basic converter. */
3779:     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);

3781: foundconv:
3782:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3783:     (*conv)(dm,newtype,M);
3784:     /* Things that are independent of DM type: We should consult DMClone() here */
3785:     {
3786:       PetscBool             isper;
3787:       const PetscReal      *maxCell, *L;
3788:       const DMBoundaryType *bd;
3789:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3790:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3791:     }
3792:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3793:   }
3794:   PetscObjectStateIncrease((PetscObject) *M);
3795:   return(0);
3796: }

3798: /*--------------------------------------------------------------------------------------------------------------------*/

3800: /*@C
3801:   DMRegister -  Adds a new DM component implementation

3803:   Not Collective

3805:   Input Parameters:
3806: + name        - The name of a new user-defined creation routine
3807: - create_func - The creation routine itself

3809:   Notes:
3810:   DMRegister() may be called multiple times to add several user-defined DMs


3813:   Sample usage:
3814: .vb
3815:     DMRegister("my_da", MyDMCreate);
3816: .ve

3818:   Then, your DM type can be chosen with the procedural interface via
3819: .vb
3820:     DMCreate(MPI_Comm, DM *);
3821:     DMSetType(DM,"my_da");
3822: .ve
3823:    or at runtime via the option
3824: .vb
3825:     -da_type my_da
3826: .ve

3828:   Level: advanced

3830: .seealso: DMRegisterAll(), DMRegisterDestroy()

3832: @*/
3833: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3834: {

3838:   DMInitializePackage();
3839:   PetscFunctionListAdd(&DMList,sname,function);
3840:   return(0);
3841: }

3843: /*@C
3844:   DMLoad - Loads a DM that has been stored in binary  with DMView().

3846:   Collective on viewer

3848:   Input Parameters:
3849: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3850:            some related function before a call to DMLoad().
3851: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3852:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3854:    Level: intermediate

3856:   Notes:
3857:    The type is determined by the data in the file, any type set into the DM before this call is ignored.

3859:   Notes for advanced users:
3860:   Most users should not need to know the details of the binary storage
3861:   format, since DMLoad() and DMView() completely hide these details.
3862:   But for anyone who's interested, the standard binary matrix storage
3863:   format is
3864: .vb
3865:      has not yet been determined
3866: .ve

3868: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3869: @*/
3870: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3871: {
3872:   PetscBool      isbinary, ishdf5;

3878:   PetscViewerCheckReadable(viewer);
3879:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3880:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3881:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3882:   if (isbinary) {
3883:     PetscInt classid;
3884:     char     type[256];

3886:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3887:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3888:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3889:     DMSetType(newdm, type);
3890:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3891:   } else if (ishdf5) {
3892:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3893:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3894:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3895:   return(0);
3896: }

3898: /*@
3899:   DMGetLocalBoundingBox - Returns the bounding box for the piece of the DM on this process.

3901:   Not collective

3903:   Input Parameter:
3904: . dm - the DM

3906:   Output Parameters:
3907: + lmin - local minimum coordinates (length coord dim, optional)
3908: - lmax - local maximim coordinates (length coord dim, optional)

3910:   Level: beginner

3912:   Note: If the DM is a DMDA and has no coordinates, the index bounds are returned instead.


3915: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3916: @*/
3917: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3918: {
3919:   Vec                coords = NULL;
3920:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3921:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3922:   const PetscScalar *local_coords;
3923:   PetscInt           N, Ni;
3924:   PetscInt           cdim, i, j;
3925:   PetscErrorCode     ierr;

3929:   DMGetCoordinateDim(dm, &cdim);
3930:   DMGetCoordinates(dm, &coords);
3931:   if (coords) {
3932:     VecGetArrayRead(coords, &local_coords);
3933:     VecGetLocalSize(coords, &N);
3934:     Ni   = N/cdim;
3935:     for (i = 0; i < Ni; ++i) {
3936:       for (j = 0; j < 3; ++j) {
3937:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3938:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3939:       }
3940:     }
3941:     VecRestoreArrayRead(coords, &local_coords);
3942:   } else {
3943:     PetscBool isda;

3945:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3946:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3947:   }
3948:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
3949:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
3950:   return(0);
3951: }

3953: /*@
3954:   DMGetBoundingBox - Returns the global bounding box for the DM.

3956:   Collective

3958:   Input Parameter:
3959: . dm - the DM

3961:   Output Parameters:
3962: + gmin - global minimum coordinates (length coord dim, optional)
3963: - gmax - global maximim coordinates (length coord dim, optional)

3965:   Level: beginner

3967: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3968: @*/
3969: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3970: {
3971:   PetscReal      lmin[3], lmax[3];
3972:   PetscInt       cdim;
3973:   PetscMPIInt    count;

3978:   DMGetCoordinateDim(dm, &cdim);
3979:   PetscMPIIntCast(cdim, &count);
3980:   DMGetLocalBoundingBox(dm, lmin, lmax);
3981:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3982:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3983:   return(0);
3984: }

3986: /******************************** FEM Support **********************************/

3988: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3989: {
3990:   PetscInt       f;

3994:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3995:   for (f = 0; f < len; ++f) {
3996:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
3997:   }
3998:   return(0);
3999: }

4001: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4002: {
4003:   PetscInt       f, g;

4007:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4008:   for (f = 0; f < rows; ++f) {
4009:     PetscPrintf(PETSC_COMM_SELF, "  |");
4010:     for (g = 0; g < cols; ++g) {
4011:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4012:     }
4013:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4014:   }
4015:   return(0);
4016: }

4018: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4019: {
4020:   PetscInt          localSize, bs;
4021:   PetscMPIInt       size;
4022:   Vec               x, xglob;
4023:   const PetscScalar *xarray;
4024:   PetscErrorCode    ierr;

4027:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4028:   VecDuplicate(X, &x);
4029:   VecCopy(X, x);
4030:   VecChop(x, tol);
4031:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4032:   if (size > 1) {
4033:     VecGetLocalSize(x,&localSize);
4034:     VecGetArrayRead(x,&xarray);
4035:     VecGetBlockSize(x,&bs);
4036:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4037:   } else {
4038:     xglob = x;
4039:   }
4040:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4041:   if (size > 1) {
4042:     VecDestroy(&xglob);
4043:     VecRestoreArrayRead(x,&xarray);
4044:   }
4045:   VecDestroy(&x);
4046:   return(0);
4047: }

4049: /*@
4050:   DMGetSection - Get the PetscSection encoding the local data layout for the DM.   This is equivalent to DMGetLocalSection(). Deprecated in v3.12

4052:   Input Parameter:
4053: . dm - The DM

4055:   Output Parameter:
4056: . section - The PetscSection

4058:   Options Database Keys:
4059: . -dm_petscsection_view - View the Section created by the DM

4061:   Level: advanced

4063:   Notes:
4064:   Use DMGetLocalSection() in new code.

4066:   This gets a borrowed reference, so the user should not destroy this PetscSection.

4068: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4069: @*/
4070: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4071: {

4075:   DMGetLocalSection(dm,section);
4076:   return(0);
4077: }

4079: /*@
4080:   DMGetLocalSection - Get the PetscSection encoding the local data layout for the DM.

4082:   Input Parameter:
4083: . dm - The DM

4085:   Output Parameter:
4086: . section - The PetscSection

4088:   Options Database Keys:
4089: . -dm_petscsection_view - View the Section created by the DM

4091:   Level: intermediate

4093:   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.

4095: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4096: @*/
4097: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4098: {

4104:   if (!dm->localSection && dm->ops->createlocalsection) {
4105:     PetscInt d;

4107:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4108:     (*dm->ops->createlocalsection)(dm);
4109:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4110:   }
4111:   *section = dm->localSection;
4112:   return(0);
4113: }

4115: /*@
4116:   DMSetSection - Set the PetscSection encoding the local data layout for the DM.  This is equivalent to DMSetLocalSection(). Deprecated in v3.12

4118:   Input Parameters:
4119: + dm - The DM
4120: - section - The PetscSection

4122:   Level: advanced

4124:   Notes:
4125:   Use DMSetLocalSection() in new code.

4127:   Any existing Section will be destroyed

4129: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4130: @*/
4131: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4132: {

4136:   DMSetLocalSection(dm,section);
4137:   return(0);
4138: }

4140: /*@
4141:   DMSetLocalSection - Set the PetscSection encoding the local data layout for the DM.

4143:   Input Parameters:
4144: + dm - The DM
4145: - section - The PetscSection

4147:   Level: intermediate

4149:   Note: Any existing Section will be destroyed

4151: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4152: @*/
4153: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4154: {
4155:   PetscInt       numFields = 0;
4156:   PetscInt       f;

4162:   PetscObjectReference((PetscObject)section);
4163:   PetscSectionDestroy(&dm->localSection);
4164:   dm->localSection = section;
4165:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4166:   if (numFields) {
4167:     DMSetNumFields(dm, numFields);
4168:     for (f = 0; f < numFields; ++f) {
4169:       PetscObject disc;
4170:       const char *name;

4172:       PetscSectionGetFieldName(dm->localSection, f, &name);
4173:       DMGetField(dm, f, NULL, &disc);
4174:       PetscObjectSetName(disc, name);
4175:     }
4176:   }
4177:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4178:   PetscSectionDestroy(&dm->globalSection);
4179:   return(0);
4180: }

4182: /*@
4183:   DMGetDefaultConstraints - Get the PetscSection and Mat that specify the local constraint interpolation. See DMSetDefaultConstraints() for a description of the purpose of constraint interpolation.

4185:   not collective

4187:   Input Parameter:
4188: . dm - The DM

4190:   Output Parameter:
4191: + section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Returns NULL if there are no local constraints.
4192: - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section.  Returns NULL if there are no local constraints.

4194:   Level: advanced

4196:   Note: This gets borrowed references, so the user should not destroy the PetscSection or the Mat.

4198: .seealso: DMSetDefaultConstraints()
4199: @*/
4200: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4201: {

4206:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4207:   if (section) {*section = dm->defaultConstraintSection;}
4208:   if (mat) {*mat = dm->defaultConstraintMat;}
4209:   return(0);
4210: }

4212: /*@
4213:   DMSetDefaultConstraints - Set the PetscSection and Mat that specify the local constraint interpolation.

4215:   If a constraint matrix is specified, then it is applied during DMGlobalToLocalEnd() when mode is INSERT_VALUES, INSERT_BC_VALUES, or INSERT_ALL_VALUES.  Without a constraint matrix, the local vector l returned by DMGlobalToLocalEnd() contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l, l[s[i]] = c[i], where the scatter s is defined by the PetscSection returned by DMGetDefaultConstraintMatrix().

4217:   If a constraint matrix is specified, then its adjoint is applied during DMLocalToGlobalBegin() when mode is ADD_VALUES, ADD_BC_VALUES, or ADD_ALL_VALUES.  Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above.

4219:   collective on dm

4221:   Input Parameters:
4222: + dm - The DM
4223: + section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (PETSC_COMM_SELF or derivative).
4224: - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section:  NULL indicates no constraints.  Must have a local communicator (PETSC_COMM_SELF or derivative).

4226:   Level: advanced

4228:   Note: This increments the references of the PetscSection and the Mat, so they user can destroy them

4230: .seealso: DMGetDefaultConstraints()
4231: @*/
4232: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4233: {
4234:   PetscMPIInt result;

4239:   if (section) {
4241:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4242:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4243:   }
4244:   if (mat) {
4246:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4247:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4248:   }
4249:   PetscObjectReference((PetscObject)section);
4250:   PetscSectionDestroy(&dm->defaultConstraintSection);
4251:   dm->defaultConstraintSection = section;
4252:   PetscObjectReference((PetscObject)mat);
4253:   MatDestroy(&dm->defaultConstraintMat);
4254:   dm->defaultConstraintMat = mat;
4255:   return(0);
4256: }

4258: #if defined(PETSC_USE_DEBUG)
4259: /*
4260:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4262:   Input Parameters:
4263: + dm - The DM
4264: . localSection - PetscSection describing the local data layout
4265: - globalSection - PetscSection describing the global data layout

4267:   Level: intermediate

4269: .seealso: DMGetSectionSF(), DMSetSectionSF()
4270: */
4271: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4272: {
4273:   MPI_Comm        comm;
4274:   PetscLayout     layout;
4275:   const PetscInt *ranges;
4276:   PetscInt        pStart, pEnd, p, nroots;
4277:   PetscMPIInt     size, rank;
4278:   PetscBool       valid = PETSC_TRUE, gvalid;
4279:   PetscErrorCode  ierr;

4282:   PetscObjectGetComm((PetscObject)dm,&comm);
4284:   MPI_Comm_size(comm, &size);
4285:   MPI_Comm_rank(comm, &rank);
4286:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4287:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4288:   PetscLayoutCreate(comm, &layout);
4289:   PetscLayoutSetBlockSize(layout, 1);
4290:   PetscLayoutSetLocalSize(layout, nroots);
4291:   PetscLayoutSetUp(layout);
4292:   PetscLayoutGetRanges(layout, &ranges);
4293:   for (p = pStart; p < pEnd; ++p) {
4294:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4296:     PetscSectionGetDof(localSection, p, &dof);
4297:     PetscSectionGetOffset(localSection, p, &off);
4298:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4299:     PetscSectionGetDof(globalSection, p, &gdof);
4300:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4301:     PetscSectionGetOffset(globalSection, p, &goff);
4302:     if (!gdof) continue; /* Censored point */
4303:     if ((gdof < 0 ? -(gdof+1) : gdof) != dof) {PetscSynchronizedPrintf(comm, "[%d]Global dof %d for point %d not equal to local dof %d\n", rank, gdof, p, dof); valid = PETSC_FALSE;}
4304:     if (gcdof && (gcdof != cdof)) {PetscSynchronizedPrintf(comm, "[%d]Global constraints %d for point %d not equal to local constraints %d\n", rank, gcdof, p, cdof); valid = PETSC_FALSE;}
4305:     if (gdof < 0) {
4306:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4307:       for (d = 0; d < gsize; ++d) {
4308:         PetscInt offset = -(goff+1) + d, r;

4310:         PetscFindInt(offset,size+1,ranges,&r);
4311:         if (r < 0) r = -(r+2);
4312:         if ((r < 0) || (r >= size)) {PetscSynchronizedPrintf(comm, "[%d]Point %d mapped to invalid process %d (%d, %d)\n", rank, p, r, gdof, goff); valid = PETSC_FALSE;break;}
4313:       }
4314:     }
4315:   }
4316:   PetscLayoutDestroy(&layout);
4317:   PetscSynchronizedFlush(comm, NULL);
4318:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4319:   if (!gvalid) {
4320:     DMView(dm, NULL);
4321:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4322:   }
4323:   return(0);
4324: }
4325: #endif

4327: /*@
4328:   DMGetGlobalSection - Get the PetscSection encoding the global data layout for the DM.

4330:   Collective on dm

4332:   Input Parameter:
4333: . dm - The DM

4335:   Output Parameter:
4336: . section - The PetscSection

4338:   Level: intermediate

4340:   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.

4342: .seealso: DMSetLocalSection(), DMGetLocalSection()
4343: @*/
4344: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4345: {

4351:   if (!dm->globalSection) {
4352:     PetscSection s;

4354:     DMGetLocalSection(dm, &s);
4355:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4356:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4357:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4358:     PetscLayoutDestroy(&dm->map);
4359:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4360:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4361:   }
4362:   *section = dm->globalSection;
4363:   return(0);
4364: }

4366: /*@
4367:   DMSetGlobalSection - Set the PetscSection encoding the global data layout for the DM.

4369:   Input Parameters:
4370: + dm - The DM
4371: - section - The PetscSection, or NULL

4373:   Level: intermediate

4375:   Note: Any existing Section will be destroyed

4377: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4378: @*/
4379: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4380: {

4386:   PetscObjectReference((PetscObject)section);
4387:   PetscSectionDestroy(&dm->globalSection);
4388:   dm->globalSection = section;
4389: #if defined(PETSC_USE_DEBUG)
4390:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4391: #endif
4392:   return(0);
4393: }

4395: /*@
4396:   DMGetSectionSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
4397:   it is created from the default PetscSection layouts in the DM.

4399:   Input Parameter:
4400: . dm - The DM

4402:   Output Parameter:
4403: . sf - The PetscSF

4405:   Level: intermediate

4407:   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.

4409: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4410: @*/
4411: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4412: {
4413:   PetscInt       nroots;

4419:   if (!dm->sectionSF) {
4420:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4421:   }
4422:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4423:   if (nroots < 0) {
4424:     PetscSection section, gSection;

4426:     DMGetLocalSection(dm, &section);
4427:     if (section) {
4428:       DMGetGlobalSection(dm, &gSection);
4429:       DMCreateSectionSF(dm, section, gSection);
4430:     } else {
4431:       *sf = NULL;
4432:       return(0);
4433:     }
4434:   }
4435:   *sf = dm->sectionSF;
4436:   return(0);
4437: }

4439: /*@
4440:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4442:   Input Parameters:
4443: + dm - The DM
4444: - sf - The PetscSF

4446:   Level: intermediate

4448:   Note: Any previous SF is destroyed

4450: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4451: @*/
4452: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4453: {

4459:   PetscObjectReference((PetscObject) sf);
4460:   PetscSFDestroy(&dm->sectionSF);
4461:   dm->sectionSF = sf;
4462:   return(0);
4463: }

4465: /*@C
4466:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4467:   describing the data layout.

4469:   Input Parameters:
4470: + dm - The DM
4471: . localSection - PetscSection describing the local data layout
4472: - globalSection - PetscSection describing the global data layout

4474:   Notes: One usually uses DMGetSectionSF() to obtain the PetscSF

4476:   Level: developer

4478:   Developer Note: Since this routine has for arguments the two sections from the DM and puts the resulting PetscSF
4479:                   directly into the DM, perhaps this function should not take the local and global sections as
4480:                   input and should just obtain them from the DM?

4482: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4483: @*/
4484: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4485: {
4486:   MPI_Comm       comm;
4487:   PetscLayout    layout;
4488:   const PetscInt *ranges;
4489:   PetscInt       *local;
4490:   PetscSFNode    *remote;
4491:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4492:   PetscMPIInt    size, rank;

4497:   PetscObjectGetComm((PetscObject)dm,&comm);
4498:   MPI_Comm_size(comm, &size);
4499:   MPI_Comm_rank(comm, &rank);
4500:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4501:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4502:   PetscLayoutCreate(comm, &layout);
4503:   PetscLayoutSetBlockSize(layout, 1);
4504:   PetscLayoutSetLocalSize(layout, nroots);
4505:   PetscLayoutSetUp(layout);
4506:   PetscLayoutGetRanges(layout, &ranges);
4507:   for (p = pStart; p < pEnd; ++p) {
4508:     PetscInt gdof, gcdof;

4510:     PetscSectionGetDof(globalSection, p, &gdof);
4511:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4512:     if (gcdof > (gdof < 0 ? -(gdof+1) : gdof)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d has %d constraints > %d dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
4513:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4514:   }
4515:   PetscMalloc1(nleaves, &local);
4516:   PetscMalloc1(nleaves, &remote);
4517:   for (p = pStart, l = 0; p < pEnd; ++p) {
4518:     const PetscInt *cind;
4519:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4521:     PetscSectionGetDof(localSection, p, &dof);
4522:     PetscSectionGetOffset(localSection, p, &off);
4523:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4524:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4525:     PetscSectionGetDof(globalSection, p, &gdof);
4526:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4527:     PetscSectionGetOffset(globalSection, p, &goff);
4528:     if (!gdof) continue; /* Censored point */
4529:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4530:     if (gsize != dof-cdof) {
4531:       if (gsize != dof) SETERRQ4(comm, PETSC_ERR_ARG_WRONG, "Global dof %d for point %d is neither the constrained size %d, nor the unconstrained %d", gsize, p, dof-cdof, dof);
4532:       cdof = 0; /* Ignore constraints */
4533:     }
4534:     for (d = 0, c = 0; d < dof; ++d) {
4535:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4536:       local[l+d-c] = off+d;
4537:     }
4538:     if (gdof < 0) {
4539:       for (d = 0; d < gsize; ++d, ++l) {
4540:         PetscInt offset = -(goff+1) + d, r;

4542:         PetscFindInt(offset,size+1,ranges,&r);
4543:         if (r < 0) r = -(r+2);
4544:         if ((r < 0) || (r >= size)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d mapped to invalid process %d (%d, %d)", p, r, gdof, goff);
4545:         remote[l].rank  = r;
4546:         remote[l].index = offset - ranges[r];
4547:       }
4548:     } else {
4549:       for (d = 0; d < gsize; ++d, ++l) {
4550:         remote[l].rank  = rank;
4551:         remote[l].index = goff+d - ranges[rank];
4552:       }
4553:     }
4554:   }
4555:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4556:   PetscLayoutDestroy(&layout);
4557:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4558:   return(0);
4559: }

4561: /*@
4562:   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.

4564:   Input Parameter:
4565: . dm - The DM

4567:   Output Parameter:
4568: . sf - The PetscSF

4570:   Level: intermediate

4572:   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.

4574: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4575: @*/
4576: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4577: {
4581:   *sf = dm->sf;
4582:   return(0);
4583: }

4585: /*@
4586:   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.

4588:   Input Parameters:
4589: + dm - The DM
4590: - sf - The PetscSF

4592:   Level: intermediate

4594: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4595: @*/
4596: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4597: {

4603:   PetscObjectReference((PetscObject) sf);
4604:   PetscSFDestroy(&dm->sf);
4605:   dm->sf = sf;
4606:   return(0);
4607: }

4609: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4610: {
4611:   PetscClassId   id;

4615:   PetscObjectGetClassId(disc, &id);
4616:   if (id == PETSCFE_CLASSID) {
4617:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4618:   } else if (id == PETSCFV_CLASSID) {
4619:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4620:   } else {
4621:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4622:   }
4623:   return(0);
4624: }

4626: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4627: {
4628:   RegionField   *tmpr;
4629:   PetscInt       Nf = dm->Nf, f;

4633:   if (Nf >= NfNew) return(0);
4634:   PetscMalloc1(NfNew, &tmpr);
4635:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4636:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4637:   PetscFree(dm->fields);
4638:   dm->Nf     = NfNew;
4639:   dm->fields = tmpr;
4640:   return(0);
4641: }

4643: /*@
4644:   DMClearFields - Remove all fields from the DM

4646:   Logically collective on dm

4648:   Input Parameter:
4649: . dm - The DM

4651:   Level: intermediate

4653: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4654: @*/
4655: PetscErrorCode DMClearFields(DM dm)
4656: {
4657:   PetscInt       f;

4662:   for (f = 0; f < dm->Nf; ++f) {
4663:     PetscObjectDestroy(&dm->fields[f].disc);
4664:     DMLabelDestroy(&dm->fields[f].label);
4665:   }
4666:   PetscFree(dm->fields);
4667:   dm->fields = NULL;
4668:   dm->Nf     = 0;
4669:   return(0);
4670: }

4672: /*@
4673:   DMGetNumFields - Get the number of fields in the DM

4675:   Not collective

4677:   Input Parameter:
4678: . dm - The DM

4680:   Output Parameter:
4681: . Nf - The number of fields

4683:   Level: intermediate

4685: .seealso: DMSetNumFields(), DMSetField()
4686: @*/
4687: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4688: {
4692:   *numFields = dm->Nf;
4693:   return(0);
4694: }

4696: /*@
4697:   DMSetNumFields - Set the number of fields in the DM

4699:   Logically collective on dm

4701:   Input Parameters:
4702: + dm - The DM
4703: - Nf - The number of fields

4705:   Level: intermediate

4707: .seealso: DMGetNumFields(), DMSetField()
4708: @*/
4709: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4710: {
4711:   PetscInt       Nf, f;

4716:   DMGetNumFields(dm, &Nf);
4717:   for (f = Nf; f < numFields; ++f) {
4718:     PetscContainer obj;

4720:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4721:     DMAddField(dm, NULL, (PetscObject) obj);
4722:     PetscContainerDestroy(&obj);
4723:   }
4724:   return(0);
4725: }

4727: /*@
4728:   DMGetField - Return the discretization object for a given DM field

4730:   Not collective

4732:   Input Parameters:
4733: + dm - The DM
4734: - f  - The field number

4736:   Output Parameters:
4737: + label - The label indicating the support of the field, or NULL for the entire mesh
4738: - field - The discretization object

4740:   Level: intermediate

4742: .seealso: DMAddField(), DMSetField()
4743: @*/
4744: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4745: {
4749:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, dm->Nf);
4750:   if (label) *label = dm->fields[f].label;
4751:   if (field) *field = dm->fields[f].disc;
4752:   return(0);
4753: }

4755: /* Does not clear the DS */
4756: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4757: {

4761:   DMFieldEnlarge_Static(dm, f+1);
4762:   DMLabelDestroy(&dm->fields[f].label);
4763:   PetscObjectDestroy(&dm->fields[f].disc);
4764:   dm->fields[f].label = label;
4765:   dm->fields[f].disc  = field;
4766:   PetscObjectReference((PetscObject) label);
4767:   PetscObjectReference((PetscObject) field);
4768:   return(0);
4769: }

4771: /*@
4772:   DMSetField - Set the discretization object for a given DM field

4774:   Logically collective on dm

4776:   Input Parameters:
4777: + dm    - The DM
4778: . f     - The field number
4779: . label - The label indicating the support of the field, or NULL for the entire mesh
4780: - field - The discretization object

4782:   Level: intermediate

4784: .seealso: DMAddField(), DMGetField()
4785: @*/
4786: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4787: {

4794:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4795:   DMSetField_Internal(dm, f, label, field);
4796:   DMSetDefaultAdjacency_Private(dm, f, field);
4797:   DMClearDS(dm);
4798:   return(0);
4799: }

4801: /*@
4802:   DMAddField - Add the discretization object for the given DM field

4804:   Logically collective on dm

4806:   Input Parameters:
4807: + dm    - The DM
4808: . label - The label indicating the support of the field, or NULL for the entire mesh
4809: - field - The discretization object

4811:   Level: intermediate

4813: .seealso: DMSetField(), DMGetField()
4814: @*/
4815: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4816: {
4817:   PetscInt       Nf = dm->Nf;

4824:   DMFieldEnlarge_Static(dm, Nf+1);
4825:   dm->fields[Nf].label = label;
4826:   dm->fields[Nf].disc  = field;
4827:   PetscObjectReference((PetscObject) label);
4828:   PetscObjectReference((PetscObject) field);
4829:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4830:   DMClearDS(dm);
4831:   return(0);
4832: }

4834: /*@
4835:   DMCopyFields - Copy the discretizations for the DM into another DM

4837:   Collective on dm

4839:   Input Parameter:
4840: . dm - The DM

4842:   Output Parameter:
4843: . newdm - The DM

4845:   Level: advanced

4847: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4848: @*/
4849: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4850: {
4851:   PetscInt       Nf, f;

4855:   if (dm == newdm) return(0);
4856:   DMGetNumFields(dm, &Nf);
4857:   DMClearFields(newdm);
4858:   for (f = 0; f < Nf; ++f) {
4859:     DMLabel     label;
4860:     PetscObject field;
4861:     PetscBool   useCone, useClosure;

4863:     DMGetField(dm, f, &label, &field);
4864:     DMSetField(newdm, f, label, field);
4865:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4866:     DMSetAdjacency(newdm, f, useCone, useClosure);
4867:   }
4868:   return(0);
4869: }

4871: /*@
4872:   DMGetAdjacency - Returns the flags for determining variable influence

4874:   Not collective

4876:   Input Parameters:
4877: + dm - The DM object
4878: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4880:   Output Parameter:
4881: + useCone    - Flag for variable influence starting with the cone operation
4882: - useClosure - Flag for variable influence using transitive closure

4884:   Notes:
4885: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4886: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4887: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4888:   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.

4890:   Level: developer

4892: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4893: @*/
4894: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4895: {
4900:   if (f < 0) {
4901:     if (useCone)    *useCone    = dm->adjacency[0];
4902:     if (useClosure) *useClosure = dm->adjacency[1];
4903:   } else {
4904:     PetscInt       Nf;

4907:     DMGetNumFields(dm, &Nf);
4908:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4909:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4910:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4911:   }
4912:   return(0);
4913: }

4915: /*@
4916:   DMSetAdjacency - Set the flags for determining variable influence

4918:   Not collective

4920:   Input Parameters:
4921: + dm         - The DM object
4922: . f          - The field number
4923: . useCone    - Flag for variable influence starting with the cone operation
4924: - useClosure - Flag for variable influence using transitive closure

4926:   Notes:
4927: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4928: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4929: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4930:   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.

4932:   Level: developer

4934: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4935: @*/
4936: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4937: {
4940:   if (f < 0) {
4941:     dm->adjacency[0] = useCone;
4942:     dm->adjacency[1] = useClosure;
4943:   } else {
4944:     PetscInt       Nf;

4947:     DMGetNumFields(dm, &Nf);
4948:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4949:     dm->fields[f].adjacency[0] = useCone;
4950:     dm->fields[f].adjacency[1] = useClosure;
4951:   }
4952:   return(0);
4953: }

4955: /*@
4956:   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined

4958:   Not collective

4960:   Input Parameters:
4961: . dm - The DM object

4963:   Output Parameter:
4964: + useCone    - Flag for variable influence starting with the cone operation
4965: - useClosure - Flag for variable influence using transitive closure

4967:   Notes:
4968: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4969: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4970: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4972:   Level: developer

4974: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4975: @*/
4976: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4977: {
4978:   PetscInt       Nf;

4985:   DMGetNumFields(dm, &Nf);
4986:   if (!Nf) {
4987:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4988:   } else {
4989:     DMGetAdjacency(dm, 0, useCone, useClosure);
4990:   }
4991:   return(0);
4992: }

4994: /*@
4995:   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined

4997:   Not collective

4999:   Input Parameters:
5000: + dm         - The DM object
5001: . useCone    - Flag for variable influence starting with the cone operation
5002: - useClosure - Flag for variable influence using transitive closure

5004:   Notes:
5005: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5006: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5007: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5009:   Level: developer

5011: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5012: @*/
5013: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5014: {
5015:   PetscInt       Nf;

5020:   DMGetNumFields(dm, &Nf);
5021:   if (!Nf) {
5022:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5023:   } else {
5024:     DMSetAdjacency(dm, 0, useCone, useClosure);
5025:   }
5026:   return(0);
5027: }

5029: /* Complete labels that are being used for FEM BC */
5030: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5031: {
5032:   DMLabel        label;
5033:   PetscObject    obj;
5034:   PetscClassId   id;
5035:   PetscInt       Nbd, bd;
5036:   PetscBool      isFE      = PETSC_FALSE;
5037:   PetscBool      duplicate = PETSC_FALSE;

5041:   DMGetField(dm, field, NULL, &obj);
5042:   PetscObjectGetClassId(obj, &id);
5043:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5044:   DMGetLabel(dm, labelname, &label);
5045:   if (isFE && label) {
5046:     /* Only want to modify label once */
5047:     PetscDSGetNumBoundary(ds, &Nbd);
5048:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5049:       const char *lname;

5051:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5052:       PetscStrcmp(lname, labelname, &duplicate);
5053:       if (duplicate) break;
5054:     }
5055:     if (!duplicate) {
5056:       DM plex;

5058:       DMConvert(dm, DMPLEX, &plex);
5059:       if (plex) {DMPlexLabelComplete(plex, label);}
5060:       DMDestroy(&plex);
5061:     }
5062:   }
5063:   return(0);
5064: }

5066: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5067: {
5068:   DMSpace       *tmpd;
5069:   PetscInt       Nds = dm->Nds, s;

5073:   if (Nds >= NdsNew) return(0);
5074:   PetscMalloc1(NdsNew, &tmpd);
5075:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5076:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5077:   PetscFree(dm->probs);
5078:   dm->Nds   = NdsNew;
5079:   dm->probs = tmpd;
5080:   return(0);
5081: }

5083: /*@
5084:   DMGetNumDS - Get the number of discrete systems in the DM

5086:   Not collective

5088:   Input Parameter:
5089: . dm - The DM

5091:   Output Parameter:
5092: . Nds - The number of PetscDS objects

5094:   Level: intermediate

5096: .seealso: DMGetDS(), DMGetCellDS()
5097: @*/
5098: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5099: {
5103:   *Nds = dm->Nds;
5104:   return(0);
5105: }

5107: /*@
5108:   DMClearDS - Remove all discrete systems from the DM

5110:   Logically collective on dm

5112:   Input Parameter:
5113: . dm - The DM

5115:   Level: intermediate

5117: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5118: @*/
5119: PetscErrorCode DMClearDS(DM dm)
5120: {
5121:   PetscInt       s;

5126:   for (s = 0; s < dm->Nds; ++s) {
5127:     PetscDSDestroy(&dm->probs[s].ds);
5128:     DMLabelDestroy(&dm->probs[s].label);
5129:     ISDestroy(&dm->probs[s].fields);
5130:   }
5131:   PetscFree(dm->probs);
5132:   dm->probs = NULL;
5133:   dm->Nds   = 0;
5134:   return(0);
5135: }

5137: /*@
5138:   DMGetDS - Get the default PetscDS

5140:   Not collective

5142:   Input Parameter:
5143: . dm    - The DM

5145:   Output Parameter:
5146: . prob - The default PetscDS

5148:   Level: intermediate

5150: .seealso: DMGetCellDS(), DMGetRegionDS()
5151: @*/
5152: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5153: {

5159:   if (dm->Nds <= 0) {
5160:     PetscDS ds;

5162:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5163:     DMSetRegionDS(dm, NULL, NULL, ds);
5164:     PetscDSDestroy(&ds);
5165:   }
5166:   *prob = dm->probs[0].ds;
5167:   return(0);
5168: }

5170: /*@
5171:   DMGetCellDS - Get the PetscDS defined on a given cell

5173:   Not collective

5175:   Input Parameters:
5176: + dm    - The DM
5177: - point - Cell for the DS

5179:   Output Parameter:
5180: . prob - The PetscDS defined on the given cell

5182:   Level: developer

5184: .seealso: DMGetDS(), DMSetRegionDS()
5185: @*/
5186: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5187: {
5188:   PetscDS        probDef = NULL;
5189:   PetscInt       s;

5195:   if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5196:   *prob = NULL;
5197:   for (s = 0; s < dm->Nds; ++s) {
5198:     PetscInt val;

5200:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5201:     else {
5202:       DMLabelGetValue(dm->probs[s].label, point, &val);
5203:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5204:     }
5205:   }
5206:   if (!*prob) *prob = probDef;
5207:   return(0);
5208: }

5210: /*@
5211:   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel

5213:   Not collective

5215:   Input Parameters:
5216: + dm    - The DM
5217: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

5219:   Output Parameters:
5220: + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5221: - prob - The PetscDS defined on the given region, or NULL

5223:   Note: If the label is missing, this function returns an error

5225:   Level: advanced

5227: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5228: @*/
5229: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5230: {
5231:   PetscInt Nds = dm->Nds, s;

5238:   for (s = 0; s < Nds; ++s) {
5239:     if (dm->probs[s].label == label) {
5240:       if (fields) *fields = dm->probs[s].fields;
5241:       if (ds)     *ds     = dm->probs[s].ds;
5242:       return(0);
5243:     }
5244:   }
5245:   return(0);
5246: }

5248: /*@
5249:   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel

5251:   Collective on dm

5253:   Input Parameters:
5254: + dm     - The DM
5255: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5256: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5257: - prob   - The PetscDS defined on the given cell

5259:   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5260:   the fields argument is ignored.

5262:   Level: advanced

5264: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5265: @*/
5266: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5267: {
5268:   PetscInt       Nds = dm->Nds, s;

5275:   for (s = 0; s < Nds; ++s) {
5276:     if (dm->probs[s].label == label) {
5277:       PetscDSDestroy(&dm->probs[s].ds);
5278:       dm->probs[s].ds = ds;
5279:       return(0);
5280:     }
5281:   }
5282:   DMDSEnlarge_Static(dm, Nds+1);
5283:   PetscObjectReference((PetscObject) label);
5284:   PetscObjectReference((PetscObject) fields);
5285:   PetscObjectReference((PetscObject) ds);
5286:   if (!label) {
5287:     /* Put the NULL label at the front, so it is returned as the default */
5288:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5289:     Nds = 0;
5290:   }
5291:   dm->probs[Nds].label  = label;
5292:   dm->probs[Nds].fields = fields;
5293:   dm->probs[Nds].ds     = ds;
5294:   return(0);
5295: }

5297: /*@
5298:   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number

5300:   Not collective

5302:   Input Parameters:
5303: + dm  - The DM
5304: - num - The region number, in [0, Nds)

5306:   Output Parameters:
5307: + label  - The region label, or NULL
5308: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5309: - ds     - The PetscDS defined on the given region, or NULL

5311:   Level: advanced

5313: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5314: @*/
5315: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5316: {
5317:   PetscInt       Nds;

5322:   DMGetNumDS(dm, &Nds);
5323:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5324:   if (label) {
5326:     *label = dm->probs[num].label;
5327:   }
5328:   if (fields) {
5330:     *fields = dm->probs[num].fields;
5331:   }
5332:   if (ds) {
5334:     *ds = dm->probs[num].ds;
5335:   }
5336:   return(0);
5337: }

5339: /*@
5340:   DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number

5342:   Not collective

5344:   Input Parameters:
5345: + dm     - The DM
5346: . num    - The region number, in [0, Nds)
5347: . label  - The region label, or NULL
5348: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5349: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5351:   Level: advanced

5353: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5354: @*/
5355: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5356: {
5357:   PetscInt       Nds;

5363:   DMGetNumDS(dm, &Nds);
5364:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5365:   PetscObjectReference((PetscObject) label);
5366:   DMLabelDestroy(&dm->probs[num].label);
5367:   dm->probs[num].label = label;
5368:   if (fields) {
5370:     PetscObjectReference((PetscObject) fields);
5371:     ISDestroy(&dm->probs[num].fields);
5372:     dm->probs[num].fields = fields;
5373:   }
5374:   if (ds) {
5376:     PetscObjectReference((PetscObject) ds);
5377:     PetscDSDestroy(&dm->probs[num].ds);
5378:     dm->probs[num].ds = ds;
5379:   }
5380:   return(0);
5381: }

5383: /*@
5384:   DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.

5386:   Not collective

5388:   Input Parameters:
5389: + dm  - The DM
5390: - ds  - The PetscDS defined on the given region

5392:   Output Parameter:
5393: . num - The region number, in [0, Nds), or -1 if not found

5395:   Level: advanced

5397: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5398: @*/
5399: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5400: {
5401:   PetscInt       Nds, n;

5408:   DMGetNumDS(dm, &Nds);
5409:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5410:   if (n >= Nds) *num = -1;
5411:   else          *num = n;
5412:   return(0);
5413: }

5415: /*@
5416:   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM

5418:   Collective on dm

5420:   Input Parameter:
5421: . dm - The DM

5423:   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.

5425:   Level: intermediate

5427: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5428: @*/
5429: PetscErrorCode DMCreateDS(DM dm)
5430: {
5431:   MPI_Comm       comm;
5432:   PetscDS        dsDef;
5433:   DMLabel       *labelSet;
5434:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5435:   PetscBool      doSetup = PETSC_TRUE;

5440:   if (!dm->fields) return(0);
5441:   PetscObjectGetComm((PetscObject) dm, &comm);
5442:   DMGetCoordinateDim(dm, &dE);
5443:   /* Determine how many regions we have */
5444:   PetscMalloc1(Nf, &labelSet);
5445:   Nl   = 0;
5446:   Ndef = 0;
5447:   for (f = 0; f < Nf; ++f) {
5448:     DMLabel  label = dm->fields[f].label;
5449:     PetscInt l;

5451:     if (!label) {++Ndef; continue;}
5452:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5453:     if (l < Nl) continue;
5454:     labelSet[Nl++] = label;
5455:   }
5456:   /* Create default DS if there are no labels to intersect with */
5457:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5458:   if (!dsDef && Ndef && !Nl) {
5459:     IS        fields;
5460:     PetscInt *fld, nf;

5462:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5463:     if (nf) {
5464:       PetscMalloc1(nf, &fld);
5465:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5466:       ISCreate(PETSC_COMM_SELF, &fields);
5467:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5468:       ISSetType(fields, ISGENERAL);
5469:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5471:       PetscDSCreate(comm, &dsDef);
5472:       DMSetRegionDS(dm, NULL, fields, dsDef);
5473:       PetscDSDestroy(&dsDef);
5474:       ISDestroy(&fields);
5475:     }
5476:   }
5477:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5478:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5479:   /* Intersect labels with default fields */
5480:   if (Ndef && Nl) {
5481:     DM              plex;
5482:     DMLabel         cellLabel;
5483:     IS              fieldIS, allcellIS, defcellIS = NULL;
5484:     PetscInt       *fields;
5485:     const PetscInt *cells;
5486:     PetscInt        depth, nf = 0, n, c;

5488:     DMConvert(dm, DMPLEX, &plex);
5489:     DMPlexGetDepth(plex, &depth);
5490:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5491:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5492:     for (l = 0; l < Nl; ++l) {
5493:       DMLabel label = labelSet[l];
5494:       IS      pointIS;

5496:       ISDestroy(&defcellIS);
5497:       DMLabelGetStratumIS(label, 1, &pointIS);
5498:       ISDifference(allcellIS, pointIS, &defcellIS);
5499:       ISDestroy(&pointIS);
5500:     }
5501:     ISDestroy(&allcellIS);

5503:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5504:     ISGetLocalSize(defcellIS, &n);
5505:     ISGetIndices(defcellIS, &cells);
5506:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5507:     ISRestoreIndices(defcellIS, &cells);
5508:     ISDestroy(&defcellIS);
5509:     DMPlexLabelComplete(plex, cellLabel);

5511:     PetscMalloc1(Ndef, &fields);
5512:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5513:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5514:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5515:     ISSetType(fieldIS, ISGENERAL);
5516:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5518:     PetscDSCreate(comm, &dsDef);
5519:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5520:     DMLabelDestroy(&cellLabel);
5521:     PetscDSSetCoordinateDimension(dsDef, dE);
5522:     PetscDSDestroy(&dsDef);
5523:     ISDestroy(&fieldIS);
5524:     DMDestroy(&plex);
5525:   }
5526:   /* Create label DSes
5527:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5528:   */
5529:   /* TODO Should check that labels are disjoint */
5530:   for (l = 0; l < Nl; ++l) {
5531:     DMLabel   label = labelSet[l];
5532:     PetscDS   ds;
5533:     IS        fields;
5534:     PetscInt *fld, nf;

5536:     PetscDSCreate(comm, &ds);
5537:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5538:     PetscMalloc1(nf, &fld);
5539:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5540:     ISCreate(PETSC_COMM_SELF, &fields);
5541:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5542:     ISSetType(fields, ISGENERAL);
5543:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5544:     DMSetRegionDS(dm, label, fields, ds);
5545:     ISDestroy(&fields);
5546:     PetscDSSetCoordinateDimension(ds, dE);
5547:     {
5548:       DMPolytopeType ct;
5549:       PetscInt       lStart, lEnd;
5550:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5552:       DMLabelGetBounds(label, &lStart, &lEnd);
5553:       if (lStart >= 0) {
5554:         DMPlexGetCellType(dm, lStart, &ct);
5555:         switch (ct) {
5556:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5557:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5558:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5559:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5560:             isHybridLocal = PETSC_TRUE;break;
5561:           default: break;
5562:         }
5563:       }
5564:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5565:       PetscDSSetHybrid(ds, isHybrid);
5566:     }
5567:     PetscDSDestroy(&ds);
5568:   }
5569:   PetscFree(labelSet);
5570:   /* Set fields in DSes */
5571:   for (s = 0; s < dm->Nds; ++s) {
5572:     PetscDS         ds     = dm->probs[s].ds;
5573:     IS              fields = dm->probs[s].fields;
5574:     const PetscInt *fld;
5575:     PetscInt        nf;

5577:     ISGetLocalSize(fields, &nf);
5578:     ISGetIndices(fields, &fld);
5579:     for (f = 0; f < nf; ++f) {
5580:       PetscObject  disc  = dm->fields[fld[f]].disc;
5581:       PetscBool    isHybrid;
5582:       PetscClassId id;

5584:       PetscDSGetHybrid(ds, &isHybrid);
5585:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5586:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5587:       PetscDSSetDiscretization(ds, f, disc);
5588:       /* We allow people to have placeholder fields and construct the Section by hand */
5589:       PetscObjectGetClassId(disc, &id);
5590:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5591:     }
5592:     ISRestoreIndices(fields, &fld);
5593:   }
5594:   /* Setup DSes */
5595:   if (doSetup) {
5596:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5597:   }
5598:   return(0);
5599: }

5601: /*@
5602:   DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.

5604:   Collective on DM

5606:   Input Parameters:
5607: + dm   - The DM
5608: - time - The time

5610:   Output Parameters:
5611: + u    - The vector will be filled with exact solution values, or NULL
5612: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5614:   Note: The user must call PetscDSSetExactSolution() beforehand

5616:   Level: developer

5618: .seealso: PetscDSSetExactSolution()
5619: @*/
5620: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5621: {
5622:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5623:   void            **ectxs;
5624:   PetscInt          Nf, Nds, s;
5625:   PetscErrorCode    ierr;

5631:   DMGetNumFields(dm, &Nf);
5632:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5633:   DMGetNumDS(dm, &Nds);
5634:   for (s = 0; s < Nds; ++s) {
5635:     PetscDS         ds;
5636:     DMLabel         label;
5637:     IS              fieldIS;
5638:     const PetscInt *fields, id = 1;
5639:     PetscInt        dsNf, f;

5641:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5642:     PetscDSGetNumFields(ds, &dsNf);
5643:     ISGetIndices(fieldIS, &fields);
5644:     PetscArrayzero(exacts, Nf);
5645:     PetscArrayzero(ectxs, Nf);
5646:     if (u) {
5647:       for (f = 0; f < dsNf; ++f) {
5648:         const PetscInt field = fields[f];
5649:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5650:       }
5651:       ISRestoreIndices(fieldIS, &fields);
5652:       if (label) {
5653:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5654:       } else {
5655:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5656:       }
5657:     }
5658:     if (u_t) {
5659:       PetscArrayzero(exacts, Nf);
5660:       PetscArrayzero(ectxs, Nf);
5661:       for (f = 0; f < dsNf; ++f) {
5662:         const PetscInt field = fields[f];
5663:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5664:       }
5665:       ISRestoreIndices(fieldIS, &fields);
5666:       if (label) {
5667:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5668:       } else {
5669:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5670:       }
5671:     }
5672:   }
5673:   if (u) {
5674:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5675:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5676:   }
5677:   if (u_t) {
5678:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5679:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5680:   }
5681:   PetscFree2(exacts, ectxs);
5682:   return(0);
5683: }

5685: /*@
5686:   DMCopyDS - Copy the discrete systems for the DM into another DM

5688:   Collective on dm

5690:   Input Parameter:
5691: . dm - The DM

5693:   Output Parameter:
5694: . newdm - The DM

5696:   Level: advanced

5698: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5699: @*/
5700: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5701: {
5702:   PetscInt       Nds, s;

5706:   if (dm == newdm) return(0);
5707:   DMGetNumDS(dm, &Nds);
5708:   DMClearDS(newdm);
5709:   for (s = 0; s < Nds; ++s) {
5710:     DMLabel  label;
5711:     IS       fields;
5712:     PetscDS  ds;
5713:     PetscInt Nbd, bd;

5715:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5716:     DMSetRegionDS(newdm, label, fields, ds);
5717:     PetscDSGetNumBoundary(ds, &Nbd);
5718:     for (bd = 0; bd < Nbd; ++bd) {
5719:       const char *labelname, *name;
5720:       PetscInt    field;

5722:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5723:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5724:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5725:     }
5726:   }
5727:   return(0);
5728: }

5730: /*@
5731:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

5733:   Collective on dm

5735:   Input Parameter:
5736: . dm - The DM

5738:   Output Parameter:
5739: . newdm - The DM

5741:   Level: advanced

5743: .seealso: DMCopyFields(), DMCopyDS()
5744: @*/
5745: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5746: {

5750:   DMCopyFields(dm, newdm);
5751:   DMCopyDS(dm, newdm);
5752:   return(0);
5753: }

5755: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5756: {
5757:   DM dm_coord,dmc_coord;
5759:   Vec coords,ccoords;
5760:   Mat inject;
5762:   DMGetCoordinateDM(dm,&dm_coord);
5763:   DMGetCoordinateDM(dmc,&dmc_coord);
5764:   DMGetCoordinates(dm,&coords);
5765:   DMGetCoordinates(dmc,&ccoords);
5766:   if (coords && !ccoords) {
5767:     DMCreateGlobalVector(dmc_coord,&ccoords);
5768:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5769:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5770:     MatRestrict(inject,coords,ccoords);
5771:     MatDestroy(&inject);
5772:     DMSetCoordinates(dmc,ccoords);
5773:     VecDestroy(&ccoords);
5774:   }
5775:   return(0);
5776: }

5778: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5779: {
5780:   DM dm_coord,subdm_coord;
5782:   Vec coords,ccoords,clcoords;
5783:   VecScatter *scat_i,*scat_g;
5785:   DMGetCoordinateDM(dm,&dm_coord);
5786:   DMGetCoordinateDM(subdm,&subdm_coord);
5787:   DMGetCoordinates(dm,&coords);
5788:   DMGetCoordinates(subdm,&ccoords);
5789:   if (coords && !ccoords) {
5790:     DMCreateGlobalVector(subdm_coord,&ccoords);
5791:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5792:     DMCreateLocalVector(subdm_coord,&clcoords);
5793:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5794:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5795:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5796:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5797:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5798:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5799:     DMSetCoordinates(subdm,ccoords);
5800:     DMSetCoordinatesLocal(subdm,clcoords);
5801:     VecScatterDestroy(&scat_i[0]);
5802:     VecScatterDestroy(&scat_g[0]);
5803:     VecDestroy(&ccoords);
5804:     VecDestroy(&clcoords);
5805:     PetscFree(scat_i);
5806:     PetscFree(scat_g);
5807:   }
5808:   return(0);
5809: }

5811: /*@
5812:   DMGetDimension - Return the topological dimension of the DM

5814:   Not collective

5816:   Input Parameter:
5817: . dm - The DM

5819:   Output Parameter:
5820: . dim - The topological dimension

5822:   Level: beginner

5824: .seealso: DMSetDimension(), DMCreate()
5825: @*/
5826: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5827: {
5831:   *dim = dm->dim;
5832:   return(0);
5833: }

5835: /*@
5836:   DMSetDimension - Set the topological dimension of the DM

5838:   Collective on dm

5840:   Input Parameters:
5841: + dm - The DM
5842: - dim - The topological dimension

5844:   Level: beginner

5846: .seealso: DMGetDimension(), DMCreate()
5847: @*/
5848: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5849: {
5850:   PetscDS        ds;

5856:   dm->dim = dim;
5857:   DMGetDS(dm, &ds);
5858:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5859:   return(0);
5860: }

5862: /*@
5863:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

5865:   Collective on dm

5867:   Input Parameters:
5868: + dm - the DM
5869: - dim - the dimension

5871:   Output Parameters:
5872: + pStart - The first point of the given dimension
5873: - pEnd - The first point following points of the given dimension

5875:   Note:
5876:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5877:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5878:   then the interval is empty.

5880:   Level: intermediate

5882: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5883: @*/
5884: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5885: {
5886:   PetscInt       d;

5891:   DMGetDimension(dm, &d);
5892:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5893:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5894:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5895:   return(0);
5896: }

5898: /*@
5899:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

5901:   Collective on dm

5903:   Input Parameters:
5904: + dm - the DM
5905: - c - coordinate vector

5907:   Notes:
5908:   The coordinates do include those for ghost points, which are in the local vector.

5910:   The vector c should be destroyed by the caller.

5912:   Level: intermediate

5914: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5915: @*/
5916: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5917: {

5923:   PetscObjectReference((PetscObject) c);
5924:   VecDestroy(&dm->coordinates);
5925:   dm->coordinates = c;
5926:   VecDestroy(&dm->coordinatesLocal);
5927:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5928:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5929:   return(0);
5930: }

5932: /*@
5933:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

5935:   Not collective

5937:    Input Parameters:
5938: +  dm - the DM
5939: -  c - coordinate vector

5941:   Notes:
5942:   The coordinates of ghost points can be set using DMSetCoordinates()
5943:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5944:   setting of ghost coordinates outside of the domain.

5946:   The vector c should be destroyed by the caller.

5948:   Level: intermediate

5950: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5951: @*/
5952: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5953: {

5959:   PetscObjectReference((PetscObject) c);
5960:   VecDestroy(&dm->coordinatesLocal);

5962:   dm->coordinatesLocal = c;

5964:   VecDestroy(&dm->coordinates);
5965:   return(0);
5966: }

5968: /*@
5969:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

5971:   Collective on dm

5973:   Input Parameter:
5974: . dm - the DM

5976:   Output Parameter:
5977: . c - global coordinate vector

5979:   Note:
5980:   This is a borrowed reference, so the user should NOT destroy this vector

5982:   Each process has only the local coordinates (does NOT have the ghost coordinates).

5984:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5985:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

5987:   Level: intermediate

5989: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5990: @*/
5991: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5992: {

5998:   if (!dm->coordinates && dm->coordinatesLocal) {
5999:     DM        cdm = NULL;
6000:     PetscBool localized;

6002:     DMGetCoordinateDM(dm, &cdm);
6003:     DMCreateGlobalVector(cdm, &dm->coordinates);
6004:     DMGetCoordinatesLocalized(dm, &localized);
6005:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6006:     if (localized) {
6007:       PetscInt cdim;

6009:       DMGetCoordinateDim(dm, &cdim);
6010:       VecSetBlockSize(dm->coordinates, cdim);
6011:     }
6012:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6013:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6014:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6015:   }
6016:   *c = dm->coordinates;
6017:   return(0);
6018: }

6020: /*@
6021:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

6023:   Collective on dm

6025:   Input Parameter:
6026: . dm - the DM

6028:   Level: advanced

6030: .seealso: DMGetCoordinatesLocalNoncollective()
6031: @*/
6032: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6033: {

6038:   if (!dm->coordinatesLocal && dm->coordinates) {
6039:     DM        cdm = NULL;
6040:     PetscBool localized;

6042:     DMGetCoordinateDM(dm, &cdm);
6043:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6044:     DMGetCoordinatesLocalized(dm, &localized);
6045:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6046:     if (localized) {
6047:       PetscInt cdim;

6049:       DMGetCoordinateDim(dm, &cdim);
6050:       VecSetBlockSize(dm->coordinates, cdim);
6051:     }
6052:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6053:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6054:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6055:   }
6056:   return(0);
6057: }

6059: /*@
6060:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

6062:   Collective on dm

6064:   Input Parameter:
6065: . dm - the DM

6067:   Output Parameter:
6068: . c - coordinate vector

6070:   Note:
6071:   This is a borrowed reference, so the user should NOT destroy this vector

6073:   Each process has the local and ghost coordinates

6075:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6076:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6078:   Level: intermediate

6080: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6081: @*/
6082: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6083: {

6089:   DMGetCoordinatesLocalSetUp(dm);
6090:   *c = dm->coordinatesLocal;
6091:   return(0);
6092: }

6094: /*@
6095:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6097:   Not collective

6099:   Input Parameter:
6100: . dm - the DM

6102:   Output Parameter:
6103: . c - coordinate vector

6105:   Level: advanced

6107: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6108: @*/
6109: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6110: {
6114:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6115:   *c = dm->coordinatesLocal;
6116:   return(0);
6117: }

6119: /*@
6120:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6122:   Not collective

6124:   Input Parameter:
6125: + dm - the DM
6126: - p - the IS of points whose coordinates will be returned

6128:   Output Parameter:
6129: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6130: - pCoord - the Vec with coordinates of points in p

6132:   Note:
6133:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6135:   This creates a new vector, so the user SHOULD destroy this vector

6137:   Each process has the local and ghost coordinates

6139:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6140:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6142:   Level: advanced

6144: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6145: @*/
6146: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6147: {
6148:   PetscSection        cs, newcs;
6149:   Vec                 coords;
6150:   const PetscScalar   *arr;
6151:   PetscScalar         *newarr=NULL;
6152:   PetscInt            n;
6153:   PetscErrorCode      ierr;

6160:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6161:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6162:   cs = dm->coordinateDM->localSection;
6163:   coords = dm->coordinatesLocal;
6164:   VecGetArrayRead(coords, &arr);
6165:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6166:   VecRestoreArrayRead(coords, &arr);
6167:   if (pCoord) {
6168:     PetscSectionGetStorageSize(newcs, &n);
6169:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6170:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6171:     VecReplaceArray(*pCoord, newarr);
6172:   } else {
6173:     PetscFree(newarr);
6174:   }
6175:   if (pCoordSection) {*pCoordSection = newcs;}
6176:   else               {PetscSectionDestroy(&newcs);}
6177:   return(0);
6178: }

6180: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6181: {

6187:   if (!dm->coordinateField) {
6188:     if (dm->ops->createcoordinatefield) {
6189:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6190:     }
6191:   }
6192:   *field = dm->coordinateField;
6193:   return(0);
6194: }

6196: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6197: {

6203:   PetscObjectReference((PetscObject)field);
6204:   DMFieldDestroy(&dm->coordinateField);
6205:   dm->coordinateField = field;
6206:   return(0);
6207: }

6209: /*@
6210:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

6212:   Collective on dm

6214:   Input Parameter:
6215: . dm - the DM

6217:   Output Parameter:
6218: . cdm - coordinate DM

6220:   Level: intermediate

6222: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6223: @*/
6224: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6225: {

6231:   if (!dm->coordinateDM) {
6232:     DM cdm;

6234:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6235:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6236:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6237:      * until the call to CreateCoordinateDM) */
6238:     DMDestroy(&dm->coordinateDM);
6239:     dm->coordinateDM = cdm;
6240:   }
6241:   *cdm = dm->coordinateDM;
6242:   return(0);
6243: }

6245: /*@
6246:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

6248:   Logically Collective on dm

6250:   Input Parameters:
6251: + dm - the DM
6252: - cdm - coordinate DM

6254:   Level: intermediate

6256: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6257: @*/
6258: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6259: {

6265:   PetscObjectReference((PetscObject)cdm);
6266:   DMDestroy(&dm->coordinateDM);
6267:   dm->coordinateDM = cdm;
6268:   return(0);
6269: }

6271: /*@
6272:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

6274:   Not Collective

6276:   Input Parameter:
6277: . dm - The DM object

6279:   Output Parameter:
6280: . dim - The embedding dimension

6282:   Level: intermediate

6284: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6285: @*/
6286: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6287: {
6291:   if (dm->dimEmbed == PETSC_DEFAULT) {
6292:     dm->dimEmbed = dm->dim;
6293:   }
6294:   *dim = dm->dimEmbed;
6295:   return(0);
6296: }

6298: /*@
6299:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

6301:   Not Collective

6303:   Input Parameters:
6304: + dm  - The DM object
6305: - dim - The embedding dimension

6307:   Level: intermediate

6309: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6310: @*/
6311: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6312: {
6313:   PetscDS        ds;

6318:   dm->dimEmbed = dim;
6319:   DMGetDS(dm, &ds);
6320:   PetscDSSetCoordinateDimension(ds, dim);
6321:   return(0);
6322: }

6324: /*@
6325:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6327:   Collective on dm

6329:   Input Parameter:
6330: . dm - The DM object

6332:   Output Parameter:
6333: . section - The PetscSection object

6335:   Level: intermediate

6337: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6338: @*/
6339: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6340: {
6341:   DM             cdm;

6347:   DMGetCoordinateDM(dm, &cdm);
6348:   DMGetLocalSection(cdm, section);
6349:   return(0);
6350: }

6352: /*@
6353:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6355:   Not Collective

6357:   Input Parameters:
6358: + dm      - The DM object
6359: . dim     - The embedding dimension, or PETSC_DETERMINE
6360: - section - The PetscSection object

6362:   Level: intermediate

6364: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6365: @*/
6366: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6367: {
6368:   DM             cdm;

6374:   DMGetCoordinateDM(dm, &cdm);
6375:   DMSetLocalSection(cdm, section);
6376:   if (dim == PETSC_DETERMINE) {
6377:     PetscInt d = PETSC_DEFAULT;
6378:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6380:     PetscSectionGetChart(section, &pStart, &pEnd);
6381:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6382:     pStart = PetscMax(vStart, pStart);
6383:     pEnd   = PetscMin(vEnd, pEnd);
6384:     for (v = pStart; v < pEnd; ++v) {
6385:       PetscSectionGetDof(section, v, &dd);
6386:       if (dd) {d = dd; break;}
6387:     }
6388:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6389:   }
6390:   return(0);
6391: }

6393: /*@
6394:   DMProjectCoordinates - Project coordinates to a different space

6396:   Input Parameters:
6397: + dm      - The DM object
6398: - disc    - The new coordinate discretization

6400:   Level: intermediate

6402: .seealso: DMGetCoordinateField()
6403: @*/
6404: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6405: {
6406:   PetscObject    discOld;
6407:   PetscClassId   classid;
6408:   DM             cdmOld,cdmNew;
6409:   Vec            coordsOld,coordsNew;
6410:   Mat            matInterp;


6417:   DMGetCoordinateDM(dm, &cdmOld);
6418:   /* Check current discretization is compatible */
6419:   DMGetField(cdmOld, 0, NULL, &discOld);
6420:   PetscObjectGetClassId(discOld, &classid);
6421:   if (classid != PETSCFE_CLASSID) SETERRQ(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type not supported");
6422:   /* Make a fresh clone of the coordinate DM */
6423:   DMClone(cdmOld, &cdmNew);
6424:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6425:   DMCreateDS(cdmNew);
6426:   /* Project the coordinate vector from old to new space  */
6427:   DMGetCoordinates(dm, &coordsOld);
6428:   DMCreateGlobalVector(cdmNew, &coordsNew);
6429:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6430:   MatInterpolate(matInterp, coordsOld, coordsNew);
6431:   MatDestroy(&matInterp);
6432:   /* Set new coordinate structures */
6433:   DMSetCoordinateField(dm, NULL);
6434:   DMSetCoordinateDM(dm, cdmNew);
6435:   DMSetCoordinates(dm, coordsNew);
6436:   VecDestroy(&coordsNew);
6437:   DMDestroy(&cdmNew);
6438:   return(0);
6439: }

6441: /*@C
6442:   DMGetPeriodicity - Get the description of mesh periodicity

6444:   Input Parameters:
6445: . dm      - The DM object

6447:   Output Parameters:
6448: + per     - Whether the DM is periodic or not
6449: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6450: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6451: - bd      - This describes the type of periodicity in each topological dimension

6453:   Level: developer

6455: .seealso: DMGetPeriodicity()
6456: @*/
6457: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6458: {
6461:   if (per)     *per     = dm->periodic;
6462:   if (L)       *L       = dm->L;
6463:   if (maxCell) *maxCell = dm->maxCell;
6464:   if (bd)      *bd      = dm->bdtype;
6465:   return(0);
6466: }

6468: /*@C
6469:   DMSetPeriodicity - Set the description of mesh periodicity

6471:   Input Parameters:
6472: + dm      - The DM object
6473: . per     - Whether the DM is periodic or not.
6474: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
6475: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6476: - bd      - This describes the type of periodicity in each topological dimension

6478:   Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.

6480:   Level: developer

6482: .seealso: DMGetPeriodicity()
6483: @*/
6484: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6485: {
6486:   PetscInt       dim, d;

6495:   DMGetDimension(dm, &dim);
6496:   if (maxCell) {
6497:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6498:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6499:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6500:     PetscFree(dm->maxCell);
6501:   }

6503:   if (L) {
6504:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6505:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6506:   }
6507:   if (bd) {
6508:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6509:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6510:   }
6511:   dm->periodic = per;
6512:   return(0);
6513: }

6515: /*@
6516:   DMLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension.

6518:   Input Parameters:
6519: + dm     - The DM
6520: . in     - The input coordinate point (dim numbers)
6521: - endpoint - Include the endpoint L_i

6523:   Output Parameter:
6524: . out - The localized coordinate point

6526:   Level: developer

6528: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6529: @*/
6530: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6531: {
6532:   PetscInt       dim, d;

6536:   DMGetCoordinateDim(dm, &dim);
6537:   if (!dm->maxCell) {
6538:     for (d = 0; d < dim; ++d) out[d] = in[d];
6539:   } else {
6540:     if (endpoint) {
6541:       for (d = 0; d < dim; ++d) {
6542:         if ((PetscAbsReal(PetscRealPart(in[d])/dm->L[d] - PetscFloorReal(PetscRealPart(in[d])/dm->L[d])) < PETSC_SMALL) && (PetscRealPart(in[d])/dm->L[d] > PETSC_SMALL)) {
6543:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6544:         } else {
6545:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6546:         }
6547:       }
6548:     } else {
6549:       for (d = 0; d < dim; ++d) {
6550:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6551:       }
6552:     }
6553:   }
6554:   return(0);
6555: }

6557: /*
6558:   DMLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

6560:   Input Parameters:
6561: + dm     - The DM
6562: . dim    - The spatial dimension
6563: . anchor - The anchor point, the input point can be no more than maxCell away from it
6564: - in     - The input coordinate point (dim numbers)

6566:   Output Parameter:
6567: . out - The localized coordinate point

6569:   Level: developer

6571:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

6573: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6574: */
6575: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6576: {
6577:   PetscInt d;

6580:   if (!dm->maxCell) {
6581:     for (d = 0; d < dim; ++d) out[d] = in[d];
6582:   } else {
6583:     for (d = 0; d < dim; ++d) {
6584:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6585:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6586:       } else {
6587:         out[d] = in[d];
6588:       }
6589:     }
6590:   }
6591:   return(0);
6592: }

6594: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6595: {
6596:   PetscInt d;

6599:   if (!dm->maxCell) {
6600:     for (d = 0; d < dim; ++d) out[d] = in[d];
6601:   } else {
6602:     for (d = 0; d < dim; ++d) {
6603:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6604:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6605:       } else {
6606:         out[d] = in[d];
6607:       }
6608:     }
6609:   }
6610:   return(0);
6611: }

6613: /*
6614:   DMLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

6616:   Input Parameters:
6617: + dm     - The DM
6618: . dim    - The spatial dimension
6619: . anchor - The anchor point, the input point can be no more than maxCell away from it
6620: . in     - The input coordinate delta (dim numbers)
6621: - out    - The input coordinate point (dim numbers)

6623:   Output Parameter:
6624: . out    - The localized coordinate in + out

6626:   Level: developer

6628:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

6630: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6631: */
6632: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6633: {
6634:   PetscInt d;

6637:   if (!dm->maxCell) {
6638:     for (d = 0; d < dim; ++d) out[d] += in[d];
6639:   } else {
6640:     for (d = 0; d < dim; ++d) {
6641:       const PetscReal maxC = dm->maxCell[d];

6643:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6644:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6646:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6647:           SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
6648:         out[d] += newCoord;
6649:       } else {
6650:         out[d] += in[d];
6651:       }
6652:     }
6653:   }
6654:   return(0);
6655: }

6657: /*@
6658:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6660:   Not collective

6662:   Input Parameter:
6663: . dm - The DM

6665:   Output Parameter:
6666:   areLocalized - True if localized

6668:   Level: developer

6670: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6671: @*/
6672: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6673: {
6674:   DM             cdm;
6675:   PetscSection   coordSection;
6676:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6677:   PetscBool      isPlex, alreadyLocalized;

6683:   *areLocalized = PETSC_FALSE;

6685:   /* We need some generic way of refering to cells/vertices */
6686:   DMGetCoordinateDM(dm, &cdm);
6687:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6688:   if (!isPlex) return(0);

6690:   DMGetCoordinateSection(dm, &coordSection);
6691:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6692:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6693:   alreadyLocalized = PETSC_FALSE;
6694:   for (c = cStart; c < cEnd; ++c) {
6695:     if (c < sStart || c >= sEnd) continue;
6696:     PetscSectionGetDof(coordSection, c, &dof);
6697:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6698:   }
6699:   *areLocalized = alreadyLocalized;
6700:   return(0);
6701: }

6703: /*@
6704:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6706:   Collective on dm

6708:   Input Parameter:
6709: . dm - The DM

6711:   Output Parameter:
6712:   areLocalized - True if localized

6714:   Level: developer

6716: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6717: @*/
6718: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6719: {
6720:   PetscBool      localized;

6726:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6727:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6728:   return(0);
6729: }

6731: /*@
6732:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6734:   Collective on dm

6736:   Input Parameter:
6737: . dm - The DM

6739:   Level: developer

6741: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6742: @*/
6743: PetscErrorCode DMLocalizeCoordinates(DM dm)
6744: {
6745:   DM             cdm;
6746:   PetscSection   coordSection, cSection;
6747:   Vec            coordinates,  cVec;
6748:   PetscScalar   *coords, *coords2, *anchor, *localized;
6749:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6750:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6751:   PetscInt       maxHeight = 0, h;
6752:   PetscInt       *pStart = NULL, *pEnd = NULL;

6757:   if (!dm->periodic) return(0);
6758:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6759:   if (alreadyLocalized) return(0);

6761:   /* We need some generic way of refering to cells/vertices */
6762:   DMGetCoordinateDM(dm, &cdm);
6763:   {
6764:     PetscBool isplex;

6766:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6767:     if (isplex) {
6768:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6769:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6770:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6771:       pEnd = &pStart[maxHeight + 1];
6772:       newStart = vStart;
6773:       newEnd   = vEnd;
6774:       for (h = 0; h <= maxHeight; h++) {
6775:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6776:         newStart = PetscMin(newStart,pStart[h]);
6777:         newEnd   = PetscMax(newEnd,pEnd[h]);
6778:       }
6779:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6780:   }
6781:   DMGetCoordinatesLocal(dm, &coordinates);
6782:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6783:   DMGetCoordinateSection(dm, &coordSection);
6784:   VecGetBlockSize(coordinates, &bs);
6785:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6787:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6788:   PetscSectionSetNumFields(cSection, 1);
6789:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6790:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6791:   PetscSectionSetChart(cSection, newStart, newEnd);

6793:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6794:   localized = &anchor[bs];
6795:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6796:   for (h = 0; h <= maxHeight; h++) {
6797:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6799:     for (c = cStart; c < cEnd; ++c) {
6800:       PetscScalar *cellCoords = NULL;
6801:       PetscInt     b;

6803:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6804:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6805:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6806:       for (d = 0; d < dof/bs; ++d) {
6807:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6808:         for (b = 0; b < bs; b++) {
6809:           if (cellCoords[d*bs + b] != localized[b]) break;
6810:         }
6811:         if (b < bs) break;
6812:       }
6813:       if (d < dof/bs) {
6814:         if (c >= sStart && c < sEnd) {
6815:           PetscInt cdof;

6817:           PetscSectionGetDof(coordSection, c, &cdof);
6818:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6819:         }
6820:         PetscSectionSetDof(cSection, c, dof);
6821:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6822:       }
6823:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6824:     }
6825:   }
6826:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6827:   if (alreadyLocalizedGlobal) {
6828:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6829:     PetscSectionDestroy(&cSection);
6830:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6831:     return(0);
6832:   }
6833:   for (v = vStart; v < vEnd; ++v) {
6834:     PetscSectionGetDof(coordSection, v, &dof);
6835:     PetscSectionSetDof(cSection, v, dof);
6836:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6837:   }
6838:   PetscSectionSetUp(cSection);
6839:   PetscSectionGetStorageSize(cSection, &coordSize);
6840:   VecCreate(PETSC_COMM_SELF, &cVec);
6841:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6842:   VecSetBlockSize(cVec, bs);
6843:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6844:   VecSetType(cVec, VECSTANDARD);
6845:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6846:   VecGetArray(cVec, &coords2);
6847:   for (v = vStart; v < vEnd; ++v) {
6848:     PetscSectionGetDof(coordSection, v, &dof);
6849:     PetscSectionGetOffset(coordSection, v, &off);
6850:     PetscSectionGetOffset(cSection,     v, &off2);
6851:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6852:   }
6853:   for (h = 0; h <= maxHeight; h++) {
6854:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6856:     for (c = cStart; c < cEnd; ++c) {
6857:       PetscScalar *cellCoords = NULL;
6858:       PetscInt     b, cdof;

6860:       PetscSectionGetDof(cSection,c,&cdof);
6861:       if (!cdof) continue;
6862:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6863:       PetscSectionGetOffset(cSection, c, &off2);
6864:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6865:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6866:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6867:     }
6868:   }
6869:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6870:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6871:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6872:   VecRestoreArray(cVec, &coords2);
6873:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6874:   DMSetCoordinatesLocal(dm, cVec);
6875:   VecDestroy(&cVec);
6876:   PetscSectionDestroy(&cSection);
6877:   return(0);
6878: }

6880: /*@
6881:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

6883:   Collective on v (see explanation below)

6885:   Input Parameters:
6886: + dm - The DM
6887: . v - The Vec of points
6888: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6889: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6891:   Output Parameter:
6892: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6893: - cells - The PetscSF containing the ranks and local indices of the containing points.


6896:   Level: developer

6898:   Notes:
6899:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6900:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

6902:   If *cellSF is NULL on input, a PetscSF will be created.
6903:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

6905:   An array that maps each point to its containing cell can be obtained with

6907: $    const PetscSFNode *cells;
6908: $    PetscInt           nFound;
6909: $    const PetscInt    *found;
6910: $
6911: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

6913:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6914:   the index of the cell in its rank's local numbering.

6916: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6917: @*/
6918: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6919: {

6926:   if (*cellSF) {
6927:     PetscMPIInt result;

6930:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6931:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6932:   } else {
6933:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6934:   }
6935:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6936:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6937:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6938:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6939:   return(0);
6940: }

6942: /*@
6943:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6945:   Collective on dm

6947:   Input Parameter:
6948: . dm - The original DM

6950:   Output Parameter:
6951: . odm - The DM which provides the layout for output

6953:   Level: intermediate

6955: .seealso: VecView(), DMGetGlobalSection()
6956: @*/
6957: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6958: {
6959:   PetscSection   section;
6960:   PetscBool      hasConstraints, ghasConstraints;

6966:   DMGetLocalSection(dm, &section);
6967:   PetscSectionHasConstraints(section, &hasConstraints);
6968:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6969:   if (!ghasConstraints) {
6970:     *odm = dm;
6971:     return(0);
6972:   }
6973:   if (!dm->dmBC) {
6974:     PetscSection newSection, gsection;
6975:     PetscSF      sf;

6977:     DMClone(dm, &dm->dmBC);
6978:     DMCopyDisc(dm, dm->dmBC);
6979:     PetscSectionClone(section, &newSection);
6980:     DMSetLocalSection(dm->dmBC, newSection);
6981:     PetscSectionDestroy(&newSection);
6982:     DMGetPointSF(dm->dmBC, &sf);
6983:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6984:     DMSetGlobalSection(dm->dmBC, gsection);
6985:     PetscSectionDestroy(&gsection);
6986:   }
6987:   *odm = dm->dmBC;
6988:   return(0);
6989: }

6991: /*@
6992:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6994:   Input Parameter:
6995: . dm - The original DM

6997:   Output Parameters:
6998: + num - The output sequence number
6999: - val - The output sequence value

7001:   Level: intermediate

7003:   Note: This is intended for output that should appear in sequence, for instance
7004:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7006: .seealso: VecView()
7007: @*/
7008: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7009: {
7014:   return(0);
7015: }

7017: /*@
7018:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7020:   Input Parameters:
7021: + dm - The original DM
7022: . num - The output sequence number
7023: - val - The output sequence value

7025:   Level: intermediate

7027:   Note: This is intended for output that should appear in sequence, for instance
7028:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7030: .seealso: VecView()
7031: @*/
7032: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7033: {
7036:   dm->outputSequenceNum = num;
7037:   dm->outputSequenceVal = val;
7038:   return(0);
7039: }

7041: /*@C
7042:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7044:   Input Parameters:
7045: + dm   - The original DM
7046: . name - The sequence name
7047: - num  - The output sequence number

7049:   Output Parameter:
7050: . val  - The output sequence value

7052:   Level: intermediate

7054:   Note: This is intended for output that should appear in sequence, for instance
7055:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7057: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7058: @*/
7059: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7060: {
7061:   PetscBool      ishdf5;

7068:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7069:   if (ishdf5) {
7070: #if defined(PETSC_HAVE_HDF5)
7071:     PetscScalar value;

7073:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7074:     *val = PetscRealPart(value);
7075: #endif
7076:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7077:   return(0);
7078: }

7080: /*@
7081:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

7083:   Not collective

7085:   Input Parameter:
7086: . dm - The DM

7088:   Output Parameter:
7089: . useNatural - The flag to build the mapping to a natural order during distribution

7091:   Level: beginner

7093: .seealso: DMSetUseNatural(), DMCreate()
7094: @*/
7095: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7096: {
7100:   *useNatural = dm->useNatural;
7101:   return(0);
7102: }

7104: /*@
7105:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7107:   Collective on dm

7109:   Input Parameters:
7110: + dm - The DM
7111: - useNatural - The flag to build the mapping to a natural order during distribution

7113:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7115:   Level: beginner

7117: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7118: @*/
7119: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7120: {
7124:   dm->useNatural = useNatural;
7125:   return(0);
7126: }


7129: /*@C
7130:   DMCreateLabel - Create a label of the given name if it does not already exist

7132:   Not Collective

7134:   Input Parameters:
7135: + dm   - The DM object
7136: - name - The label name

7138:   Level: intermediate

7140: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7141: @*/
7142: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7143: {
7144:   PetscBool      flg;
7145:   DMLabel        label;

7151:   DMHasLabel(dm, name, &flg);
7152:   if (!flg) {
7153:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7154:     DMAddLabel(dm, label);
7155:     DMLabelDestroy(&label);
7156:   }
7157:   return(0);
7158: }

7160: /*@C
7161:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

7163:   Not Collective

7165:   Input Parameters:
7166: + dm   - The DM object
7167: . name - The label name
7168: - point - The mesh point

7170:   Output Parameter:
7171: . value - The label value for this point, or -1 if the point is not in the label

7173:   Level: beginner

7175: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7176: @*/
7177: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7178: {
7179:   DMLabel        label;

7185:   DMGetLabel(dm, name, &label);
7186:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7187:   DMLabelGetValue(label, point, value);
7188:   return(0);
7189: }

7191: /*@C
7192:   DMSetLabelValue - Add a point to a Sieve Label with given value

7194:   Not Collective

7196:   Input Parameters:
7197: + dm   - The DM object
7198: . name - The label name
7199: . point - The mesh point
7200: - value - The label value for this point

7202:   Output Parameter:

7204:   Level: beginner

7206: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7207: @*/
7208: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7209: {
7210:   DMLabel        label;

7216:   DMGetLabel(dm, name, &label);
7217:   if (!label) {
7218:     DMCreateLabel(dm, name);
7219:     DMGetLabel(dm, name, &label);
7220:   }
7221:   DMLabelSetValue(label, point, value);
7222:   return(0);
7223: }

7225: /*@C
7226:   DMClearLabelValue - Remove a point from a Sieve Label with given value

7228:   Not Collective

7230:   Input Parameters:
7231: + dm   - The DM object
7232: . name - The label name
7233: . point - The mesh point
7234: - value - The label value for this point

7236:   Output Parameter:

7238:   Level: beginner

7240: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7241: @*/
7242: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7243: {
7244:   DMLabel        label;

7250:   DMGetLabel(dm, name, &label);
7251:   if (!label) return(0);
7252:   DMLabelClearValue(label, point, value);
7253:   return(0);
7254: }

7256: /*@C
7257:   DMGetLabelSize - Get the number of different integer ids in a Label

7259:   Not Collective

7261:   Input Parameters:
7262: + dm   - The DM object
7263: - name - The label name

7265:   Output Parameter:
7266: . size - The number of different integer ids, or 0 if the label does not exist

7268:   Level: beginner

7270: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7271: @*/
7272: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7273: {
7274:   DMLabel        label;

7281:   DMGetLabel(dm, name, &label);
7282:   *size = 0;
7283:   if (!label) return(0);
7284:   DMLabelGetNumValues(label, size);
7285:   return(0);
7286: }

7288: /*@C
7289:   DMGetLabelIdIS - Get the integer ids in a label

7291:   Not Collective

7293:   Input Parameters:
7294: + mesh - The DM object
7295: - name - The label name

7297:   Output Parameter:
7298: . ids - The integer ids, or NULL if the label does not exist

7300:   Level: beginner

7302: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7303: @*/
7304: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7305: {
7306:   DMLabel        label;

7313:   DMGetLabel(dm, name, &label);
7314:   *ids = NULL;
7315:  if (label) {
7316:     DMLabelGetValueIS(label, ids);
7317:   } else {
7318:     /* returning an empty IS */
7319:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7320:   }
7321:   return(0);
7322: }

7324: /*@C
7325:   DMGetStratumSize - Get the number of points in a label stratum

7327:   Not Collective

7329:   Input Parameters:
7330: + dm - The DM object
7331: . name - The label name
7332: - value - The stratum value

7334:   Output Parameter:
7335: . size - The stratum size

7337:   Level: beginner

7339: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7340: @*/
7341: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7342: {
7343:   DMLabel        label;

7350:   DMGetLabel(dm, name, &label);
7351:   *size = 0;
7352:   if (!label) return(0);
7353:   DMLabelGetStratumSize(label, value, size);
7354:   return(0);
7355: }

7357: /*@C
7358:   DMGetStratumIS - Get the points in a label stratum

7360:   Not Collective

7362:   Input Parameters:
7363: + dm - The DM object
7364: . name - The label name
7365: - value - The stratum value

7367:   Output Parameter:
7368: . points - The stratum points, or NULL if the label does not exist or does not have that value

7370:   Level: beginner

7372: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7373: @*/
7374: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7375: {
7376:   DMLabel        label;

7383:   DMGetLabel(dm, name, &label);
7384:   *points = NULL;
7385:   if (!label) return(0);
7386:   DMLabelGetStratumIS(label, value, points);
7387:   return(0);
7388: }

7390: /*@C
7391:   DMSetStratumIS - Set the points in a label stratum

7393:   Not Collective

7395:   Input Parameters:
7396: + dm - The DM object
7397: . name - The label name
7398: . value - The stratum value
7399: - points - The stratum points

7401:   Level: beginner

7403: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7404: @*/
7405: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7406: {
7407:   DMLabel        label;

7414:   DMGetLabel(dm, name, &label);
7415:   if (!label) return(0);
7416:   DMLabelSetStratumIS(label, value, points);
7417:   return(0);
7418: }

7420: /*@C
7421:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7423:   Not Collective

7425:   Input Parameters:
7426: + dm   - The DM object
7427: . name - The label name
7428: - value - The label value for this point

7430:   Output Parameter:

7432:   Level: beginner

7434: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7435: @*/
7436: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7437: {
7438:   DMLabel        label;

7444:   DMGetLabel(dm, name, &label);
7445:   if (!label) return(0);
7446:   DMLabelClearStratum(label, value);
7447:   return(0);
7448: }

7450: /*@
7451:   DMGetNumLabels - Return the number of labels defined by the mesh

7453:   Not Collective

7455:   Input Parameter:
7456: . dm   - The DM object

7458:   Output Parameter:
7459: . numLabels - the number of Labels

7461:   Level: intermediate

7463: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7464: @*/
7465: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7466: {
7467:   DMLabelLink next = dm->labels;
7468:   PetscInt  n    = 0;

7473:   while (next) {++n; next = next->next;}
7474:   *numLabels = n;
7475:   return(0);
7476: }

7478: /*@C
7479:   DMGetLabelName - Return the name of nth label

7481:   Not Collective

7483:   Input Parameters:
7484: + dm - The DM object
7485: - n  - the label number

7487:   Output Parameter:
7488: . name - the label name

7490:   Level: intermediate

7492: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7493: @*/
7494: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7495: {
7496:   DMLabelLink    next = dm->labels;
7497:   PetscInt       l    = 0;

7503:   while (next) {
7504:     if (l == n) {
7505:       PetscObjectGetName((PetscObject) next->label, name);
7506:       return(0);
7507:     }
7508:     ++l;
7509:     next = next->next;
7510:   }
7511:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7512: }

7514: /*@C
7515:   DMHasLabel - Determine whether the mesh has a label of a given name

7517:   Not Collective

7519:   Input Parameters:
7520: + dm   - The DM object
7521: - name - The label name

7523:   Output Parameter:
7524: . hasLabel - PETSC_TRUE if the label is present

7526:   Level: intermediate

7528: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7529: @*/
7530: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7531: {
7532:   DMLabelLink    next = dm->labels;
7533:   const char    *lname;

7540:   *hasLabel = PETSC_FALSE;
7541:   while (next) {
7542:     PetscObjectGetName((PetscObject) next->label, &lname);
7543:     PetscStrcmp(name, lname, hasLabel);
7544:     if (*hasLabel) break;
7545:     next = next->next;
7546:   }
7547:   return(0);
7548: }

7550: /*@C
7551:   DMGetLabel - Return the label of a given name, or NULL

7553:   Not Collective

7555:   Input Parameters:
7556: + dm   - The DM object
7557: - name - The label name

7559:   Output Parameter:
7560: . label - The DMLabel, or NULL if the label is absent

7562:   Level: intermediate

7564: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7565: @*/
7566: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7567: {
7568:   DMLabelLink    next = dm->labels;
7569:   PetscBool      hasLabel;
7570:   const char    *lname;

7577:   *label = NULL;
7578:   while (next) {
7579:     PetscObjectGetName((PetscObject) next->label, &lname);
7580:     PetscStrcmp(name, lname, &hasLabel);
7581:     if (hasLabel) {
7582:       *label = next->label;
7583:       break;
7584:     }
7585:     next = next->next;
7586:   }
7587:   return(0);
7588: }

7590: /*@C
7591:   DMGetLabelByNum - Return the nth label

7593:   Not Collective

7595:   Input Parameters:
7596: + dm - The DM object
7597: - n  - the label number

7599:   Output Parameter:
7600: . label - the label

7602:   Level: intermediate

7604: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7605: @*/
7606: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7607: {
7608:   DMLabelLink next = dm->labels;
7609:   PetscInt    l    = 0;

7614:   while (next) {
7615:     if (l == n) {
7616:       *label = next->label;
7617:       return(0);
7618:     }
7619:     ++l;
7620:     next = next->next;
7621:   }
7622:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7623: }

7625: /*@C
7626:   DMAddLabel - Add the label to this mesh

7628:   Not Collective

7630:   Input Parameters:
7631: + dm   - The DM object
7632: - label - The DMLabel

7634:   Level: developer

7636: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7637: @*/
7638: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7639: {
7640:   DMLabelLink    l, *p, tmpLabel;
7641:   PetscBool      hasLabel;
7642:   const char    *lname;
7643:   PetscBool      flg;

7648:   PetscObjectGetName((PetscObject) label, &lname);
7649:   DMHasLabel(dm, lname, &hasLabel);
7650:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7651:   PetscCalloc1(1, &tmpLabel);
7652:   tmpLabel->label  = label;
7653:   tmpLabel->output = PETSC_TRUE;
7654:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7655:   *p = tmpLabel;
7656:   PetscObjectReference((PetscObject)label);
7657:   PetscStrcmp(lname, "depth", &flg);
7658:   if (flg) dm->depthLabel = label;
7659:   PetscStrcmp(lname, "celltype", &flg);
7660:   if (flg) dm->celltypeLabel = label;
7661:   return(0);
7662: }

7664: /*@C
7665:   DMRemoveLabel - Remove the label given by name from this mesh

7667:   Not Collective

7669:   Input Parameters:
7670: + dm   - The DM object
7671: - name - The label name

7673:   Output Parameter:
7674: . label - The DMLabel, or NULL if the label is absent

7676:   Level: developer

7678:   Notes:
7679:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7680:   DMLabelDestroy() on the label.

7682:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7683:   call DMLabelDestroy(). Instead, the label is returned and the user is
7684:   responsible of calling DMLabelDestroy() at some point.

7686: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7687: @*/
7688: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7689: {
7690:   DMLabelLink    link, *pnext;
7691:   PetscBool      hasLabel;
7692:   const char    *lname;

7698:   if (label) {
7700:     *label = NULL;
7701:   }
7702:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7703:     PetscObjectGetName((PetscObject) link->label, &lname);
7704:     PetscStrcmp(name, lname, &hasLabel);
7705:     if (hasLabel) {
7706:       *pnext = link->next; /* Remove from list */
7707:       PetscStrcmp(name, "depth", &hasLabel);
7708:       if (hasLabel) dm->depthLabel = NULL;
7709:       PetscStrcmp(name, "celltype", &hasLabel);
7710:       if (hasLabel) dm->celltypeLabel = NULL;
7711:       if (label) *label = link->label;
7712:       else       {DMLabelDestroy(&link->label);}
7713:       PetscFree(link);
7714:       break;
7715:     }
7716:   }
7717:   return(0);
7718: }

7720: /*@
7721:   DMRemoveLabelBySelf - Remove the label from this mesh

7723:   Not Collective

7725:   Input Parameters:
7726: + dm   - The DM object
7727: . label - (Optional) The DMLabel to be removed from the DM
7728: - failNotFound - Should it fail if the label is not found in the DM?

7730:   Level: developer

7732:   Notes:
7733:   Only exactly the same instance is removed if found, name match is ignored.
7734:   If the DM has an exclusive reference to the label, it gets destroyed and
7735:   *label nullified.

7737: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7738: @*/
7739: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7740: {
7741:   DMLabelLink    link, *pnext;
7742:   PetscBool      hasLabel = PETSC_FALSE;

7748:   if (!*label && !failNotFound) return(0);
7751:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7752:     if (*label == link->label) {
7753:       hasLabel = PETSC_TRUE;
7754:       *pnext = link->next; /* Remove from list */
7755:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7756:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7757:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7758:       DMLabelDestroy(&link->label);
7759:       PetscFree(link);
7760:       break;
7761:     }
7762:   }
7763:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7764:   return(0);
7765: }

7767: /*@C
7768:   DMGetLabelOutput - Get the output flag for a given label

7770:   Not Collective

7772:   Input Parameters:
7773: + dm   - The DM object
7774: - name - The label name

7776:   Output Parameter:
7777: . output - The flag for output

7779:   Level: developer

7781: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7782: @*/
7783: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7784: {
7785:   DMLabelLink    next = dm->labels;
7786:   const char    *lname;

7793:   while (next) {
7794:     PetscBool flg;

7796:     PetscObjectGetName((PetscObject) next->label, &lname);
7797:     PetscStrcmp(name, lname, &flg);
7798:     if (flg) {*output = next->output; return(0);}
7799:     next = next->next;
7800:   }
7801:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7802: }

7804: /*@C
7805:   DMSetLabelOutput - Set the output flag for a given label

7807:   Not Collective

7809:   Input Parameters:
7810: + dm     - The DM object
7811: . name   - The label name
7812: - output - The flag for output

7814:   Level: developer

7816: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7817: @*/
7818: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7819: {
7820:   DMLabelLink    next = dm->labels;
7821:   const char    *lname;

7827:   while (next) {
7828:     PetscBool flg;

7830:     PetscObjectGetName((PetscObject) next->label, &lname);
7831:     PetscStrcmp(name, lname, &flg);
7832:     if (flg) {next->output = output; return(0);}
7833:     next = next->next;
7834:   }
7835:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7836: }

7838: /*@
7839:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

7841:   Collective on dmA

7843:   Input Parameter:
7844: + dmA - The DM object with initial labels
7845: . dmB - The DM object with copied labels
7846: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7847: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7849:   Level: intermediate

7851:   Note: This is typically used when interpolating or otherwise adding to a mesh

7853: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7854: @*/
7855: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7856: {
7857:   DMLabel        label, labelNew;
7858:   const char    *name;
7859:   PetscBool      flg;
7860:   DMLabelLink    link;

7868:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7869:   if (dmA == dmB) return(0);
7870:   for (link=dmA->labels; link; link=link->next) {
7871:     label=link->label;
7872:     PetscObjectGetName((PetscObject)label, &name);
7873:     if (!all) {
7874:       PetscStrcmp(name, "depth", &flg);
7875:       if (flg) continue;
7876:       PetscStrcmp(name, "dim", &flg);
7877:       if (flg) continue;
7878:       PetscStrcmp(name, "celltype", &flg);
7879:       if (flg) continue;
7880:     }
7881:     if (mode==PETSC_COPY_VALUES) {
7882:       DMLabelDuplicate(label, &labelNew);
7883:     } else {
7884:       labelNew = label;
7885:     }
7886:     DMAddLabel(dmB, labelNew);
7887:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7888:   }
7889:   return(0);
7890: }

7892: /*@
7893:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

7895:   Input Parameter:
7896: . dm - The DM object

7898:   Output Parameter:
7899: . cdm - The coarse DM

7901:   Level: intermediate

7903: .seealso: DMSetCoarseDM()
7904: @*/
7905: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7906: {
7910:   *cdm = dm->coarseMesh;
7911:   return(0);
7912: }

7914: /*@
7915:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

7917:   Input Parameters:
7918: + dm - The DM object
7919: - cdm - The coarse DM

7921:   Level: intermediate

7923: .seealso: DMGetCoarseDM()
7924: @*/
7925: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7926: {

7932:   PetscObjectReference((PetscObject)cdm);
7933:   DMDestroy(&dm->coarseMesh);
7934:   dm->coarseMesh = cdm;
7935:   return(0);
7936: }

7938: /*@
7939:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

7941:   Input Parameter:
7942: . dm - The DM object

7944:   Output Parameter:
7945: . fdm - The fine DM

7947:   Level: intermediate

7949: .seealso: DMSetFineDM()
7950: @*/
7951: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7952: {
7956:   *fdm = dm->fineMesh;
7957:   return(0);
7958: }

7960: /*@
7961:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

7963:   Input Parameters:
7964: + dm - The DM object
7965: - fdm - The fine DM

7967:   Level: intermediate

7969: .seealso: DMGetFineDM()
7970: @*/
7971: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7972: {

7978:   PetscObjectReference((PetscObject)fdm);
7979:   DMDestroy(&dm->fineMesh);
7980:   dm->fineMesh = fdm;
7981:   return(0);
7982: }

7984: /*=== DMBoundary code ===*/

7986: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7987: {
7988:   PetscInt       d;

7992:   for (d = 0; d < dm->Nds; ++d) {
7993:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7994:   }
7995:   return(0);
7996: }

7998: /*@C
7999:   DMAddBoundary - Add a boundary condition to the model

8001:   Collective on dm

8003:   Input Parameters:
8004: + dm          - The DM, with a PetscDS that matches the problem being constrained
8005: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8006: . name        - The BC name
8007: . labelname   - The label defining constrained points
8008: . field       - The field to constrain
8009: . numcomps    - The number of constrained field components (0 will constrain all fields)
8010: . comps       - An array of constrained component numbers
8011: . bcFunc      - A pointwise function giving boundary values
8012: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8013: . numids      - The number of DMLabel ids for constrained points
8014: . ids         - An array of ids for constrained points
8015: - ctx         - An optional user context for bcFunc

8017:   Options Database Keys:
8018: + -bc_<boundary name> <num> - Overrides the boundary ids
8019: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8021:   Note:
8022:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8024: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8026:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8028: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8029: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8030: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8031: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8033: + dim - the spatial dimension
8034: . Nf - the number of fields
8035: . uOff - the offset into u[] and u_t[] for each field
8036: . uOff_x - the offset into u_x[] for each field
8037: . u - each field evaluated at the current point
8038: . u_t - the time derivative of each field evaluated at the current point
8039: . u_x - the gradient of each field evaluated at the current point
8040: . aOff - the offset into a[] and a_t[] for each auxiliary field
8041: . aOff_x - the offset into a_x[] for each auxiliary field
8042: . a - each auxiliary field evaluated at the current point
8043: . a_t - the time derivative of each auxiliary field evaluated at the current point
8044: . a_x - the gradient of auxiliary each field evaluated at the current point
8045: . t - current time
8046: . x - coordinates of the current point
8047: . numConstants - number of constant parameters
8048: . constants - constant parameters
8049: - bcval - output values at the current point

8051:   Level: developer

8053: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8054: @*/
8055: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
8056: {
8057:   PetscDS        ds;

8066:   DMGetDS(dm, &ds);
8067:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8068:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8069:   return(0);
8070: }

8072: /*@
8073:   DMGetNumBoundary - Get the number of registered BC

8075:   Input Parameters:
8076: . dm - The mesh object

8078:   Output Parameters:
8079: . numBd - The number of BC

8081:   Level: intermediate

8083: .seealso: DMAddBoundary(), DMGetBoundary()
8084: @*/
8085: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8086: {
8087:   PetscDS        ds;

8092:   DMGetDS(dm, &ds);
8093:   PetscDSGetNumBoundary(ds, numBd);
8094:   return(0);
8095: }

8097: /*@C
8098:   DMGetBoundary - Get a model boundary condition

8100:   Input Parameters:
8101: + dm          - The mesh object
8102: - bd          - The BC number

8104:   Output Parameters:
8105: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8106: . name        - The BC name
8107: . labelname   - The label defining constrained points
8108: . field       - The field to constrain
8109: . numcomps    - The number of constrained field components
8110: . comps       - An array of constrained component numbers
8111: . bcFunc      - A pointwise function giving boundary values
8112: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8113: . numids      - The number of DMLabel ids for constrained points
8114: . ids         - An array of ids for constrained points
8115: - ctx         - An optional user context for bcFunc

8117:   Options Database Keys:
8118: + -bc_<boundary name> <num> - Overrides the boundary ids
8119: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8121:   Level: developer

8123: .seealso: DMAddBoundary()
8124: @*/
8125: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
8126: {
8127:   PetscDS        ds;

8132:   DMGetDS(dm, &ds);
8133:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8134:   return(0);
8135: }

8137: static PetscErrorCode DMPopulateBoundary(DM dm)
8138: {
8139:   PetscDS        ds;
8140:   DMBoundary    *lastnext;
8141:   DSBoundary     dsbound;

8145:   DMGetDS(dm, &ds);
8146:   dsbound = ds->boundary;
8147:   if (dm->boundary) {
8148:     DMBoundary next = dm->boundary;

8150:     /* quick check to see if the PetscDS has changed */
8151:     if (next->dsboundary == dsbound) return(0);
8152:     /* the PetscDS has changed: tear down and rebuild */
8153:     while (next) {
8154:       DMBoundary b = next;

8156:       next = b->next;
8157:       PetscFree(b);
8158:     }
8159:     dm->boundary = NULL;
8160:   }

8162:   lastnext = &(dm->boundary);
8163:   while (dsbound) {
8164:     DMBoundary dmbound;

8166:     PetscNew(&dmbound);
8167:     dmbound->dsboundary = dsbound;
8168:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8169:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8170:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8171:     *lastnext = dmbound;
8172:     lastnext = &(dmbound->next);
8173:     dsbound = dsbound->next;
8174:   }
8175:   return(0);
8176: }

8178: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8179: {
8180:   DMBoundary     b;

8186:   *isBd = PETSC_FALSE;
8187:   DMPopulateBoundary(dm);
8188:   b = dm->boundary;
8189:   while (b && !(*isBd)) {
8190:     DMLabel    label = b->label;
8191:     DSBoundary dsb = b->dsboundary;

8193:     if (label) {
8194:       PetscInt i;

8196:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8197:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8198:       }
8199:     }
8200:     b = b->next;
8201:   }
8202:   return(0);
8203: }

8205: /*@C
8206:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8208:   Collective on DM

8210:   Input Parameters:
8211: + dm      - The DM
8212: . time    - The time
8213: . funcs   - The coordinate functions to evaluate, one per field
8214: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8215: - mode    - The insertion mode for values

8217:   Output Parameter:
8218: . X - vector

8220:    Calling sequence of func:
8221: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8223: +  dim - The spatial dimension
8224: .  time - The time at which to sample
8225: .  x   - The coordinates
8226: .  Nf  - The number of fields
8227: .  u   - The output field values
8228: -  ctx - optional user-defined function context

8230:   Level: developer

8232: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8233: @*/
8234: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8235: {
8236:   Vec            localX;

8241:   DMGetLocalVector(dm, &localX);
8242:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8243:   DMLocalToGlobalBegin(dm, localX, mode, X);
8244:   DMLocalToGlobalEnd(dm, localX, mode, X);
8245:   DMRestoreLocalVector(dm, &localX);
8246:   return(0);
8247: }

8249: /*@C
8250:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8252:   Not collective

8254:   Input Parameters:
8255: + dm      - The DM
8256: . time    - The time
8257: . funcs   - The coordinate functions to evaluate, one per field
8258: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8259: - mode    - The insertion mode for values

8261:   Output Parameter:
8262: . localX - vector

8264:    Calling sequence of func:
8265: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8267: +  dim - The spatial dimension
8268: .  x   - The coordinates
8269: .  Nf  - The number of fields
8270: .  u   - The output field values
8271: -  ctx - optional user-defined function context

8273:   Level: developer

8275: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8276: @*/
8277: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8278: {

8284:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8285:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8286:   return(0);
8287: }

8289: /*@C
8290:   DMProjectFunctionLabel - This projects the given function into the function space provided, putting the coefficients in a global vector, setting values only for points in the given label.

8292:   Collective on DM

8294:   Input Parameters:
8295: + dm      - The DM
8296: . time    - The time
8297: . label   - The DMLabel selecting the portion of the mesh for projection
8298: . funcs   - The coordinate functions to evaluate, one per field
8299: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8300: - mode    - The insertion mode for values

8302:   Output Parameter:
8303: . X - vector

8305:    Calling sequence of func:
8306: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8308: +  dim - The spatial dimension
8309: .  x   - The coordinates
8310: .  Nf  - The number of fields
8311: .  u   - The output field values
8312: -  ctx - optional user-defined function context

8314:   Level: developer

8316: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8317: @*/
8318: PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8319: {
8320:   Vec            localX;

8325:   DMGetLocalVector(dm, &localX);
8326:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8327:   DMLocalToGlobalBegin(dm, localX, mode, X);
8328:   DMLocalToGlobalEnd(dm, localX, mode, X);
8329:   DMRestoreLocalVector(dm, &localX);
8330:   return(0);
8331: }

8333: /*@C
8334:   DMProjectFunctionLabelLocal - This projects the given function into the function space provided, putting the coefficients in a local vector, setting values only for points in the given label.

8336:   Not collective

8338:   Input Parameters:
8339: + dm      - The DM
8340: . time    - The time
8341: . label   - The DMLabel selecting the portion of the mesh for projection
8342: . funcs   - The coordinate functions to evaluate, one per field
8343: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8344: - mode    - The insertion mode for values

8346:   Output Parameter:
8347: . localX - vector

8349:    Calling sequence of func:
8350: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8352: +  dim - The spatial dimension
8353: .  x   - The coordinates
8354: .  Nf  - The number of fields
8355: .  u   - The output field values
8356: -  ctx - optional user-defined function context

8358:   Level: developer

8360: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8361: @*/
8362: PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8363: {

8369:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8370:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8371:   return(0);
8372: }

8374: /*@C
8375:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8377:   Not collective

8379:   Input Parameters:
8380: + dm      - The DM
8381: . time    - The time
8382: . localU  - The input field vector
8383: . funcs   - The functions to evaluate, one per field
8384: - mode    - The insertion mode for values

8386:   Output Parameter:
8387: . localX  - The output vector

8389:    Calling sequence of func:
8390: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8391: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8392: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8393: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8395: +  dim          - The spatial dimension
8396: .  Nf           - The number of input fields
8397: .  NfAux        - The number of input auxiliary fields
8398: .  uOff         - The offset of each field in u[]
8399: .  uOff_x       - The offset of each field in u_x[]
8400: .  u            - The field values at this point in space
8401: .  u_t          - The field time derivative at this point in space (or NULL)
8402: .  u_x          - The field derivatives at this point in space
8403: .  aOff         - The offset of each auxiliary field in u[]
8404: .  aOff_x       - The offset of each auxiliary field in u_x[]
8405: .  a            - The auxiliary field values at this point in space
8406: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8407: .  a_x          - The auxiliary field derivatives at this point in space
8408: .  t            - The current time
8409: .  x            - The coordinates of this point
8410: .  numConstants - The number of constants
8411: .  constants    - The value of each constant
8412: -  f            - The value of the function at this point in space

8414:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8415:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8416:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8417:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8419:   Level: intermediate

8421: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8422: @*/
8423: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8424:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8425:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8426:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8427:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8428:                                    InsertMode mode, Vec localX)
8429: {

8436:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8437:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8438:   return(0);
8439: }

8441: /*@C
8442:   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.

8444:   Not collective

8446:   Input Parameters:
8447: + dm      - The DM
8448: . time    - The time
8449: . label   - The DMLabel marking the portion of the domain to output
8450: . numIds  - The number of label ids to use
8451: . ids     - The label ids to use for marking
8452: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8453: . comps   - The components to set in the output, or NULL for all components
8454: . localU  - The input field vector
8455: . funcs   - The functions to evaluate, one per field
8456: - mode    - The insertion mode for values

8458:   Output Parameter:
8459: . localX  - The output vector

8461:    Calling sequence of func:
8462: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8463: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8464: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8465: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8467: +  dim          - The spatial dimension
8468: .  Nf           - The number of input fields
8469: .  NfAux        - The number of input auxiliary fields
8470: .  uOff         - The offset of each field in u[]
8471: .  uOff_x       - The offset of each field in u_x[]
8472: .  u            - The field values at this point in space
8473: .  u_t          - The field time derivative at this point in space (or NULL)
8474: .  u_x          - The field derivatives at this point in space
8475: .  aOff         - The offset of each auxiliary field in u[]
8476: .  aOff_x       - The offset of each auxiliary field in u_x[]
8477: .  a            - The auxiliary field values at this point in space
8478: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8479: .  a_x          - The auxiliary field derivatives at this point in space
8480: .  t            - The current time
8481: .  x            - The coordinates of this point
8482: .  numConstants - The number of constants
8483: .  constants    - The value of each constant
8484: -  f            - The value of the function at this point in space

8486:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8487:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8488:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8489:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8491:   Level: intermediate

8493: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8494: @*/
8495: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8496:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8497:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8498:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8499:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8500:                                         InsertMode mode, Vec localX)
8501: {

8508:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8509:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8510:   return(0);
8511: }

8513: /*@C
8514:   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.

8516:   Not collective

8518:   Input Parameters:
8519: + dm      - The DM
8520: . time    - The time
8521: . label   - The DMLabel marking the portion of the domain boundary to output
8522: . numIds  - The number of label ids to use
8523: . ids     - The label ids to use for marking
8524: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8525: . comps   - The components to set in the output, or NULL for all components
8526: . localU  - The input field vector
8527: . funcs   - The functions to evaluate, one per field
8528: - mode    - The insertion mode for values

8530:   Output Parameter:
8531: . localX  - The output vector

8533:    Calling sequence of func:
8534: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8535: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8536: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8537: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8539: +  dim          - The spatial dimension
8540: .  Nf           - The number of input fields
8541: .  NfAux        - The number of input auxiliary fields
8542: .  uOff         - The offset of each field in u[]
8543: .  uOff_x       - The offset of each field in u_x[]
8544: .  u            - The field values at this point in space
8545: .  u_t          - The field time derivative at this point in space (or NULL)
8546: .  u_x          - The field derivatives at this point in space
8547: .  aOff         - The offset of each auxiliary field in u[]
8548: .  aOff_x       - The offset of each auxiliary field in u_x[]
8549: .  a            - The auxiliary field values at this point in space
8550: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8551: .  a_x          - The auxiliary field derivatives at this point in space
8552: .  t            - The current time
8553: .  x            - The coordinates of this point
8554: .  n            - The face normal
8555: .  numConstants - The number of constants
8556: .  constants    - The value of each constant
8557: -  f            - The value of the function at this point in space

8559:   Note:
8560:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8561:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8562:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8563:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8565:   Level: intermediate

8567: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8568: @*/
8569: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8570:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8571:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8572:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8573:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8574:                                           InsertMode mode, Vec localX)
8575: {

8582:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8583:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8584:   return(0);
8585: }

8587: /*@C
8588:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8590:   Input Parameters:
8591: + dm    - The DM
8592: . time  - The time
8593: . funcs - The functions to evaluate for each field component
8594: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8595: - X     - The coefficient vector u_h, a global vector

8597:   Output Parameter:
8598: . diff - The diff ||u - u_h||_2

8600:   Level: developer

8602: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8603: @*/
8604: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8605: {

8611:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8612:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8613:   return(0);
8614: }

8616: /*@C
8617:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8619:   Collective on dm

8621:   Input Parameters:
8622: + dm    - The DM
8623: , time  - The time
8624: . funcs - The gradient functions to evaluate for each field component
8625: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8626: . X     - The coefficient vector u_h, a global vector
8627: - n     - The vector to project along

8629:   Output Parameter:
8630: . diff - The diff ||(grad u - grad u_h) . n||_2

8632:   Level: developer

8634: .seealso: DMProjectFunction(), DMComputeL2Diff()
8635: @*/
8636: PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
8637: {

8643:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8644:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8645:   return(0);
8646: }

8648: /*@C
8649:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8651:   Collective on dm

8653:   Input Parameters:
8654: + dm    - The DM
8655: . time  - The time
8656: . funcs - The functions to evaluate for each field component
8657: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8658: - X     - The coefficient vector u_h, a global vector

8660:   Output Parameter:
8661: . diff - The array of differences, ||u^f - u^f_h||_2

8663:   Level: developer

8665: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8666: @*/
8667: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8668: {

8674:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8675:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8676:   return(0);
8677: }

8679: /*@C
8680:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8681:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

8683:   Collective on dm

8685:   Input parameters:
8686: + dm - the pre-adaptation DM object
8687: - label - label with the flags

8689:   Output parameters:
8690: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

8692:   Level: intermediate

8694: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8695: @*/
8696: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8697: {

8704:   *dmAdapt = NULL;
8705:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8706:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8707:   return(0);
8708: }

8710: /*@C
8711:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

8713:   Input Parameters:
8714: + dm - The DM object
8715: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8716: - bdLabel - Label for boundary tags, which will be preserved in the output mesh. bdLabel should be NULL if there is no such label, and should be different from "_boundary_".

8718:   Output Parameter:
8719: . dmAdapt  - Pointer to the DM object containing the adapted mesh

8721:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

8723:   Level: advanced

8725: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8726: @*/
8727: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8728: {

8736:   *dmAdapt = NULL;
8737:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8738:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8739:   return(0);
8740: }

8742: /*@C
8743:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

8745:  Not Collective

8747:  Input Parameter:
8748: .  dm    - The DM

8750:  Output Parameters:
8751: +  nranks - the number of neighbours
8752: -  ranks - the neighbors ranks

8754:  Notes:
8755:  Do not free the array, it is freed when the DM is destroyed.

8757:  Level: beginner

8759:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8760: @*/
8761: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8762: {

8767:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8768:   (dm->ops->getneighbors)(dm,nranks,ranks);
8769:   return(0);
8770: }

8772: #include <petsc/private/matimpl.h>

8774: /*
8775:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8776:     This has be a different function because it requires DM which is not defined in the Mat library
8777: */
8778: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8779: {

8783:   if (coloring->ctype == IS_COLORING_LOCAL) {
8784:     Vec x1local;
8785:     DM  dm;
8786:     MatGetDM(J,&dm);
8787:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8788:     DMGetLocalVector(dm,&x1local);
8789:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8790:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8791:     x1   = x1local;
8792:   }
8793:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8794:   if (coloring->ctype == IS_COLORING_LOCAL) {
8795:     DM  dm;
8796:     MatGetDM(J,&dm);
8797:     DMRestoreLocalVector(dm,&x1);
8798:   }
8799:   return(0);
8800: }

8802: /*@
8803:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

8805:     Input Parameter:
8806: .    coloring - the MatFDColoring object

8808:     Developer Notes:
8809:     this routine exists because the PETSc Mat library does not know about the DM objects

8811:     Level: advanced

8813: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8814: @*/
8815: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8816: {
8818:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8819:   return(0);
8820: }

8822: /*@
8823:     DMGetCompatibility - determine if two DMs are compatible

8825:     Collective

8827:     Input Parameters:
8828: +    dm1 - the first DM
8829: -    dm2 - the second DM

8831:     Output Parameters:
8832: +    compatible - whether or not the two DMs are compatible
8833: -    set - whether or not the compatible value was set

8835:     Notes:
8836:     Two DMs are deemed compatible if they represent the same parallel decomposition
8837:     of the same topology. This implies that the section (field data) on one
8838:     "makes sense" with respect to the topology and parallel decomposition of the other.
8839:     Loosely speaking, compatible DMs represent the same domain and parallel
8840:     decomposition, but hold different data.

8842:     Typically, one would confirm compatibility if intending to simultaneously iterate
8843:     over a pair of vectors obtained from different DMs.

8845:     For example, two DMDA objects are compatible if they have the same local
8846:     and global sizes and the same stencil width. They can have different numbers
8847:     of degrees of freedom per node. Thus, one could use the node numbering from
8848:     either DM in bounds for a loop over vectors derived from either DM.

8850:     Consider the operation of summing data living on a 2-dof DMDA to data living
8851:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8852: .vb
8853:   ...
8854:   DMGetCompatibility(da1,da2,&compatible,&set);
8855:   if (set && compatible)  {
8856:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8857:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8858:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8859:     for (j=y; j<y+n; ++j) {
8860:       for (i=x; i<x+m, ++i) {
8861:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8862:       }
8863:     }
8864:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8865:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8866:   } else {
8867:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8868:   }
8869:   ...
8870: .ve

8872:     Checking compatibility might be expensive for a given implementation of DM,
8873:     or might be impossible to unambiguously confirm or deny. For this reason,
8874:     this function may decline to determine compatibility, and hence users should
8875:     always check the "set" output parameter.

8877:     A DM is always compatible with itself.

8879:     In the current implementation, DMs which live on "unequal" communicators
8880:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8881:     incompatible.

8883:     This function is labeled "Collective," as information about all subdomains
8884:     is required on each rank. However, in DM implementations which store all this
8885:     information locally, this function may be merely "Logically Collective".

8887:     Developer Notes:
8888:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8889:     iff B is compatible with A. Thus, this function checks the implementations
8890:     of both dm and dmc (if they are of different types), attempting to determine
8891:     compatibility. It is left to DM implementers to ensure that symmetry is
8892:     preserved. The simplest way to do this is, when implementing type-specific
8893:     logic for this function, is to check for existing logic in the implementation
8894:     of other DM types and let *set = PETSC_FALSE if found.

8896:     Level: advanced

8898: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8899: @*/

8901: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8902: {
8904:   PetscMPIInt    compareResult;
8905:   DMType         type,type2;
8906:   PetscBool      sameType;


8912:   /* Declare a DM compatible with itself */
8913:   if (dm1 == dm2) {
8914:     *set = PETSC_TRUE;
8915:     *compatible = PETSC_TRUE;
8916:     return(0);
8917:   }

8919:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8920:      communicator. Note that this does not preclude compatibility with
8921:      DMs living on "congruent" or "similar" communicators, but this must be
8922:      determined by the implementation-specific logic */
8923:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
8924:   if (compareResult == MPI_UNEQUAL) {
8925:     *set = PETSC_TRUE;
8926:     *compatible = PETSC_FALSE;
8927:     return(0);
8928:   }

8930:   /* Pass to the implementation-specific routine, if one exists. */
8931:   if (dm1->ops->getcompatibility) {
8932:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
8933:     if (*set) return(0);
8934:   }

8936:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8937:      with an implementation of this function from dm2 */
8938:   DMGetType(dm1,&type);
8939:   DMGetType(dm2,&type2);
8940:   PetscStrcmp(type,type2,&sameType);
8941:   if (!sameType && dm2->ops->getcompatibility) {
8942:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
8943:   } else {
8944:     *set = PETSC_FALSE;
8945:   }
8946:   return(0);
8947: }

8949: /*@C
8950:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

8952:   Logically Collective on DM

8954:   Input Parameters:
8955: + DM - the DM
8956: . f - the monitor function
8957: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8958: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

8960:   Options Database Keys:
8961: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8962:                             does not cancel those set via the options database.

8964:   Notes:
8965:   Several different monitoring routines may be set by calling
8966:   DMMonitorSet() multiple times; all will be called in the
8967:   order in which they were set.

8969:   Fortran Notes:
8970:   Only a single monitor function can be set for each DM object

8972:   Level: intermediate

8974: .seealso: DMMonitorCancel()
8975: @*/
8976: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8977: {
8978:   PetscInt       m;

8983:   for (m = 0; m < dm->numbermonitors; ++m) {
8984:     PetscBool identical;

8986:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8987:     if (identical) return(0);
8988:   }
8989:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8990:   dm->monitor[dm->numbermonitors]          = f;
8991:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8992:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8993:   return(0);
8994: }

8996: /*@
8997:   DMMonitorCancel - Clears all the monitor functions for a DM object.

8999:   Logically Collective on DM

9001:   Input Parameter:
9002: . dm - the DM

9004:   Options Database Key:
9005: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9006:   into a code by calls to DMonitorSet(), but does not cancel those
9007:   set via the options database

9009:   Notes:
9010:   There is no way to clear one specific monitor from a DM object.

9012:   Level: intermediate

9014: .seealso: DMMonitorSet()
9015: @*/
9016: PetscErrorCode DMMonitorCancel(DM dm)
9017: {
9019:   PetscInt       m;

9023:   for (m = 0; m < dm->numbermonitors; ++m) {
9024:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9025:   }
9026:   dm->numbermonitors = 0;
9027:   return(0);
9028: }

9030: /*@C
9031:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9033:   Collective on DM

9035:   Input Parameters:
9036: + dm   - DM object you wish to monitor
9037: . name - the monitor type one is seeking
9038: . help - message indicating what monitoring is done
9039: . manual - manual page for the monitor
9040: . monitor - the monitor function
9041: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the DM or PetscViewer objects

9043:   Output Parameter:
9044: . flg - Flag set if the monitor was created

9046:   Level: developer

9048: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9049:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9050:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9051:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9052:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9053:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9054:           PetscOptionsFList(), PetscOptionsEList()
9055: @*/
9056: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9057: {
9058:   PetscViewer       viewer;
9059:   PetscViewerFormat format;
9060:   PetscErrorCode    ierr;

9064:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9065:   if (*flg) {
9066:     PetscViewerAndFormat *vf;

9068:     PetscViewerAndFormatCreate(viewer, format, &vf);
9069:     PetscObjectDereference((PetscObject) viewer);
9070:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9071:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9072:   }
9073:   return(0);
9074: }

9076: /*@
9077:    DMMonitor - runs the user provided monitor routines, if they exist

9079:    Collective on DM

9081:    Input Parameters:
9082: .  dm - The DM

9084:    Level: developer

9086: .seealso: DMMonitorSet()
9087: @*/
9088: PetscErrorCode DMMonitor(DM dm)
9089: {
9090:   PetscInt       m;

9094:   if (!dm) return(0);
9096:   for (m = 0; m < dm->numbermonitors; ++m) {
9097:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9098:   }
9099:   return(0);
9100: }