Actual source code: dm.c

petsc-main 2021-04-20
Report Typos and Errors
  1: #include <petscvec.h>
  2: #include <petsc/private/dmimpl.h>
  3: #include <petsc/private/dmlabelimpl.h>
  4: #include <petsc/private/petscdsimpl.h>
  5: #include <petscdmplex.h>
  6: #include <petscdmfield.h>
  7: #include <petscsf.h>
  8: #include <petscds.h>

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

 14: PetscClassId  DM_CLASSID;
 15: PetscClassId  DMLABEL_CLASSID;
 16: 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;

 18: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
 19: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","ESSENTIAL_BD_FIELD","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
 20: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};

 22: /*@
 23:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

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

 28:   Collective

 30:   Input Parameter:
 31: . comm - The communicator for the DM object

 33:   Output Parameter:
 34: . dm - The DM object

 36:   Level: beginner

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

 48:   *dm = NULL;
 49:   DMInitializePackage();

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

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

 92:   *dm = v;
 93:   return(0);
 94: }

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

 99:   Collective

101:   Input Parameter:
102: . dm - The original DM object

104:   Output Parameter:
105: . newdm  - The new DM object

107:   Level: beginner

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

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

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

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

130:   DMCreate(PetscObjectComm((PetscObject) dm), newdm);
131:   DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
132:   (*newdm)->leveldown  = dm->leveldown;
133:   (*newdm)->levelup    = dm->levelup;
134:   (*newdm)->prealloc_only = dm->prealloc_only;
135:   PetscFree((*newdm)->vectype);
136:   PetscStrallocpy(dm->vectype,(char**)&(*newdm)->vectype);
137:   PetscFree((*newdm)->mattype);
138:   PetscStrallocpy(dm->mattype,(char**)&(*newdm)->mattype);
139:   DMGetDimension(dm, &dim);
140:   DMSetDimension(*newdm, dim);
141:   if (dm->ops->clone) {
142:     (*dm->ops->clone)(dm, newdm);
143:   }
144:   (*newdm)->setupcalled = dm->setupcalled;
145:   DMGetPointSF(dm, &sf);
146:   DMSetPointSF(*newdm, sf);
147:   DMGetApplicationContext(dm, &ctx);
148:   DMSetApplicationContext(*newdm, ctx);
149:   if (dm->coordinateDM) {
150:     DM           ncdm;
151:     PetscSection cs;
152:     PetscInt     pEnd = -1, pEndMax = -1;

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

184:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
185:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
186:   }
187:   return(0);
188: }

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

193:    Logically Collective on da

195:    Input Parameter:
196: +  da - initial distributed array
197: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

199:    Options Database:
200: .   -dm_vec_type ctype

202:    Level: intermediate

204: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
205: @*/
206: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
207: {

212:   PetscFree(da->vectype);
213:   PetscStrallocpy(ctype,(char**)&da->vectype);
214:   return(0);
215: }

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

220:    Logically Collective on da

222:    Input Parameter:
223: .  da - initial distributed array

225:    Output Parameter:
226: .  ctype - the vector type

228:    Level: intermediate

230: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
231: @*/
232: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
233: {
236:   *ctype = da->vectype;
237:   return(0);
238: }

240: /*@
241:   VecGetDM - Gets the DM defining the data layout of the vector

243:   Not collective

245:   Input Parameter:
246: . v - The Vec

248:   Output Parameter:
249: . dm - The DM

251:   Level: intermediate

253: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
254: @*/
255: PetscErrorCode VecGetDM(Vec v, DM *dm)
256: {

262:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
263:   return(0);
264: }

266: /*@
267:   VecSetDM - Sets the DM defining the data layout of the vector.

269:   Not collective

271:   Input Parameters:
272: + v - The Vec
273: - dm - The DM

275:   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.

277:   Level: intermediate

279: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
280: @*/
281: PetscErrorCode VecSetDM(Vec v, DM dm)
282: {

288:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
289:   return(0);
290: }

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

295:    Logically Collective on dm

297:    Input Parameters:
298: +  dm - the DM context
299: -  ctype - the matrix type

301:    Options Database:
302: .   -dm_is_coloring_type - global or local

304:    Level: intermediate

306: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
307:           DMGetISColoringType()
308: @*/
309: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
310: {
313:   dm->coloringtype = ctype;
314:   return(0);
315: }

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

320:    Logically Collective on dm

322:    Input Parameter:
323: .  dm - the DM context

325:    Output Parameter:
326: .  ctype - the matrix type

328:    Options Database:
329: .   -dm_is_coloring_type - global or local

331:    Level: intermediate

333: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
334:           DMGetISColoringType()
335: @*/
336: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
337: {
340:   *ctype = dm->coloringtype;
341:   return(0);
342: }

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

347:    Logically Collective on dm

349:    Input Parameters:
350: +  dm - the DM context
351: -  ctype - the matrix type

353:    Options Database:
354: .   -dm_mat_type ctype

356:    Level: intermediate

358: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
359: @*/
360: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
361: {

366:   PetscFree(dm->mattype);
367:   PetscStrallocpy(ctype,(char**)&dm->mattype);
368:   return(0);
369: }

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

374:    Logically Collective on dm

376:    Input Parameter:
377: .  dm - the DM context

379:    Output Parameter:
380: .  ctype - the matrix type

382:    Options Database:
383: .   -dm_mat_type ctype

385:    Level: intermediate

387: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
388: @*/
389: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
390: {
393:   *ctype = dm->mattype;
394:   return(0);
395: }

397: /*@
398:   MatGetDM - Gets the DM defining the data layout of the matrix

400:   Not collective

402:   Input Parameter:
403: . A - The Mat

405:   Output Parameter:
406: . dm - The DM

408:   Level: intermediate

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

413: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
414: @*/
415: PetscErrorCode MatGetDM(Mat A, DM *dm)
416: {

422:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
423:   return(0);
424: }

426: /*@
427:   MatSetDM - Sets the DM defining the data layout of the matrix

429:   Not collective

431:   Input Parameters:
432: + A - The Mat
433: - dm - The DM

435:   Level: intermediate

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


441: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
442: @*/
443: PetscErrorCode MatSetDM(Mat A, DM dm)
444: {

450:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
451:   return(0);
452: }

454: /*@C
455:    DMSetOptionsPrefix - Sets the prefix used for searching for all
456:    DM options in the database.

458:    Logically Collective on dm

460:    Input Parameter:
461: +  da - the DM context
462: -  prefix - the prefix to prepend to all option names

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

468:    Level: advanced

470: .seealso: DMSetFromOptions()
471: @*/
472: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
473: {

478:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
479:   if (dm->sf) {
480:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
481:   }
482:   if (dm->sectionSF) {
483:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
484:   }
485:   return(0);
486: }

488: /*@C
489:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
490:    DM options in the database.

492:    Logically Collective on dm

494:    Input Parameters:
495: +  dm - the DM context
496: -  prefix - the prefix string to prepend to all DM option requests

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

502:    Level: advanced

504: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
505: @*/
506: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
507: {

512:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
513:   return(0);
514: }

516: /*@C
517:    DMGetOptionsPrefix - Gets the prefix used for searching for all
518:    DM options in the database.

520:    Not Collective

522:    Input Parameters:
523: .  dm - the DM context

525:    Output Parameters:
526: .  prefix - pointer to the prefix string used is returned

528:    Notes:
529:     On the fortran side, the user should pass in a string 'prefix' of
530:    sufficient length to hold the prefix.

532:    Level: advanced

534: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
535: @*/
536: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
537: {

542:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
543:   return(0);
544: }

546: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
547: {
548:   PetscInt       refct = ((PetscObject) dm)->refct;

552:   *ncrefct = 0;
553:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
554:     refct--;
555:     if (recurseCoarse) {
556:       PetscInt coarseCount;

558:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
559:       refct += coarseCount;
560:     }
561:   }
562:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
563:     refct--;
564:     if (recurseFine) {
565:       PetscInt fineCount;

567:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
568:       refct += fineCount;
569:     }
570:   }
571:   *ncrefct = refct;
572:   return(0);
573: }

575: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
576: {
577:   DMLabelLink    next = dm->labels;

581:   /* destroy the labels */
582:   while (next) {
583:     DMLabelLink tmp = next->next;

585:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
586:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
587:     DMLabelDestroy(&next->label);
588:     PetscFree(next);
589:     next = tmp;
590:   }
591:   dm->labels = NULL;
592:   return(0);
593: }

595: /*@C
596:     DMDestroy - Destroys a vector packer or DM.

598:     Collective on dm

600:     Input Parameter:
601: .   dm - the DM object to destroy

603:     Level: developer

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

607: @*/
608: PetscErrorCode  DMDestroy(DM *dm)
609: {
610:   PetscInt       cnt;
611:   DMNamedVecLink nlink,nnext;

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

618:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
619:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
620:   --((PetscObject)(*dm))->refct;
621:   if (--cnt > 0) {*dm = NULL; return(0);}
622:   if (((PetscObject)(*dm))->refct < 0) return(0);
623:   ((PetscObject)(*dm))->refct = 0;

625:   DMClearGlobalVectors(*dm);
626:   DMClearLocalVectors(*dm);

628:   nnext=(*dm)->namedglobal;
629:   (*dm)->namedglobal = NULL;
630:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
631:     nnext = nlink->next;
632:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
633:     PetscFree(nlink->name);
634:     VecDestroy(&nlink->X);
635:     PetscFree(nlink);
636:   }
637:   nnext=(*dm)->namedlocal;
638:   (*dm)->namedlocal = NULL;
639:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
640:     nnext = nlink->next;
641:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
642:     PetscFree(nlink->name);
643:     VecDestroy(&nlink->X);
644:     PetscFree(nlink);
645:   }

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

709:       next = b->next;
710:       PetscFree(b);
711:     }
712:   }

714:   PetscObjectDestroy(&(*dm)->dmksp);
715:   PetscObjectDestroy(&(*dm)->dmsnes);
716:   PetscObjectDestroy(&(*dm)->dmts);

718:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
719:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
720:   }
721:   MatFDColoringDestroy(&(*dm)->fd);
722:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
723:   PetscFree((*dm)->vectype);
724:   PetscFree((*dm)->mattype);

726:   PetscSectionDestroy(&(*dm)->localSection);
727:   PetscSectionDestroy(&(*dm)->globalSection);
728:   PetscLayoutDestroy(&(*dm)->map);
729:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
730:   MatDestroy(&(*dm)->defaultConstraintMat);
731:   PetscSFDestroy(&(*dm)->sf);
732:   PetscSFDestroy(&(*dm)->sectionSF);
733:   if ((*dm)->useNatural) {
734:     if ((*dm)->sfNatural) {
735:       PetscSFDestroy(&(*dm)->sfNatural);
736:     }
737:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
738:   }
739:   {
740:     Vec     *auxData;
741:     PetscInt n, i, off = 0;

743:     PetscHMapAuxGetSize((*dm)->auxData, &n);
744:     PetscMalloc1(n, &auxData);
745:     PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
746:     for (i = 0; i < n; ++i) {VecDestroy(&auxData[i]);}
747:     PetscFree(auxData);
748:     PetscHMapAuxDestroy(&(*dm)->auxData);
749:   }
750:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
751:     DMSetFineDM((*dm)->coarseMesh,NULL);
752:   }

754:   DMDestroy(&(*dm)->coarseMesh);
755:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
756:     DMSetCoarseDM((*dm)->fineMesh,NULL);
757:   }
758:   DMDestroy(&(*dm)->fineMesh);
759:   DMFieldDestroy(&(*dm)->coordinateField);
760:   DMDestroy(&(*dm)->coordinateDM);
761:   VecDestroy(&(*dm)->coordinates);
762:   VecDestroy(&(*dm)->coordinatesLocal);
763:   PetscFree((*dm)->L);
764:   PetscFree((*dm)->maxCell);
765:   PetscFree((*dm)->bdtype);
766:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
767:   DMDestroy(&(*dm)->transformDM);
768:   VecDestroy(&(*dm)->transform);

770:   DMClearDS(*dm);
771:   DMDestroy(&(*dm)->dmBC);
772:   /* if memory was published with SAWs then destroy it */
773:   PetscObjectSAWsViewOff((PetscObject)*dm);

775:   if ((*dm)->ops->destroy) {
776:     (*(*dm)->ops->destroy)(*dm);
777:   }
778:   DMMonitorCancel(*dm);
779:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
780:   PetscHeaderDestroy(dm);
781:   return(0);
782: }

784: /*@
785:     DMSetUp - sets up the data structures inside a DM object

787:     Collective on dm

789:     Input Parameter:
790: .   dm - the DM object to setup

792:     Level: developer

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

796: @*/
797: PetscErrorCode  DMSetUp(DM dm)
798: {

803:   if (dm->setupcalled) return(0);
804:   if (dm->ops->setup) {
805:     (*dm->ops->setup)(dm);
806:   }
807:   dm->setupcalled = PETSC_TRUE;
808:   return(0);
809: }

811: /*@
812:     DMSetFromOptions - sets parameters in a DM from the options database

814:     Collective on dm

816:     Input Parameter:
817: .   dm - the DM object to set options for

819:     Options Database:
820: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
821: .   -dm_vec_type <type>  - type of vector to create inside DM
822: .   -dm_mat_type <type>  - type of matrix to create inside DM
823: -   -dm_is_coloring_type - <global or local>

825:     DMPLEX Specific Checks
826: +   -dm_plex_check_symmetry        - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
827: .   -dm_plex_check_skeleton        - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
828: .   -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()
829: .   -dm_plex_check_geometry        - Check that cells have positive volume - DMPlexCheckGeometry()
830: .   -dm_plex_check_pointsf         - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
831: .   -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
832: -   -dm_plex_check_all             - Perform all the checks above

834:     Level: intermediate

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

839: @*/
840: PetscErrorCode DMSetFromOptions(DM dm)
841: {
842:   char           typeName[256];
843:   PetscBool      flg;

848:   dm->setfromoptionscalled = PETSC_TRUE;
849:   if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
850:   if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
851:   PetscObjectOptionsBegin((PetscObject)dm);
852:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
853:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
854:   if (flg) {
855:     DMSetVecType(dm,typeName);
856:   }
857:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
858:   if (flg) {
859:     DMSetMatType(dm,typeName);
860:   }
861:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
862:   if (dm->ops->setfromoptions) {
863:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
864:   }
865:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
866:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
867:   PetscOptionsEnd();
868:   return(0);
869: }

871: /*@C
872:    DMViewFromOptions - View from Options

874:    Collective on DM

876:    Input Parameters:
877: +  dm - the DM object
878: .  obj - Optional object
879: -  name - command line option

881:    Level: intermediate
882: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
883: @*/
884: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
885: {

890:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
891:   return(0);
892: }

894: /*@C
895:     DMView - Views a DM

897:     Collective on dm

899:     Input Parameter:
900: +   dm - the DM object to view
901: -   v - the viewer

903:     Level: beginner

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

907: @*/
908: PetscErrorCode  DMView(DM dm,PetscViewer v)
909: {
910:   PetscErrorCode    ierr;
911:   PetscBool         isbinary;
912:   PetscMPIInt       size;
913:   PetscViewerFormat format;

917:   if (!v) {
918:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
919:   }
921:   /* Ideally, we would like to have this test on.
922:      However, it currently breaks socket viz via GLVis.
923:      During DMView(parallel_mesh,glvis_viewer), each
924:      process opens a sequential ASCII socket to visualize
925:      the local mesh, and PetscObjectView(dm,local_socket)
926:      is internally called inside VecView_GLVis, incurring
927:      in an error here */
929:   PetscViewerCheckWritable(v);

931:   PetscViewerGetFormat(v,&format);
932:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
933:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
934:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
935:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
936:   if (isbinary) {
937:     PetscInt classid = DM_FILE_CLASSID;
938:     char     type[256];

940:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
941:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
942:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
943:   }
944:   if (dm->ops->view) {
945:     (*dm->ops->view)(dm,v);
946:   }
947:   return(0);
948: }

950: /*@
951:     DMCreateGlobalVector - Creates a global vector from a DM object

953:     Collective on dm

955:     Input Parameter:
956: .   dm - the DM object

958:     Output Parameter:
959: .   vec - the global vector

961:     Level: beginner

963: .seealso DMCreateLocalVector(), DMGetGlobalVector(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

965: @*/
966: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
967: {

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

978:     VecGetDM(*vec,&vdm);
979:     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);
980:   }
981:   return(0);
982: }

984: /*@
985:     DMCreateLocalVector - Creates a local vector from a DM object

987:     Not Collective

989:     Input Parameter:
990: .   dm - the DM object

992:     Output Parameter:
993: .   vec - the local vector

995:     Level: beginner

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

999: @*/
1000: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
1001: {

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

1012:     VecGetDM(*vec,&vdm);
1013:     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);
1014:   }
1015:   return(0);
1016: }

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

1021:    Collective on dm

1023:    Input Parameter:
1024: .  dm - the DM that provides the mapping

1026:    Output Parameter:
1027: .  ltog - the mapping

1029:    Level: intermediate

1031:    Notes:
1032:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1033:    MatSetLocalToGlobalMapping().

1035: .seealso: DMCreateLocalVector()
1036: @*/
1037: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1038: {
1039:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1045:   if (!dm->ltogmap) {
1046:     PetscSection section, sectionGlobal;

1048:     DMGetLocalSection(dm, &section);
1049:     if (section) {
1050:       const PetscInt *cdofs;
1051:       PetscInt       *ltog;
1052:       PetscInt        pStart, pEnd, n, p, k, l;

1054:       DMGetGlobalSection(dm, &sectionGlobal);
1055:       PetscSectionGetChart(section, &pStart, &pEnd);
1056:       PetscSectionGetStorageSize(section, &n);
1057:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1058:       for (p = pStart, l = 0; p < pEnd; ++p) {
1059:         PetscInt bdof, cdof, dof, off, c, cind = 0;

1061:         /* Should probably use constrained dofs */
1062:         PetscSectionGetDof(section, p, &dof);
1063:         PetscSectionGetConstraintDof(section, p, &cdof);
1064:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1065:         PetscSectionGetOffset(sectionGlobal, p, &off);
1066:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1067:         bdof = cdof && (dof-cdof) ? 1 : dof;
1068:         if (dof) {
1069:           if (bs < 0)          {bs = bdof;}
1070:           else if (bs != bdof) {bs = 1;}
1071:         }
1072:         for (c = 0; c < dof; ++c, ++l) {
1073:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1074:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
1075:         }
1076:       }
1077:       /* Must have same blocksize on all procs (some might have no points) */
1078:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1079:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1080:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1081:       else                            {bs = bsMinMax[0];}
1082:       bs = bs < 0 ? 1 : bs;
1083:       /* Must reduce indices by blocksize */
1084:       if (bs > 1) {
1085:         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1086:         n /= bs;
1087:       }
1088:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1089:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1090:     } else {
1091:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1092:       (*dm->ops->getlocaltoglobalmapping)(dm);
1093:     }
1094:   }
1095:   *ltog = dm->ltogmap;
1096:   return(0);
1097: }

1099: /*@
1100:    DMGetBlockSize - Gets the inherent block size associated with a DM

1102:    Not Collective

1104:    Input Parameter:
1105: .  dm - the DM with block structure

1107:    Output Parameter:
1108: .  bs - the block size, 1 implies no exploitable block structure

1110:    Level: intermediate

1112: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1113: @*/
1114: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1115: {
1119:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1120:   *bs = dm->bs;
1121:   return(0);
1122: }

1124: /*@C
1125:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1127:     Collective on dmc

1129:     Input Parameter:
1130: +   dmc - the DM object
1131: -   dmf - the second, finer DM object

1133:     Output Parameter:
1134: +  mat - the interpolation
1135: -  vec - the scaling (optional)

1137:     Level: developer

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

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


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

1149: @*/
1150: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1151: {

1158:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1159:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1160:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1161:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1162:   return(0);
1163: }

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

1168:   Input Parameters:
1169: +      dac - DM that defines a coarse mesh
1170: .      daf - DM that defines a fine mesh
1171: -      mat - the restriction (or interpolation operator) from fine to coarse

1173:   Output Parameter:
1174: .    scale - the scaled vector

1176:   Level: developer

1178: .seealso: DMCreateInterpolation()

1180: @*/
1181: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1182: {
1184:   Vec            fine;
1185:   PetscScalar    one = 1.0;

1188:   DMCreateGlobalVector(daf,&fine);
1189:   DMCreateGlobalVector(dac,scale);
1190:   VecSet(fine,one);
1191:   MatRestrict(mat,fine,*scale);
1192:   VecDestroy(&fine);
1193:   VecReciprocal(*scale);
1194:   return(0);
1195: }

1197: /*@
1198:     DMCreateRestriction - Gets restriction matrix between two DM objects

1200:     Collective on dmc

1202:     Input Parameter:
1203: +   dmc - the DM object
1204: -   dmf - the second, finer DM object

1206:     Output Parameter:
1207: .  mat - the restriction


1210:     Level: developer

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


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

1219: @*/
1220: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1221: {

1228:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1229:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1230:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1231:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1232:   return(0);
1233: }

1235: /*@
1236:     DMCreateInjection - Gets injection matrix between two DM objects

1238:     Collective on dac

1240:     Input Parameter:
1241: +   dac - the DM object
1242: -   daf - the second, finer DM object

1244:     Output Parameter:
1245: .   mat - the injection

1247:     Level: developer

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

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

1255: @*/
1256: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1257: {

1264:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1265:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1266:   (*dac->ops->createinjection)(dac,daf,mat);
1267:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1268:   return(0);
1269: }

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

1274:   Collective on dac

1276:   Input Parameter:
1277: + dac - the DM object
1278: - daf - the second, finer DM object

1280:   Output Parameter:
1281: . mat - the interpolation

1283:   Level: developer

1285: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1286: @*/
1287: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1288: {

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

1300: /*@
1301:     DMCreateColoring - Gets coloring for a DM

1303:     Collective on dm

1305:     Input Parameter:
1306: +   dm - the DM object
1307: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1309:     Output Parameter:
1310: .   coloring - the coloring

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

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

1318:     Level: developer

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

1322: @*/
1323: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1324: {

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

1335: /*@
1336:     DMCreateMatrix - Gets empty Jacobian for a DM

1338:     Collective on dm

1340:     Input Parameter:
1341: .   dm - the DM object

1343:     Output Parameter:
1344: .   mat - the empty Jacobian

1346:     Level: beginner

1348:     Notes:
1349:     This properly preallocates the number of nonzeros in the sparse matrix so you
1350:        do not need to do it yourself.

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

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

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

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

1363: @*/
1364: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1365: {

1371:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1372:   MatInitializePackage();
1373:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1374:   (*dm->ops->creatematrix)(dm,mat);
1375:   if (PetscDefined(USE_DEBUG)) {
1376:     DM mdm;

1378:     MatGetDM(*mat,&mdm);
1379:     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);
1380:   }
1381:   /* Handle nullspace and near nullspace */
1382:   if (dm->Nf) {
1383:     MatNullSpace nullSpace;
1384:     PetscInt     Nf, f;

1386:     DMGetNumFields(dm, &Nf);
1387:     for (f = 0; f < Nf; ++f) {
1388:       if (dm->nullspaceConstructors[f]) {
1389:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1390:         MatSetNullSpace(*mat, nullSpace);
1391:         MatNullSpaceDestroy(&nullSpace);
1392:         break;
1393:       }
1394:     }
1395:     for (f = 0; f < Nf; ++f) {
1396:       if (dm->nearnullspaceConstructors[f]) {
1397:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1398:         MatSetNearNullSpace(*mat, nullSpace);
1399:         MatNullSpaceDestroy(&nullSpace);
1400:       }
1401:     }
1402:   }
1403:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1404:   return(0);
1405: }

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

1411:   Logically Collective on dm

1413:   Input Parameter:
1414: + dm - the DM
1415: - only - PETSC_TRUE if only want preallocation

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

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

1432:   Logically Collective on dm

1434:   Input Parameter:
1435: + dm - the DM
1436: - only - PETSC_TRUE if only want matrix stucture

1438:   Level: developer
1439: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1440: @*/
1441: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1442: {
1445:   dm->structure_only = only;
1446:   return(0);
1447: }

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

1452:   Not Collective

1454:   Input Parameters:
1455: + dm - the DM object
1456: . count - The minium size
1457: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1459:   Output Parameter:
1460: . array - the work array

1462:   Level: developer

1464: .seealso DMDestroy(), DMCreate()
1465: @*/
1466: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1467: {
1469:   DMWorkLink     link;
1470:   PetscMPIInt    dsize;

1475:   if (dm->workin) {
1476:     link       = dm->workin;
1477:     dm->workin = dm->workin->next;
1478:   } else {
1479:     PetscNewLog(dm,&link);
1480:   }
1481:   MPI_Type_size(dtype,&dsize);
1482:   if (((size_t)dsize*count) > link->bytes) {
1483:     PetscFree(link->mem);
1484:     PetscMalloc(dsize*count,&link->mem);
1485:     link->bytes = dsize*count;
1486:   }
1487:   link->next   = dm->workout;
1488:   dm->workout  = link;
1489: #if defined(PETSC_HAVE_VALGRIND)
1490:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1491:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1492: #endif
1493:   *(void**)mem = link->mem;
1494:   return(0);
1495: }

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

1500:   Not Collective

1502:   Input Parameters:
1503: + dm - the DM object
1504: . count - The minium size
1505: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1507:   Output Parameter:
1508: . array - the work array

1510:   Level: developer

1512:   Developer Notes:
1513:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1514: .seealso DMDestroy(), DMCreate()
1515: @*/
1516: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1517: {
1518:   DMWorkLink *p,link;

1523:   for (p=&dm->workout; (link=*p); p=&link->next) {
1524:     if (link->mem == *(void**)mem) {
1525:       *p           = link->next;
1526:       link->next   = dm->workin;
1527:       dm->workin   = link;
1528:       *(void**)mem = NULL;
1529:       return(0);
1530:     }
1531:   }
1532:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1533: }

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

1538:   Logically collective on DM

1540:   Input Parameters:
1541: + dm     - The DM
1542: . field  - The field number for the nullspace
1543: - nullsp - A callback to create the nullspace

1545:   Notes:
1546:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1547: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1548: $ dm        - The present DM
1549: $ origField - The field number given above, in the original DM
1550: $ field     - The field number in dm
1551: $ nullSpace - The nullspace for the given field

1553:   This function is currently not available from Fortran.

1555: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1556: */
1557: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1558: {
1561:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1562:   dm->nullspaceConstructors[field] = nullsp;
1563:   return(0);
1564: }

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

1569:   Not collective

1571:   Input Parameters:
1572: + dm     - The DM
1573: - field  - The field number for the nullspace

1575:   Output Parameter:
1576: . nullsp - A callback to create the nullspace

1578:   Notes:
1579:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1580: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1581: $ dm        - The present DM
1582: $ origField - The field number given above, in the original DM
1583: $ field     - The field number in dm
1584: $ nullSpace - The nullspace for the given field

1586:   This function is currently not available from Fortran.

1588: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1589: */
1590: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1591: {
1595:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1596:   *nullsp = dm->nullspaceConstructors[field];
1597:   return(0);
1598: }

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

1603:   Logically collective on DM

1605:   Input Parameters:
1606: + dm     - The DM
1607: . field  - The field number for the nullspace
1608: - nullsp - A callback to create the near-nullspace

1610:   Notes:
1611:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1612: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1613: $ dm        - The present DM
1614: $ origField - The field number given above, in the original DM
1615: $ field     - The field number in dm
1616: $ nullSpace - The nullspace for the given field

1618:   This function is currently not available from Fortran.

1620: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1621: */
1622: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1623: {
1626:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1627:   dm->nearnullspaceConstructors[field] = nullsp;
1628:   return(0);
1629: }

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

1634:   Not collective

1636:   Input Parameters:
1637: + dm     - The DM
1638: - field  - The field number for the nullspace

1640:   Output Parameter:
1641: . nullsp - A callback to create the near-nullspace

1643:   Notes:
1644:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1645: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1646: $ dm        - The present DM
1647: $ origField - The field number given above, in the original DM
1648: $ field     - The field number in dm
1649: $ nullSpace - The nullspace for the given field

1651:   This function is currently not available from Fortran.

1653: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1654: */
1655: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1656: {
1660:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1661:   *nullsp = dm->nearnullspaceConstructors[field];
1662:   return(0);
1663: }

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

1668:   Not collective

1670:   Input Parameter:
1671: . dm - the DM object

1673:   Output Parameters:
1674: + numFields  - The number of fields (or NULL if not requested)
1675: . fieldNames - The name for each field (or NULL if not requested)
1676: - fields     - The global indices for each field (or NULL if not requested)

1678:   Level: intermediate

1680:   Notes:
1681:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1682:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1683:   PetscFree().

1685: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1686: @*/
1687: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1688: {
1689:   PetscSection   section, sectionGlobal;

1694:   if (numFields) {
1696:     *numFields = 0;
1697:   }
1698:   if (fieldNames) {
1700:     *fieldNames = NULL;
1701:   }
1702:   if (fields) {
1704:     *fields = NULL;
1705:   }
1706:   DMGetLocalSection(dm, &section);
1707:   if (section) {
1708:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1709:     PetscInt nF, f, pStart, pEnd, p;

1711:     DMGetGlobalSection(dm, &sectionGlobal);
1712:     PetscSectionGetNumFields(section, &nF);
1713:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1714:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1715:     for (f = 0; f < nF; ++f) {
1716:       fieldSizes[f] = 0;
1717:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1718:     }
1719:     for (p = pStart; p < pEnd; ++p) {
1720:       PetscInt gdof;

1722:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1723:       if (gdof > 0) {
1724:         for (f = 0; f < nF; ++f) {
1725:           PetscInt fdof, fcdof, fpdof;

1727:           PetscSectionGetFieldDof(section, p, f, &fdof);
1728:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1729:           fpdof = fdof-fcdof;
1730:           if (fpdof && fpdof != fieldNc[f]) {
1731:             /* Layout does not admit a pointwise block size */
1732:             fieldNc[f] = 1;
1733:           }
1734:           fieldSizes[f] += fpdof;
1735:         }
1736:       }
1737:     }
1738:     for (f = 0; f < nF; ++f) {
1739:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1740:       fieldSizes[f] = 0;
1741:     }
1742:     for (p = pStart; p < pEnd; ++p) {
1743:       PetscInt gdof, goff;

1745:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1746:       if (gdof > 0) {
1747:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1748:         for (f = 0; f < nF; ++f) {
1749:           PetscInt fdof, fcdof, fc;

1751:           PetscSectionGetFieldDof(section, p, f, &fdof);
1752:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1753:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1754:             fieldIndices[f][fieldSizes[f]] = goff++;
1755:           }
1756:         }
1757:       }
1758:     }
1759:     if (numFields) *numFields = nF;
1760:     if (fieldNames) {
1761:       PetscMalloc1(nF, fieldNames);
1762:       for (f = 0; f < nF; ++f) {
1763:         const char *fieldName;

1765:         PetscSectionGetFieldName(section, f, &fieldName);
1766:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1767:       }
1768:     }
1769:     if (fields) {
1770:       PetscMalloc1(nF, fields);
1771:       for (f = 0; f < nF; ++f) {
1772:         PetscInt bs, in[2], out[2];

1774:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1775:         in[0] = -fieldNc[f];
1776:         in[1] = fieldNc[f];
1777:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1778:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1779:         ISSetBlockSize((*fields)[f], bs);
1780:       }
1781:     }
1782:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1783:   } else if (dm->ops->createfieldis) {
1784:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1785:   }
1786:   return(0);
1787: }


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

1796:   Not collective

1798:   Input Parameter:
1799: . dm - the DM object

1801:   Output Parameters:
1802: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1803: . namelist  - The name for each field (or NULL if not requested)
1804: . islist    - The global indices for each field (or NULL if not requested)
1805: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1807:   Level: intermediate

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

1814: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1815: @*/
1816: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1817: {

1822:   if (len) {
1824:     *len = 0;
1825:   }
1826:   if (namelist) {
1828:     *namelist = NULL;
1829:   }
1830:   if (islist) {
1832:     *islist = NULL;
1833:   }
1834:   if (dmlist) {
1836:     *dmlist = NULL;
1837:   }
1838:   /*
1839:    Is it a good idea to apply the following check across all impls?
1840:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1841:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1842:    */
1843:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1844:   if (!dm->ops->createfielddecomposition) {
1845:     PetscSection section;
1846:     PetscInt     numFields, f;

1848:     DMGetLocalSection(dm, &section);
1849:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1850:     if (section && numFields && dm->ops->createsubdm) {
1851:       if (len) *len = numFields;
1852:       if (namelist) {PetscMalloc1(numFields,namelist);}
1853:       if (islist)   {PetscMalloc1(numFields,islist);}
1854:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1855:       for (f = 0; f < numFields; ++f) {
1856:         const char *fieldName;

1858:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1859:         if (namelist) {
1860:           PetscSectionGetFieldName(section, f, &fieldName);
1861:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1862:         }
1863:       }
1864:     } else {
1865:       DMCreateFieldIS(dm, len, namelist, islist);
1866:       /* By default there are no DMs associated with subproblems. */
1867:       if (dmlist) *dmlist = NULL;
1868:     }
1869:   } else {
1870:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1871:   }
1872:   return(0);
1873: }

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

1879:   Not collective

1881:   Input Parameters:
1882: + dm        - The DM object
1883: . numFields - The number of fields in this subproblem
1884: - fields    - The field numbers of the selected fields

1886:   Output Parameters:
1887: + is - The global indices for the subproblem
1888: - subdm - The DM for the subproblem

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

1892:   Level: intermediate

1894: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1895: @*/
1896: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1897: {

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

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

1913:   Not collective

1915:   Input Parameter:
1916: + dms - The DM objects
1917: - len - The number of DMs

1919:   Output Parameters:
1920: + is - The global indices for the subproblem, or NULL
1921: - superdm - The DM for the superproblem

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

1925:   Level: intermediate

1927: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1928: @*/
1929: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1930: {
1931:   PetscInt       i;

1939:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1940:   if (len) {
1941:     DM dm = dms[0];
1942:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1943:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1944:   }
1945:   return(0);
1946: }


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

1956:   Not collective

1958:   Input Parameter:
1959: . dm - the DM object

1961:   Output Parameters:
1962: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1963: . namelist    - The name for each subdomain (or NULL if not requested)
1964: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1965: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1966: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1968:   Level: intermediate

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

1975: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1976: @*/
1977: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1978: {
1979:   PetscErrorCode      ierr;
1980:   DMSubDomainHookLink link;
1981:   PetscInt            i,l;

1990:   /*
1991:    Is it a good idea to apply the following check across all impls?
1992:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1993:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1994:    */
1995:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1996:   if (dm->ops->createdomaindecomposition) {
1997:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1998:     /* copy subdomain hooks and context over to the subdomain DMs */
1999:     if (dmlist && *dmlist) {
2000:       for (i = 0; i < l; i++) {
2001:         for (link=dm->subdomainhook; link; link=link->next) {
2002:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
2003:         }
2004:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2005:       }
2006:     }
2007:     if (len) *len = l;
2008:   }
2009:   return(0);
2010: }


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

2016:   Not collective

2018:   Input Parameters:
2019: + dm - the DM object
2020: . n  - the number of subdomain scatters
2021: - subdms - the local subdomains

2023:   Output Parameters:
2024: + n     - the number of scatters returned
2025: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2026: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2027: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

2035:   Level: developer

2037: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2038: @*/
2039: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2040: {

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

2051: /*@
2052:   DMRefine - Refines a DM object

2054:   Collective on dm

2056:   Input Parameter:
2057: + dm   - the DM object
2058: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2060:   Output Parameter:
2061: . dmf - the refined DM, or NULL

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

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

2068:   Level: developer

2070: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2071: @*/
2072: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2073: {
2074:   PetscErrorCode   ierr;
2075:   DMRefineHookLink link;

2079:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2080:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
2081:   (*dm->ops->refine)(dm,comm,dmf);
2082:   if (*dmf) {
2083:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2087:     (*dmf)->ctx       = dm->ctx;
2088:     (*dmf)->leveldown = dm->leveldown;
2089:     (*dmf)->levelup   = dm->levelup + 1;

2091:     DMSetMatType(*dmf,dm->mattype);
2092:     for (link=dm->refinehook; link; link=link->next) {
2093:       if (link->refinehook) {
2094:         (*link->refinehook)(dm,*dmf,link->ctx);
2095:       }
2096:     }
2097:   }
2098:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2099:   return(0);
2100: }

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

2105:    Logically Collective

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

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

2116: +  coarse - coarse level DM
2117: .  fine - fine level DM to interpolate problem to
2118: -  ctx - optional user-defined function context

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

2123: +  coarse - coarse level DM
2124: .  interp - matrix interpolating a coarse-level solution to the finer grid
2125: .  fine - fine level DM to update
2126: -  ctx - optional user-defined function context

2128:    Level: advanced

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

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

2135:    This function is currently not available from Fortran.

2137: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2138: @*/
2139: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2140: {
2141:   PetscErrorCode   ierr;
2142:   DMRefineHookLink link,*p;

2146:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2147:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2148:   }
2149:   PetscNew(&link);
2150:   link->refinehook = refinehook;
2151:   link->interphook = interphook;
2152:   link->ctx        = ctx;
2153:   link->next       = NULL;
2154:   *p               = link;
2155:   return(0);
2156: }

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

2161:    Logically Collective

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

2169:    Level: advanced

2171:    Notes:
2172:    This function does nothing if the hook is not in the list.

2174:    This function is currently not available from Fortran.

2176: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2177: @*/
2178: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2179: {
2180:   PetscErrorCode   ierr;
2181:   DMRefineHookLink link,*p;

2185:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2186:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2187:       link = *p;
2188:       *p = link->next;
2189:       PetscFree(link);
2190:       break;
2191:     }
2192:   }
2193:   return(0);
2194: }

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

2199:    Collective if any hooks are

2201:    Input Arguments:
2202: +  coarse - coarser DM to use as a base
2203: .  interp - interpolation matrix, apply using MatInterpolate()
2204: -  fine - finer DM to update

2206:    Level: developer

2208: .seealso: DMRefineHookAdd(), MatInterpolate()
2209: @*/
2210: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2211: {
2212:   PetscErrorCode   ierr;
2213:   DMRefineHookLink link;

2216:   for (link=fine->refinehook; link; link=link->next) {
2217:     if (link->interphook) {
2218:       (*link->interphook)(coarse,interp,fine,link->ctx);
2219:     }
2220:   }
2221:   return(0);
2222: }

2224: /*@
2225:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2227:    Collective on DM

2229:    Input Arguments:
2230: +  coarse - coarse DM
2231: .  fine   - fine DM
2232: .  interp - (optional) the matrix computed by DMCreateInterpolation().  Implementations may not need this, but if it
2233:             is available it can avoid some recomputation.  If it is provided, MatInterpolate() will be used if
2234:             the coarse DM does not have a specialized implementation.
2235: -  coarseSol - solution on the coarse mesh

2237:    Output Arguments:
2238: .  fineSol - the interpolation of coarseSol to the fine mesh

2240:    Level: developer

2242:    Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2243:    map.  For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2244:    out of the solution vector.  Or if interpolation is inherently a nonlinear operation, such as a method using
2245:    slope-limiting reconstruction.

2247: .seealso DMInterpolate(), DMCreateInterpolation()
2248: @*/
2249: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2250: {
2251:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;


2261:   PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2262:   if (interpsol) {
2263:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2264:   } else if (interp) {
2265:     MatInterpolate(interp, coarseSol, fineSol);
2266:   } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2267:   return(0);
2268: }

2270: /*@
2271:     DMGetRefineLevel - Gets the number of refinements that have generated this DM.

2273:     Not Collective

2275:     Input Parameter:
2276: .   dm - the DM object

2278:     Output Parameter:
2279: .   level - number of refinements

2281:     Level: developer

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

2285: @*/
2286: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2287: {
2290:   *level = dm->levelup;
2291:   return(0);
2292: }

2294: /*@
2295:     DMSetRefineLevel - Sets the number of refinements that have generated this DM.

2297:     Not Collective

2299:     Input Parameter:
2300: +   dm - the DM object
2301: -   level - number of refinements

2303:     Level: advanced

2305:     Notes:
2306:     This value is used by PCMG to determine how many multigrid levels to use

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

2310: @*/
2311: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2312: {
2315:   dm->levelup = level;
2316:   return(0);
2317: }

2319: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2320: {
2324:   *tdm = dm->transformDM;
2325:   return(0);
2326: }

2328: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2329: {
2333:   *tv = dm->transform;
2334:   return(0);
2335: }

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

2340:   Input Parameter:
2341: . dm - The DM

2343:   Output Parameter:
2344: . flg - PETSC_TRUE if a basis transformation should be done

2346:   Level: developer

2348: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2349: @*/
2350: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2351: {
2352:   Vec            tv;

2358:   DMGetBasisTransformVec_Internal(dm, &tv);
2359:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2360:   return(0);
2361: }

2363: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2364: {
2365:   PetscSection   s, ts;
2366:   PetscScalar   *ta;
2367:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2371:   DMGetCoordinateDim(dm, &cdim);
2372:   DMGetLocalSection(dm, &s);
2373:   PetscSectionGetChart(s, &pStart, &pEnd);
2374:   PetscSectionGetNumFields(s, &Nf);
2375:   DMClone(dm, &dm->transformDM);
2376:   DMGetLocalSection(dm->transformDM, &ts);
2377:   PetscSectionSetNumFields(ts, Nf);
2378:   PetscSectionSetChart(ts, pStart, pEnd);
2379:   for (f = 0; f < Nf; ++f) {
2380:     PetscSectionGetFieldComponents(s, f, &Nc);
2381:     /* We could start to label fields by their transformation properties */
2382:     if (Nc != cdim) continue;
2383:     for (p = pStart; p < pEnd; ++p) {
2384:       PetscSectionGetFieldDof(s, p, f, &dof);
2385:       if (!dof) continue;
2386:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2387:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2388:     }
2389:   }
2390:   PetscSectionSetUp(ts);
2391:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2392:   VecGetArray(dm->transform, &ta);
2393:   for (p = pStart; p < pEnd; ++p) {
2394:     for (f = 0; f < Nf; ++f) {
2395:       PetscSectionGetFieldDof(ts, p, f, &dof);
2396:       if (dof) {
2397:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2398:         PetscScalar       *tva;
2399:         const PetscScalar *A;

2401:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2402:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2403:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2404:         PetscArraycpy(tva, A, PetscSqr(cdim));
2405:       }
2406:     }
2407:   }
2408:   VecRestoreArray(dm->transform, &ta);
2409:   return(0);
2410: }

2412: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2413: {

2419:   newdm->transformCtx       = dm->transformCtx;
2420:   newdm->transformSetUp     = dm->transformSetUp;
2421:   newdm->transformDestroy   = NULL;
2422:   newdm->transformGetMatrix = dm->transformGetMatrix;
2423:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2424:   return(0);
2425: }

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

2430:    Logically Collective

2432:    Input Arguments:
2433: +  dm - the DM
2434: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2435: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2436: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2441: +  dm - global DM
2442: .  g - global vector
2443: .  mode - mode
2444: .  l - local vector
2445: -  ctx - optional user-defined function context


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

2451: +  global - global DM
2452: -  ctx - optional user-defined function context

2454:    Level: advanced

2456: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2457: @*/
2458: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2459: {
2460:   PetscErrorCode          ierr;
2461:   DMGlobalToLocalHookLink link,*p;

2465:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2466:   PetscNew(&link);
2467:   link->beginhook = beginhook;
2468:   link->endhook   = endhook;
2469:   link->ctx       = ctx;
2470:   link->next      = NULL;
2471:   *p              = link;
2472:   return(0);
2473: }

2475: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2476: {
2477:   Mat cMat;
2478:   Vec cVec;
2479:   PetscSection section, cSec;
2480:   PetscInt pStart, pEnd, p, dof;

2485:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2486:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2487:     PetscInt nRows;

2489:     MatGetSize(cMat,&nRows,NULL);
2490:     if (nRows <= 0) return(0);
2491:     DMGetLocalSection(dm,&section);
2492:     MatCreateVecs(cMat,NULL,&cVec);
2493:     MatMult(cMat,l,cVec);
2494:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2495:     for (p = pStart; p < pEnd; p++) {
2496:       PetscSectionGetDof(cSec,p,&dof);
2497:       if (dof) {
2498:         PetscScalar *vals;
2499:         VecGetValuesSection(cVec,cSec,p,&vals);
2500:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2501:       }
2502:     }
2503:     VecDestroy(&cVec);
2504:   }
2505:   return(0);
2506: }

2508: /*@
2509:     DMGlobalToLocal - update local vectors from global vector

2511:     Neighbor-wise Collective on dm

2513:     Input Parameters:
2514: +   dm - the DM object
2515: .   g - the global vector
2516: .   mode - INSERT_VALUES or ADD_VALUES
2517: -   l - the local vector

2519:     Notes:
2520:     The communication involved in this update can be overlapped with computation by using
2521:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2523:     Level: beginner

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

2527: @*/
2528: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2529: {

2533:   DMGlobalToLocalBegin(dm,g,mode,l);
2534:   DMGlobalToLocalEnd(dm,g,mode,l);
2535:   return(0);
2536: }

2538: /*@
2539:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2541:     Neighbor-wise Collective on dm

2543:     Input Parameters:
2544: +   dm - the DM object
2545: .   g - the global vector
2546: .   mode - INSERT_VALUES or ADD_VALUES
2547: -   l - the local vector

2549:     Level: intermediate

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

2553: @*/
2554: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2555: {
2556:   PetscSF                 sf;
2557:   PetscErrorCode          ierr;
2558:   DMGlobalToLocalHookLink link;


2563:   for (link=dm->gtolhook; link; link=link->next) {
2564:     if (link->beginhook) {
2565:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2566:     }
2567:   }
2568:   DMGetSectionSF(dm, &sf);
2569:   if (sf) {
2570:     const PetscScalar *gArray;
2571:     PetscScalar       *lArray;
2572:     PetscMemType      lmtype,gmtype;

2574:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2575:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2576:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2577:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2578:     VecRestoreArrayAndMemType(l, &lArray);
2579:     VecRestoreArrayReadAndMemType(g, &gArray);
2580:   } else {
2581:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2582:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2583:   }
2584:   return(0);
2585: }

2587: /*@
2588:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2590:     Neighbor-wise Collective on dm

2592:     Input Parameters:
2593: +   dm - the DM object
2594: .   g - the global vector
2595: .   mode - INSERT_VALUES or ADD_VALUES
2596: -   l - the local vector

2598:     Level: intermediate

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

2602: @*/
2603: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2604: {
2605:   PetscSF                 sf;
2606:   PetscErrorCode          ierr;
2607:   const PetscScalar      *gArray;
2608:   PetscScalar            *lArray;
2609:   PetscBool               transform;
2610:   DMGlobalToLocalHookLink link;
2611:   PetscMemType            lmtype,gmtype;

2615:   DMGetSectionSF(dm, &sf);
2616:   DMHasBasisTransform(dm, &transform);
2617:   if (sf) {
2618:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2620:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2621:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2622:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2623:     VecRestoreArrayAndMemType(l, &lArray);
2624:     VecRestoreArrayReadAndMemType(g, &gArray);
2625:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2626:   } else {
2627:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2628:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2629:   }
2630:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2631:   for (link=dm->gtolhook; link; link=link->next) {
2632:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2633:   }
2634:   return(0);
2635: }

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

2640:    Logically Collective

2642:    Input Arguments:
2643: +  dm - the DM
2644: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2645: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2646: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2651: +  dm - global DM
2652: .  l - local vector
2653: .  mode - mode
2654: .  g - global vector
2655: -  ctx - optional user-defined function context


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

2661: +  global - global DM
2662: .  l - local vector
2663: .  mode - mode
2664: .  g - global vector
2665: -  ctx - optional user-defined function context

2667:    Level: advanced

2669: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2670: @*/
2671: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2672: {
2673:   PetscErrorCode          ierr;
2674:   DMLocalToGlobalHookLink link,*p;

2678:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2679:   PetscNew(&link);
2680:   link->beginhook = beginhook;
2681:   link->endhook   = endhook;
2682:   link->ctx       = ctx;
2683:   link->next      = NULL;
2684:   *p              = link;
2685:   return(0);
2686: }

2688: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2689: {
2690:   Mat cMat;
2691:   Vec cVec;
2692:   PetscSection section, cSec;
2693:   PetscInt pStart, pEnd, p, dof;

2698:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2699:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2700:     PetscInt nRows;

2702:     MatGetSize(cMat,&nRows,NULL);
2703:     if (nRows <= 0) return(0);
2704:     DMGetLocalSection(dm,&section);
2705:     MatCreateVecs(cMat,NULL,&cVec);
2706:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2707:     for (p = pStart; p < pEnd; p++) {
2708:       PetscSectionGetDof(cSec,p,&dof);
2709:       if (dof) {
2710:         PetscInt d;
2711:         PetscScalar *vals;
2712:         VecGetValuesSection(l,section,p,&vals);
2713:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2714:         /* for this to be the true transpose, we have to zero the values that
2715:          * we just extracted */
2716:         for (d = 0; d < dof; d++) {
2717:           vals[d] = 0.;
2718:         }
2719:       }
2720:     }
2721:     MatMultTransposeAdd(cMat,cVec,l,l);
2722:     VecDestroy(&cVec);
2723:   }
2724:   return(0);
2725: }
2726: /*@
2727:     DMLocalToGlobal - updates global vectors from local vectors

2729:     Neighbor-wise Collective on dm

2731:     Input Parameters:
2732: +   dm - the DM object
2733: .   l - the local vector
2734: .   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.
2735: -   g - the global vector

2737:     Notes:
2738:     The communication involved in this update can be overlapped with computation by using
2739:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2744:     Level: beginner

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

2748: @*/
2749: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2750: {

2754:   DMLocalToGlobalBegin(dm,l,mode,g);
2755:   DMLocalToGlobalEnd(dm,l,mode,g);
2756:   return(0);
2757: }

2759: /*@
2760:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2762:     Neighbor-wise Collective on dm

2764:     Input Parameters:
2765: +   dm - the DM object
2766: .   l - the local vector
2767: .   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.
2768: -   g - the global vector

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

2774:     Level: intermediate

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

2778: @*/
2779: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2780: {
2781:   PetscSF                 sf;
2782:   PetscSection            s, gs;
2783:   DMLocalToGlobalHookLink link;
2784:   Vec                     tmpl;
2785:   const PetscScalar      *lArray;
2786:   PetscScalar            *gArray;
2787:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2788:   PetscErrorCode          ierr;
2789:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

2793:   for (link=dm->ltoghook; link; link=link->next) {
2794:     if (link->beginhook) {
2795:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2796:     }
2797:   }
2798:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2799:   DMGetSectionSF(dm, &sf);
2800:   DMGetLocalSection(dm, &s);
2801:   switch (mode) {
2802:   case INSERT_VALUES:
2803:   case INSERT_ALL_VALUES:
2804:   case INSERT_BC_VALUES:
2805:     isInsert = PETSC_TRUE; break;
2806:   case ADD_VALUES:
2807:   case ADD_ALL_VALUES:
2808:   case ADD_BC_VALUES:
2809:     isInsert = PETSC_FALSE; break;
2810:   default:
2811:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2812:   }
2813:   if ((sf && !isInsert) || (s && isInsert)) {
2814:     DMHasBasisTransform(dm, &transform);
2815:     if (transform) {
2816:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2817:       VecCopy(l, tmpl);
2818:       DMPlexLocalToGlobalBasis(dm, tmpl);
2819:       VecGetArrayRead(tmpl, &lArray);
2820:     } else if (isInsert) {
2821:       VecGetArrayRead(l, &lArray);
2822:     } else {
2823:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2824:       l_inplace = PETSC_TRUE;
2825:     }
2826:     if (s && isInsert) {
2827:       VecGetArray(g, &gArray);
2828:     } else {
2829:       VecGetArrayAndMemType(g, &gArray, &gmtype);
2830:       g_inplace = PETSC_TRUE;
2831:     }
2832:     if (sf && !isInsert) {
2833:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2834:     } else if (s && isInsert) {
2835:       PetscInt gStart, pStart, pEnd, p;

2837:       DMGetGlobalSection(dm, &gs);
2838:       PetscSectionGetChart(s, &pStart, &pEnd);
2839:       VecGetOwnershipRange(g, &gStart, NULL);
2840:       for (p = pStart; p < pEnd; ++p) {
2841:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2843:         PetscSectionGetDof(s, p, &dof);
2844:         PetscSectionGetDof(gs, p, &gdof);
2845:         PetscSectionGetConstraintDof(s, p, &cdof);
2846:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2847:         PetscSectionGetOffset(s, p, &off);
2848:         PetscSectionGetOffset(gs, p, &goff);
2849:         /* Ignore off-process data and points with no global data */
2850:         if (!gdof || goff < 0) continue;
2851:         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);
2852:         /* If no constraints are enforced in the global vector */
2853:         if (!gcdof) {
2854:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2855:           /* If constraints are enforced in the global vector */
2856:         } else if (cdof == gcdof) {
2857:           const PetscInt *cdofs;
2858:           PetscInt        cind = 0;

2860:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2861:           for (d = 0, e = 0; d < dof; ++d) {
2862:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2863:             gArray[goff-gStart+e++] = lArray[off+d];
2864:           }
2865:         } 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);
2866:       }
2867:     }
2868:     if (g_inplace) {
2869:       VecRestoreArrayAndMemType(g, &gArray);
2870:     } else {
2871:       VecRestoreArray(g, &gArray);
2872:     }
2873:     if (transform) {
2874:       VecRestoreArrayRead(tmpl, &lArray);
2875:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2876:     } else if (l_inplace) {
2877:       VecRestoreArrayReadAndMemType(l, &lArray);
2878:     } else {
2879:       VecRestoreArrayRead(l, &lArray);
2880:     }
2881:   } else {
2882:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2883:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2884:   }
2885:   return(0);
2886: }

2888: /*@
2889:     DMLocalToGlobalEnd - updates global vectors from local vectors

2891:     Neighbor-wise Collective on dm

2893:     Input Parameters:
2894: +   dm - the DM object
2895: .   l - the local vector
2896: .   mode - INSERT_VALUES or ADD_VALUES
2897: -   g - the global vector

2899:     Level: intermediate

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

2903: @*/
2904: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2905: {
2906:   PetscSF                 sf;
2907:   PetscSection            s;
2908:   DMLocalToGlobalHookLink link;
2909:   PetscBool               isInsert, transform;
2910:   PetscErrorCode          ierr;

2914:   DMGetSectionSF(dm, &sf);
2915:   DMGetLocalSection(dm, &s);
2916:   switch (mode) {
2917:   case INSERT_VALUES:
2918:   case INSERT_ALL_VALUES:
2919:     isInsert = PETSC_TRUE; break;
2920:   case ADD_VALUES:
2921:   case ADD_ALL_VALUES:
2922:     isInsert = PETSC_FALSE; break;
2923:   default:
2924:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2925:   }
2926:   if (sf && !isInsert) {
2927:     const PetscScalar *lArray;
2928:     PetscScalar       *gArray;
2929:     Vec                tmpl;

2931:     DMHasBasisTransform(dm, &transform);
2932:     if (transform) {
2933:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2934:       VecGetArrayRead(tmpl, &lArray);
2935:     } else {
2936:       VecGetArrayReadAndMemType(l, &lArray, NULL);
2937:     }
2938:     VecGetArrayAndMemType(g, &gArray, NULL);
2939:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2940:     if (transform) {
2941:       VecRestoreArrayRead(tmpl, &lArray);
2942:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2943:     } else {
2944:       VecRestoreArrayReadAndMemType(l, &lArray);
2945:     }
2946:     VecRestoreArrayAndMemType(g, &gArray);
2947:   } else if (s && isInsert) {
2948:   } else {
2949:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2950:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2951:   }
2952:   for (link=dm->ltoghook; link; link=link->next) {
2953:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2954:   }
2955:   return(0);
2956: }

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

2963:    Neighbor-wise Collective on dm

2965:    Input Parameters:
2966: +  dm - the DM object
2967: .  g - the original local vector
2968: -  mode - one of INSERT_VALUES or ADD_VALUES

2970:    Output Parameter:
2971: .  l  - the local vector with correct ghost values

2973:    Level: intermediate

2975:    Notes:
2976:    The local vectors used here need not be the same as those
2977:    obtained from DMCreateLocalVector(), BUT they
2978:    must have the same parallel data layout; they could, for example, be
2979:    obtained with VecDuplicate() from the DM originating vectors.

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

2983: @*/
2984: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2985: {
2986:   PetscErrorCode          ierr;

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

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

3000:    Neighbor-wise Collective on dm

3002:    Input Parameters:
3003: +  da - the DM object
3004: .  g - the original local vector
3005: -  mode - one of INSERT_VALUES or ADD_VALUES

3007:    Output Parameter:
3008: .  l  - the local vector with correct ghost values

3010:    Level: intermediate

3012:    Notes:
3013:    The local vectors used here need not be the same as those
3014:    obtained from DMCreateLocalVector(), BUT they
3015:    must have the same parallel data layout; they could, for example, be
3016:    obtained with VecDuplicate() from the DM originating vectors.

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

3020: @*/
3021: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3022: {
3023:   PetscErrorCode          ierr;

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


3033: /*@
3034:     DMCoarsen - Coarsens a DM object

3036:     Collective on dm

3038:     Input Parameter:
3039: +   dm - the DM object
3040: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

3042:     Output Parameter:
3043: .   dmc - the coarsened DM

3045:     Level: developer

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

3049: @*/
3050: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3051: {
3052:   PetscErrorCode    ierr;
3053:   DMCoarsenHookLink link;

3057:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
3058:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3059:   (*dm->ops->coarsen)(dm, comm, dmc);
3060:   if (*dmc) {
3061:     DMSetCoarseDM(dm,*dmc);
3062:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3063:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3064:     (*dmc)->ctx               = dm->ctx;
3065:     (*dmc)->levelup           = dm->levelup;
3066:     (*dmc)->leveldown         = dm->leveldown + 1;
3067:     DMSetMatType(*dmc,dm->mattype);
3068:     for (link=dm->coarsenhook; link; link=link->next) {
3069:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3070:     }
3071:   }
3072:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3073:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3074:   return(0);
3075: }

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

3080:    Logically Collective

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

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

3091: +  fine - fine level DM
3092: .  coarse - coarse level DM to restrict problem to
3093: -  ctx - optional user-defined function context

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

3098: +  fine - fine level DM
3099: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
3100: .  rscale - scaling vector for restriction
3101: .  inject - matrix restricting by injection
3102: .  coarse - coarse level DM to update
3103: -  ctx - optional user-defined function context

3105:    Level: advanced

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

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

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

3115:    This function is currently not available from Fortran.

3117: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3118: @*/
3119: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3120: {
3121:   PetscErrorCode    ierr;
3122:   DMCoarsenHookLink link,*p;

3126:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3127:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3128:   }
3129:   PetscNew(&link);
3130:   link->coarsenhook  = coarsenhook;
3131:   link->restricthook = restricthook;
3132:   link->ctx          = ctx;
3133:   link->next         = NULL;
3134:   *p                 = link;
3135:   return(0);
3136: }

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

3141:    Logically Collective

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

3149:    Level: advanced

3151:    Notes:
3152:    This function does nothing if the hook is not in the list.

3154:    This function is currently not available from Fortran.

3156: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3157: @*/
3158: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3159: {
3160:   PetscErrorCode    ierr;
3161:   DMCoarsenHookLink link,*p;

3165:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3166:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3167:       link = *p;
3168:       *p = link->next;
3169:       PetscFree(link);
3170:       break;
3171:     }
3172:   }
3173:   return(0);
3174: }


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

3180:    Collective if any hooks are

3182:    Input Arguments:
3183: +  fine - finer DM to use as a base
3184: .  restrct - restriction matrix, apply using MatRestrict()
3185: .  rscale - scaling vector for restriction
3186: .  inject - injection matrix, also use MatRestrict()
3187: -  coarse - coarser DM to update

3189:    Level: developer

3191: .seealso: DMCoarsenHookAdd(), MatRestrict()
3192: @*/
3193: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3194: {
3195:   PetscErrorCode    ierr;
3196:   DMCoarsenHookLink link;

3199:   for (link=fine->coarsenhook; link; link=link->next) {
3200:     if (link->restricthook) {
3201:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3202:     }
3203:   }
3204:   return(0);
3205: }

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

3210:    Logically Collective on global

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


3219:    Calling sequence for ddhook:
3220: $    ddhook(DM global,DM block,void *ctx)

3222: +  global - global DM
3223: .  block  - block DM
3224: -  ctx - optional user-defined function context

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

3229: +  global - global DM
3230: .  out    - scatter to the outer (with ghost and overlap points) block vector
3231: .  in     - scatter to block vector values only owned locally
3232: .  block  - block DM
3233: -  ctx - optional user-defined function context

3235:    Level: advanced

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

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

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

3245:    This function is currently not available from Fortran.

3247: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3248: @*/
3249: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3250: {
3251:   PetscErrorCode      ierr;
3252:   DMSubDomainHookLink link,*p;

3256:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3257:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3258:   }
3259:   PetscNew(&link);
3260:   link->restricthook = restricthook;
3261:   link->ddhook       = ddhook;
3262:   link->ctx          = ctx;
3263:   link->next         = NULL;
3264:   *p                 = link;
3265:   return(0);
3266: }

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

3271:    Logically Collective

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

3279:    Level: advanced

3281:    Notes:

3283:    This function is currently not available from Fortran.

3285: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3286: @*/
3287: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3288: {
3289:   PetscErrorCode      ierr;
3290:   DMSubDomainHookLink link,*p;

3294:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3295:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3296:       link = *p;
3297:       *p = link->next;
3298:       PetscFree(link);
3299:       break;
3300:     }
3301:   }
3302:   return(0);
3303: }

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

3308:    Collective if any hooks are

3310:    Input Arguments:
3311: +  fine - finer DM to use as a base
3312: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3313: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3314: -  coarse - coarer DM to update

3316:    Level: developer

3318: .seealso: DMCoarsenHookAdd(), MatRestrict()
3319: @*/
3320: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3321: {
3322:   PetscErrorCode      ierr;
3323:   DMSubDomainHookLink link;

3326:   for (link=global->subdomainhook; link; link=link->next) {
3327:     if (link->restricthook) {
3328:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3329:     }
3330:   }
3331:   return(0);
3332: }

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

3337:     Not Collective

3339:     Input Parameter:
3340: .   dm - the DM object

3342:     Output Parameter:
3343: .   level - number of coarsenings

3345:     Level: developer

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

3349: @*/
3350: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3351: {
3355:   *level = dm->leveldown;
3356:   return(0);
3357: }

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

3362:     Not Collective

3364:     Input Parameters:
3365: +   dm - the DM object
3366: -   level - number of coarsenings

3368:     Level: developer

3370: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3371: @*/
3372: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3373: {
3376:   dm->leveldown = level;
3377:   return(0);
3378: }



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

3385:     Collective on dm

3387:     Input Parameter:
3388: +   dm - the DM object
3389: -   nlevels - the number of levels of refinement

3391:     Output Parameter:
3392: .   dmf - the refined DM hierarchy

3394:     Level: developer

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

3398: @*/
3399: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3400: {

3405:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3406:   if (nlevels == 0) return(0);
3408:   if (dm->ops->refinehierarchy) {
3409:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3410:   } else if (dm->ops->refine) {
3411:     PetscInt i;

3413:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3414:     for (i=1; i<nlevels; i++) {
3415:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3416:     }
3417:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3418:   return(0);
3419: }

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

3424:     Collective on dm

3426:     Input Parameter:
3427: +   dm - the DM object
3428: -   nlevels - the number of levels of coarsening

3430:     Output Parameter:
3431: .   dmc - the coarsened DM hierarchy

3433:     Level: developer

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

3437: @*/
3438: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3439: {

3444:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3445:   if (nlevels == 0) return(0);
3447:   if (dm->ops->coarsenhierarchy) {
3448:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3449:   } else if (dm->ops->coarsen) {
3450:     PetscInt i;

3452:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3453:     for (i=1; i<nlevels; i++) {
3454:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3455:     }
3456:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3457:   return(0);
3458: }

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

3463:     Not Collective

3465:     Input Parameters:
3466: +   dm - the DM object
3467: -   destroy - the destroy function

3469:     Level: intermediate

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

3473: @*/
3474: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3475: {
3478:   dm->ctxdestroy = destroy;
3479:   return(0);
3480: }

3482: /*@
3483:     DMSetApplicationContext - Set a user context into a DM object

3485:     Not Collective

3487:     Input Parameters:
3488: +   dm - the DM object
3489: -   ctx - the user context

3491:     Level: intermediate

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

3495: @*/
3496: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3497: {
3500:   dm->ctx = ctx;
3501:   return(0);
3502: }

3504: /*@
3505:     DMGetApplicationContext - Gets a user context from a DM object

3507:     Not Collective

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

3512:     Output Parameter:
3513: .   ctx - the user context

3515:     Level: intermediate

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

3519: @*/
3520: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3521: {
3524:   *(void**)ctx = dm->ctx;
3525:   return(0);
3526: }

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

3531:     Logically Collective on dm

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

3537:     Level: intermediate

3539: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3540:          DMSetJacobian()

3542: @*/
3543: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3544: {
3547:   dm->ops->computevariablebounds = f;
3548:   return(0);
3549: }

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

3554:     Not Collective

3556:     Input Parameter:
3557: .   dm - the DM object to destroy

3559:     Output Parameter:
3560: .   flg - PETSC_TRUE if the variable bounds function exists

3562:     Level: developer

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

3566: @*/
3567: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3568: {
3572:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3573:   return(0);
3574: }

3576: /*@C
3577:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3579:     Logically Collective on dm

3581:     Input Parameters:
3582: .   dm - the DM object

3584:     Output parameters:
3585: +   xl - lower bound
3586: -   xu - upper bound

3588:     Level: advanced

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

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

3595: @*/
3596: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3597: {

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

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

3612:     Not Collective

3614:     Input Parameter:
3615: .   dm - the DM object

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

3620:     Level: developer

3622: .seealso DMCreateColoring()

3624: @*/
3625: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3626: {
3630:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3631:   return(0);
3632: }

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

3637:     Not Collective

3639:     Input Parameter:
3640: .   dm - the DM object

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

3645:     Level: developer

3647: .seealso DMCreateRestriction()

3649: @*/
3650: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3651: {
3655:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3656:   return(0);
3657: }


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

3663:     Not Collective

3665:     Input Parameter:
3666: .   dm - the DM object

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

3671:     Level: developer

3673: .seealso DMCreateInjection()

3675: @*/
3676: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3677: {

3683:   if (dm->ops->hascreateinjection) {
3684:     (*dm->ops->hascreateinjection)(dm,flg);
3685:   } else {
3686:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3687:   }
3688:   return(0);
3689: }

3691: PetscFunctionList DMList              = NULL;
3692: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3694: /*@C
3695:   DMSetType - Builds a DM, for a particular DM implementation.

3697:   Collective on dm

3699:   Input Parameters:
3700: + dm     - The DM object
3701: - method - The name of the DM type

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

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

3709:   Level: intermediate

3711: .seealso: DMGetType(), DMCreate()
3712: @*/
3713: PetscErrorCode  DMSetType(DM dm, DMType method)
3714: {
3715:   PetscErrorCode (*r)(DM);
3716:   PetscBool      match;

3721:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3722:   if (match) return(0);

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

3728:   if (dm->ops->destroy) {
3729:     (*dm->ops->destroy)(dm);
3730:   }
3731:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3732:   PetscObjectChangeTypeName((PetscObject)dm,method);
3733:   (*r)(dm);
3734:   return(0);
3735: }

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

3740:   Not Collective

3742:   Input Parameter:
3743: . dm  - The DM

3745:   Output Parameter:
3746: . type - The DM type name

3748:   Level: intermediate

3750: .seealso: DMSetType(), DMCreate()
3751: @*/
3752: PetscErrorCode  DMGetType(DM dm, DMType *type)
3753: {

3759:   DMRegisterAll();
3760:   *type = ((PetscObject)dm)->type_name;
3761:   return(0);
3762: }

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

3767:   Collective on dm

3769:   Input Parameters:
3770: + dm - the DM
3771: - newtype - new DM type (use "same" for the same type)

3773:   Output Parameter:
3774: . M - pointer to new DM

3776:   Notes:
3777:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3778:   the MPI communicator of the generated DM is always the same as the communicator
3779:   of the input DM.

3781:   Level: intermediate

3783: .seealso: DMCreate()
3784: @*/
3785: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3786: {
3787:   DM             B;
3788:   char           convname[256];
3789:   PetscBool      sametype/*, issame */;

3796:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3797:   /* PetscStrcmp(newtype, "same", &issame); */
3798:   if (sametype) {
3799:     *M   = dm;
3800:     PetscObjectReference((PetscObject) dm);
3801:     return(0);
3802:   } else {
3803:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3805:     /*
3806:        Order of precedence:
3807:        1) See if a specialized converter is known to the current DM.
3808:        2) See if a specialized converter is known to the desired DM class.
3809:        3) See if a good general converter is registered for the desired class
3810:        4) See if a good general converter is known for the current matrix.
3811:        5) Use a really basic converter.
3812:     */

3814:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3815:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3816:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3817:     PetscStrlcat(convname,"_",sizeof(convname));
3818:     PetscStrlcat(convname,newtype,sizeof(convname));
3819:     PetscStrlcat(convname,"_C",sizeof(convname));
3820:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3821:     if (conv) goto foundconv;

3823:     /* 2)  See if a specialized converter is known to the desired DM class. */
3824:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3825:     DMSetType(B, newtype);
3826:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3827:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3828:     PetscStrlcat(convname,"_",sizeof(convname));
3829:     PetscStrlcat(convname,newtype,sizeof(convname));
3830:     PetscStrlcat(convname,"_C",sizeof(convname));
3831:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3832:     if (conv) {
3833:       DMDestroy(&B);
3834:       goto foundconv;
3835:     }

3837: #if 0
3838:     /* 3) See if a good general converter is registered for the desired class */
3839:     conv = B->ops->convertfrom;
3840:     DMDestroy(&B);
3841:     if (conv) goto foundconv;

3843:     /* 4) See if a good general converter is known for the current matrix */
3844:     if (dm->ops->convert) {
3845:       conv = dm->ops->convert;
3846:     }
3847:     if (conv) goto foundconv;
3848: #endif

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

3853: foundconv:
3854:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3855:     (*conv)(dm,newtype,M);
3856:     /* Things that are independent of DM type: We should consult DMClone() here */
3857:     {
3858:       PetscBool             isper;
3859:       const PetscReal      *maxCell, *L;
3860:       const DMBoundaryType *bd;
3861:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3862:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3863:       (*M)->prealloc_only = dm->prealloc_only;
3864:       PetscFree((*M)->vectype);
3865:       PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3866:       PetscFree((*M)->mattype);
3867:       PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3868:     }
3869:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3870:   }
3871:   PetscObjectStateIncrease((PetscObject) *M);
3872:   return(0);
3873: }

3875: /*--------------------------------------------------------------------------------------------------------------------*/

3877: /*@C
3878:   DMRegister -  Adds a new DM component implementation

3880:   Not Collective

3882:   Input Parameters:
3883: + name        - The name of a new user-defined creation routine
3884: - create_func - The creation routine itself

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


3890:   Sample usage:
3891: .vb
3892:     DMRegister("my_da", MyDMCreate);
3893: .ve

3895:   Then, your DM type can be chosen with the procedural interface via
3896: .vb
3897:     DMCreate(MPI_Comm, DM *);
3898:     DMSetType(DM,"my_da");
3899: .ve
3900:    or at runtime via the option
3901: .vb
3902:     -da_type my_da
3903: .ve

3905:   Level: advanced

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

3909: @*/
3910: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3911: {

3915:   DMInitializePackage();
3916:   PetscFunctionListAdd(&DMList,sname,function);
3917:   return(0);
3918: }

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

3923:   Collective on viewer

3925:   Input Parameters:
3926: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3927:            some related function before a call to DMLoad().
3928: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3929:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3931:    Level: intermediate

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

3936:   Notes for advanced users:
3937:   Most users should not need to know the details of the binary storage
3938:   format, since DMLoad() and DMView() completely hide these details.
3939:   But for anyone who's interested, the standard binary matrix storage
3940:   format is
3941: .vb
3942:      has not yet been determined
3943: .ve

3945: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3946: @*/
3947: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3948: {
3949:   PetscBool      isbinary, ishdf5;

3955:   PetscViewerCheckReadable(viewer);
3956:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3957:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3958:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3959:   if (isbinary) {
3960:     PetscInt classid;
3961:     char     type[256];

3963:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3964:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3965:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3966:     DMSetType(newdm, type);
3967:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3968:   } else if (ishdf5) {
3969:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3970:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3971:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3972:   return(0);
3973: }

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

3978:   Not collective

3980:   Input Parameter:
3981: . dm - the DM

3983:   Output Parameters:
3984: + lmin - local minimum coordinates (length coord dim, optional)
3985: - lmax - local maximim coordinates (length coord dim, optional)

3987:   Level: beginner

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


3992: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3993: @*/
3994: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3995: {
3996:   Vec                coords = NULL;
3997:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3998:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3999:   const PetscScalar *local_coords;
4000:   PetscInt           N, Ni;
4001:   PetscInt           cdim, i, j;
4002:   PetscErrorCode     ierr;

4006:   DMGetCoordinateDim(dm, &cdim);
4007:   DMGetCoordinates(dm, &coords);
4008:   if (coords) {
4009:     VecGetArrayRead(coords, &local_coords);
4010:     VecGetLocalSize(coords, &N);
4011:     Ni   = N/cdim;
4012:     for (i = 0; i < Ni; ++i) {
4013:       for (j = 0; j < 3; ++j) {
4014:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4015:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4016:       }
4017:     }
4018:     VecRestoreArrayRead(coords, &local_coords);
4019:   } else {
4020:     PetscBool isda;

4022:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4023:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4024:   }
4025:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
4026:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
4027:   return(0);
4028: }

4030: /*@
4031:   DMGetBoundingBox - Returns the global bounding box for the DM.

4033:   Collective

4035:   Input Parameter:
4036: . dm - the DM

4038:   Output Parameters:
4039: + gmin - global minimum coordinates (length coord dim, optional)
4040: - gmax - global maximim coordinates (length coord dim, optional)

4042:   Level: beginner

4044: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4045: @*/
4046: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4047: {
4048:   PetscReal      lmin[3], lmax[3];
4049:   PetscInt       cdim;
4050:   PetscMPIInt    count;

4055:   DMGetCoordinateDim(dm, &cdim);
4056:   PetscMPIIntCast(cdim, &count);
4057:   DMGetLocalBoundingBox(dm, lmin, lmax);
4058:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4059:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4060:   return(0);
4061: }

4063: /******************************** FEM Support **********************************/

4065: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4066: {
4067:   PetscInt       f;

4071:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4072:   for (f = 0; f < len; ++f) {
4073:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
4074:   }
4075:   return(0);
4076: }

4078: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4079: {
4080:   PetscInt       f, g;

4084:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4085:   for (f = 0; f < rows; ++f) {
4086:     PetscPrintf(PETSC_COMM_SELF, "  |");
4087:     for (g = 0; g < cols; ++g) {
4088:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4089:     }
4090:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4091:   }
4092:   return(0);
4093: }

4095: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4096: {
4097:   PetscInt          localSize, bs;
4098:   PetscMPIInt       size;
4099:   Vec               x, xglob;
4100:   const PetscScalar *xarray;
4101:   PetscErrorCode    ierr;

4104:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4105:   VecDuplicate(X, &x);
4106:   VecCopy(X, x);
4107:   VecChop(x, tol);
4108:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4109:   if (size > 1) {
4110:     VecGetLocalSize(x,&localSize);
4111:     VecGetArrayRead(x,&xarray);
4112:     VecGetBlockSize(x,&bs);
4113:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4114:   } else {
4115:     xglob = x;
4116:   }
4117:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4118:   if (size > 1) {
4119:     VecDestroy(&xglob);
4120:     VecRestoreArrayRead(x,&xarray);
4121:   }
4122:   VecDestroy(&x);
4123:   return(0);
4124: }

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

4129:   Input Parameter:
4130: . dm - The DM

4132:   Output Parameter:
4133: . section - The PetscSection

4135:   Options Database Keys:
4136: . -dm_petscsection_view - View the Section created by the DM

4138:   Level: advanced

4140:   Notes:
4141:   Use DMGetLocalSection() in new code.

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

4145: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4146: @*/
4147: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4148: {

4152:   DMGetLocalSection(dm,section);
4153:   return(0);
4154: }

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

4159:   Input Parameter:
4160: . dm - The DM

4162:   Output Parameter:
4163: . section - The PetscSection

4165:   Options Database Keys:
4166: . -dm_petscsection_view - View the Section created by the DM

4168:   Level: intermediate

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

4172: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4173: @*/
4174: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4175: {

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

4184:     if (dm->setfromoptionscalled) {
4185:       PetscObject       obj = (PetscObject) dm;
4186:       PetscViewer       viewer;
4187:       PetscViewerFormat format;
4188:       PetscBool         flg;

4190:       PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4191:       if (flg) {PetscViewerPushFormat(viewer, format);}
4192:       for (d = 0; d < dm->Nds; ++d) {
4193:         PetscDSSetFromOptions(dm->probs[d].ds);
4194:         if (flg) {PetscDSView(dm->probs[d].ds, viewer);}
4195:       }
4196:       if (flg) {
4197:         PetscViewerFlush(viewer);
4198:         PetscViewerPopFormat(viewer);
4199:         PetscViewerDestroy(&viewer);
4200:       }
4201:     }
4202:     (*dm->ops->createlocalsection)(dm);
4203:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4204:   }
4205:   *section = dm->localSection;
4206:   return(0);
4207: }

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

4212:   Input Parameters:
4213: + dm - The DM
4214: - section - The PetscSection

4216:   Level: advanced

4218:   Notes:
4219:   Use DMSetLocalSection() in new code.

4221:   Any existing Section will be destroyed

4223: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4224: @*/
4225: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4226: {

4230:   DMSetLocalSection(dm,section);
4231:   return(0);
4232: }

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

4237:   Input Parameters:
4238: + dm - The DM
4239: - section - The PetscSection

4241:   Level: intermediate

4243:   Note: Any existing Section will be destroyed

4245: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4246: @*/
4247: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4248: {
4249:   PetscInt       numFields = 0;
4250:   PetscInt       f;

4256:   PetscObjectReference((PetscObject)section);
4257:   PetscSectionDestroy(&dm->localSection);
4258:   dm->localSection = section;
4259:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4260:   if (numFields) {
4261:     DMSetNumFields(dm, numFields);
4262:     for (f = 0; f < numFields; ++f) {
4263:       PetscObject disc;
4264:       const char *name;

4266:       PetscSectionGetFieldName(dm->localSection, f, &name);
4267:       DMGetField(dm, f, NULL, &disc);
4268:       PetscObjectSetName(disc, name);
4269:     }
4270:   }
4271:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4272:   PetscSectionDestroy(&dm->globalSection);
4273:   return(0);
4274: }

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

4279:   not collective

4281:   Input Parameter:
4282: . dm - The DM

4284:   Output Parameter:
4285: + 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.
4286: - 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.

4288:   Level: advanced

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

4292: .seealso: DMSetDefaultConstraints()
4293: @*/
4294: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4295: {

4300:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4301:   if (section) {*section = dm->defaultConstraintSection;}
4302:   if (mat) {*mat = dm->defaultConstraintMat;}
4303:   return(0);
4304: }

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

4309:   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().

4311:   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.

4313:   collective on dm

4315:   Input Parameters:
4316: + dm - The DM
4317: + 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).
4318: - 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).

4320:   Level: advanced

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

4324: .seealso: DMGetDefaultConstraints()
4325: @*/
4326: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4327: {
4328:   PetscMPIInt result;

4333:   if (section) {
4335:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4336:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4337:   }
4338:   if (mat) {
4340:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4341:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4342:   }
4343:   PetscObjectReference((PetscObject)section);
4344:   PetscSectionDestroy(&dm->defaultConstraintSection);
4345:   dm->defaultConstraintSection = section;
4346:   PetscObjectReference((PetscObject)mat);
4347:   MatDestroy(&dm->defaultConstraintMat);
4348:   dm->defaultConstraintMat = mat;
4349:   return(0);
4350: }

4352: #if defined(PETSC_USE_DEBUG)
4353: /*
4354:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4356:   Input Parameters:
4357: + dm - The DM
4358: . localSection - PetscSection describing the local data layout
4359: - globalSection - PetscSection describing the global data layout

4361:   Level: intermediate

4363: .seealso: DMGetSectionSF(), DMSetSectionSF()
4364: */
4365: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4366: {
4367:   MPI_Comm        comm;
4368:   PetscLayout     layout;
4369:   const PetscInt *ranges;
4370:   PetscInt        pStart, pEnd, p, nroots;
4371:   PetscMPIInt     size, rank;
4372:   PetscBool       valid = PETSC_TRUE, gvalid;
4373:   PetscErrorCode  ierr;

4376:   PetscObjectGetComm((PetscObject)dm,&comm);
4378:   MPI_Comm_size(comm, &size);
4379:   MPI_Comm_rank(comm, &rank);
4380:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4381:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4382:   PetscLayoutCreate(comm, &layout);
4383:   PetscLayoutSetBlockSize(layout, 1);
4384:   PetscLayoutSetLocalSize(layout, nroots);
4385:   PetscLayoutSetUp(layout);
4386:   PetscLayoutGetRanges(layout, &ranges);
4387:   for (p = pStart; p < pEnd; ++p) {
4388:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4390:     PetscSectionGetDof(localSection, p, &dof);
4391:     PetscSectionGetOffset(localSection, p, &off);
4392:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4393:     PetscSectionGetDof(globalSection, p, &gdof);
4394:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4395:     PetscSectionGetOffset(globalSection, p, &goff);
4396:     if (!gdof) continue; /* Censored point */
4397:     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;}
4398:     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;}
4399:     if (gdof < 0) {
4400:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4401:       for (d = 0; d < gsize; ++d) {
4402:         PetscInt offset = -(goff+1) + d, r;

4404:         PetscFindInt(offset,size+1,ranges,&r);
4405:         if (r < 0) r = -(r+2);
4406:         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;}
4407:       }
4408:     }
4409:   }
4410:   PetscLayoutDestroy(&layout);
4411:   PetscSynchronizedFlush(comm, NULL);
4412:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4413:   if (!gvalid) {
4414:     DMView(dm, NULL);
4415:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4416:   }
4417:   return(0);
4418: }
4419: #endif

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

4424:   Collective on dm

4426:   Input Parameter:
4427: . dm - The DM

4429:   Output Parameter:
4430: . section - The PetscSection

4432:   Level: intermediate

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

4436: .seealso: DMSetLocalSection(), DMGetLocalSection()
4437: @*/
4438: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4439: {

4445:   if (!dm->globalSection) {
4446:     PetscSection s;

4448:     DMGetLocalSection(dm, &s);
4449:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4450:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4451:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4452:     PetscLayoutDestroy(&dm->map);
4453:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4454:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4455:   }
4456:   *section = dm->globalSection;
4457:   return(0);
4458: }

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

4463:   Input Parameters:
4464: + dm - The DM
4465: - section - The PetscSection, or NULL

4467:   Level: intermediate

4469:   Note: Any existing Section will be destroyed

4471: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4472: @*/
4473: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4474: {

4480:   PetscObjectReference((PetscObject)section);
4481:   PetscSectionDestroy(&dm->globalSection);
4482:   dm->globalSection = section;
4483: #if defined(PETSC_USE_DEBUG)
4484:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4485: #endif
4486:   return(0);
4487: }

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

4493:   Input Parameter:
4494: . dm - The DM

4496:   Output Parameter:
4497: . sf - The PetscSF

4499:   Level: intermediate

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

4503: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4504: @*/
4505: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4506: {
4507:   PetscInt       nroots;

4513:   if (!dm->sectionSF) {
4514:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4515:   }
4516:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4517:   if (nroots < 0) {
4518:     PetscSection section, gSection;

4520:     DMGetLocalSection(dm, &section);
4521:     if (section) {
4522:       DMGetGlobalSection(dm, &gSection);
4523:       DMCreateSectionSF(dm, section, gSection);
4524:     } else {
4525:       *sf = NULL;
4526:       return(0);
4527:     }
4528:   }
4529:   *sf = dm->sectionSF;
4530:   return(0);
4531: }

4533: /*@
4534:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4536:   Input Parameters:
4537: + dm - The DM
4538: - sf - The PetscSF

4540:   Level: intermediate

4542:   Note: Any previous SF is destroyed

4544: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4545: @*/
4546: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4547: {

4553:   PetscObjectReference((PetscObject) sf);
4554:   PetscSFDestroy(&dm->sectionSF);
4555:   dm->sectionSF = sf;
4556:   return(0);
4557: }

4559: /*@C
4560:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4561:   describing the data layout.

4563:   Input Parameters:
4564: + dm - The DM
4565: . localSection - PetscSection describing the local data layout
4566: - globalSection - PetscSection describing the global data layout

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

4570:   Level: developer

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

4576: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4577: @*/
4578: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4579: {

4584:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4585:   return(0);
4586: }

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

4591:   Input Parameter:
4592: . dm - The DM

4594:   Output Parameter:
4595: . sf - The PetscSF

4597:   Level: intermediate

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

4601: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4602: @*/
4603: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4604: {
4608:   *sf = dm->sf;
4609:   return(0);
4610: }

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

4615:   Input Parameters:
4616: + dm - The DM
4617: - sf - The PetscSF

4619:   Level: intermediate

4621: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4622: @*/
4623: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4624: {

4630:   PetscObjectReference((PetscObject) sf);
4631:   PetscSFDestroy(&dm->sf);
4632:   dm->sf = sf;
4633:   return(0);
4634: }

4636: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4637: {
4638:   PetscClassId   id;

4642:   PetscObjectGetClassId(disc, &id);
4643:   if (id == PETSCFE_CLASSID) {
4644:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4645:   } else if (id == PETSCFV_CLASSID) {
4646:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4647:   } else {
4648:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4649:   }
4650:   return(0);
4651: }

4653: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4654: {
4655:   RegionField   *tmpr;
4656:   PetscInt       Nf = dm->Nf, f;

4660:   if (Nf >= NfNew) return(0);
4661:   PetscMalloc1(NfNew, &tmpr);
4662:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4663:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4664:   PetscFree(dm->fields);
4665:   dm->Nf     = NfNew;
4666:   dm->fields = tmpr;
4667:   return(0);
4668: }

4670: /*@
4671:   DMClearFields - Remove all fields from the DM

4673:   Logically collective on dm

4675:   Input Parameter:
4676: . dm - The DM

4678:   Level: intermediate

4680: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4681: @*/
4682: PetscErrorCode DMClearFields(DM dm)
4683: {
4684:   PetscInt       f;

4689:   for (f = 0; f < dm->Nf; ++f) {
4690:     PetscObjectDestroy(&dm->fields[f].disc);
4691:     DMLabelDestroy(&dm->fields[f].label);
4692:   }
4693:   PetscFree(dm->fields);
4694:   dm->fields = NULL;
4695:   dm->Nf     = 0;
4696:   return(0);
4697: }

4699: /*@
4700:   DMGetNumFields - Get the number of fields in the DM

4702:   Not collective

4704:   Input Parameter:
4705: . dm - The DM

4707:   Output Parameter:
4708: . Nf - The number of fields

4710:   Level: intermediate

4712: .seealso: DMSetNumFields(), DMSetField()
4713: @*/
4714: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4715: {
4719:   *numFields = dm->Nf;
4720:   return(0);
4721: }

4723: /*@
4724:   DMSetNumFields - Set the number of fields in the DM

4726:   Logically collective on dm

4728:   Input Parameters:
4729: + dm - The DM
4730: - Nf - The number of fields

4732:   Level: intermediate

4734: .seealso: DMGetNumFields(), DMSetField()
4735: @*/
4736: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4737: {
4738:   PetscInt       Nf, f;

4743:   DMGetNumFields(dm, &Nf);
4744:   for (f = Nf; f < numFields; ++f) {
4745:     PetscContainer obj;

4747:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4748:     DMAddField(dm, NULL, (PetscObject) obj);
4749:     PetscContainerDestroy(&obj);
4750:   }
4751:   return(0);
4752: }

4754: /*@
4755:   DMGetField - Return the discretization object for a given DM field

4757:   Not collective

4759:   Input Parameters:
4760: + dm - The DM
4761: - f  - The field number

4763:   Output Parameters:
4764: + label - The label indicating the support of the field, or NULL for the entire mesh
4765: - field - The discretization object

4767:   Level: intermediate

4769: .seealso: DMAddField(), DMSetField()
4770: @*/
4771: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4772: {
4776:   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);
4777:   if (label) *label = dm->fields[f].label;
4778:   if (field) *field = dm->fields[f].disc;
4779:   return(0);
4780: }

4782: /* Does not clear the DS */
4783: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4784: {

4788:   DMFieldEnlarge_Static(dm, f+1);
4789:   DMLabelDestroy(&dm->fields[f].label);
4790:   PetscObjectDestroy(&dm->fields[f].disc);
4791:   dm->fields[f].label = label;
4792:   dm->fields[f].disc  = field;
4793:   PetscObjectReference((PetscObject) label);
4794:   PetscObjectReference((PetscObject) field);
4795:   return(0);
4796: }

4798: /*@
4799:   DMSetField - Set the discretization object for a given DM field

4801:   Logically collective on dm

4803:   Input Parameters:
4804: + dm    - The DM
4805: . f     - The field number
4806: . label - The label indicating the support of the field, or NULL for the entire mesh
4807: - field - The discretization object

4809:   Level: intermediate

4811: .seealso: DMAddField(), DMGetField()
4812: @*/
4813: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4814: {

4821:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4822:   DMSetField_Internal(dm, f, label, field);
4823:   DMSetDefaultAdjacency_Private(dm, f, field);
4824:   DMClearDS(dm);
4825:   return(0);
4826: }

4828: /*@
4829:   DMAddField - Add the discretization object for the given DM field

4831:   Logically collective on dm

4833:   Input Parameters:
4834: + dm    - The DM
4835: . label - The label indicating the support of the field, or NULL for the entire mesh
4836: - field - The discretization object

4838:   Level: intermediate

4840: .seealso: DMSetField(), DMGetField()
4841: @*/
4842: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4843: {
4844:   PetscInt       Nf = dm->Nf;

4851:   DMFieldEnlarge_Static(dm, Nf+1);
4852:   dm->fields[Nf].label = label;
4853:   dm->fields[Nf].disc  = field;
4854:   PetscObjectReference((PetscObject) label);
4855:   PetscObjectReference((PetscObject) field);
4856:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4857:   DMClearDS(dm);
4858:   return(0);
4859: }

4861: /*@
4862:   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells

4864:   Logically collective on dm

4866:   Input Parameters:
4867: + dm          - The DM
4868: . f           - The field index
4869: - avoidTensor - The flag to avoid defining the field on tensor cells

4871:   Level: intermediate

4873: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4874: @*/
4875: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4876: {
4878:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4879:   dm->fields[f].avoidTensor = avoidTensor;
4880:   return(0);
4881: }

4883: /*@
4884:   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells

4886:   Logically collective on dm

4888:   Input Parameters:
4889: + dm          - The DM
4890: - f           - The field index

4892:   Output Parameter:
4893: . avoidTensor - The flag to avoid defining the field on tensor cells

4895:   Level: intermediate

4897: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4898: @*/
4899: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4900: {
4902:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4903:   *avoidTensor = dm->fields[f].avoidTensor;
4904:   return(0);
4905: }

4907: /*@
4908:   DMCopyFields - Copy the discretizations for the DM into another DM

4910:   Collective on dm

4912:   Input Parameter:
4913: . dm - The DM

4915:   Output Parameter:
4916: . newdm - The DM

4918:   Level: advanced

4920: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4921: @*/
4922: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4923: {
4924:   PetscInt       Nf, f;

4928:   if (dm == newdm) return(0);
4929:   DMGetNumFields(dm, &Nf);
4930:   DMClearFields(newdm);
4931:   for (f = 0; f < Nf; ++f) {
4932:     DMLabel     label;
4933:     PetscObject field;
4934:     PetscBool   useCone, useClosure;

4936:     DMGetField(dm, f, &label, &field);
4937:     DMSetField(newdm, f, label, field);
4938:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4939:     DMSetAdjacency(newdm, f, useCone, useClosure);
4940:   }
4941:   return(0);
4942: }

4944: /*@
4945:   DMGetAdjacency - Returns the flags for determining variable influence

4947:   Not collective

4949:   Input Parameters:
4950: + dm - The DM object
4951: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4953:   Output Parameter:
4954: + useCone    - Flag for variable influence starting with the cone operation
4955: - useClosure - Flag for variable influence using transitive closure

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

4963:   Level: developer

4965: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4966: @*/
4967: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4968: {
4973:   if (f < 0) {
4974:     if (useCone)    *useCone    = dm->adjacency[0];
4975:     if (useClosure) *useClosure = dm->adjacency[1];
4976:   } else {
4977:     PetscInt       Nf;

4980:     DMGetNumFields(dm, &Nf);
4981:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4982:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4983:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4984:   }
4985:   return(0);
4986: }

4988: /*@
4989:   DMSetAdjacency - Set the flags for determining variable influence

4991:   Not collective

4993:   Input Parameters:
4994: + dm         - The DM object
4995: . f          - The field number
4996: . useCone    - Flag for variable influence starting with the cone operation
4997: - useClosure - Flag for variable influence using transitive closure

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

5005:   Level: developer

5007: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
5008: @*/
5009: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5010: {
5013:   if (f < 0) {
5014:     dm->adjacency[0] = useCone;
5015:     dm->adjacency[1] = useClosure;
5016:   } else {
5017:     PetscInt       Nf;

5020:     DMGetNumFields(dm, &Nf);
5021:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5022:     dm->fields[f].adjacency[0] = useCone;
5023:     dm->fields[f].adjacency[1] = useClosure;
5024:   }
5025:   return(0);
5026: }

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

5031:   Not collective

5033:   Input Parameters:
5034: . dm - The DM object

5036:   Output Parameter:
5037: + useCone    - Flag for variable influence starting with the cone operation
5038: - useClosure - Flag for variable influence using transitive closure

5040:   Notes:
5041: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5042: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5043: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5045:   Level: developer

5047: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5048: @*/
5049: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5050: {
5051:   PetscInt       Nf;

5058:   DMGetNumFields(dm, &Nf);
5059:   if (!Nf) {
5060:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5061:   } else {
5062:     DMGetAdjacency(dm, 0, useCone, useClosure);
5063:   }
5064:   return(0);
5065: }

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

5070:   Not collective

5072:   Input Parameters:
5073: + dm         - The DM object
5074: . useCone    - Flag for variable influence starting with the cone operation
5075: - useClosure - Flag for variable influence using transitive closure

5077:   Notes:
5078: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5079: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5080: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5082:   Level: developer

5084: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5085: @*/
5086: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5087: {
5088:   PetscInt       Nf;

5093:   DMGetNumFields(dm, &Nf);
5094:   if (!Nf) {
5095:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5096:   } else {
5097:     DMSetAdjacency(dm, 0, useCone, useClosure);
5098:   }
5099:   return(0);
5100: }

5102: /* Complete labels that are being used for FEM BC */
5103: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
5104: {
5105:   PetscObject    obj;
5106:   PetscClassId   id;
5107:   PetscInt       Nbd, bd;
5108:   PetscBool      isFE      = PETSC_FALSE;
5109:   PetscBool      duplicate = PETSC_FALSE;

5113:   DMGetField(dm, field, NULL, &obj);
5114:   PetscObjectGetClassId(obj, &id);
5115:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5116:   if (isFE && label) {
5117:     /* Only want to modify label once */
5118:     PetscDSGetNumBoundary(ds, &Nbd);
5119:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5120:       DMLabel l;

5122:       PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5123:       duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
5124:       if (duplicate) break;
5125:     }
5126:     if (!duplicate) {
5127:       DM plex;

5129:       DMConvert(dm, DMPLEX, &plex);
5130:       if (plex) {DMPlexLabelComplete(plex, label);}
5131:       DMDestroy(&plex);
5132:     }
5133:   }
5134:   return(0);
5135: }

5137: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5138: {
5139:   DMSpace       *tmpd;
5140:   PetscInt       Nds = dm->Nds, s;

5144:   if (Nds >= NdsNew) return(0);
5145:   PetscMalloc1(NdsNew, &tmpd);
5146:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5147:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5148:   PetscFree(dm->probs);
5149:   dm->Nds   = NdsNew;
5150:   dm->probs = tmpd;
5151:   return(0);
5152: }

5154: /*@
5155:   DMGetNumDS - Get the number of discrete systems in the DM

5157:   Not collective

5159:   Input Parameter:
5160: . dm - The DM

5162:   Output Parameter:
5163: . Nds - The number of PetscDS objects

5165:   Level: intermediate

5167: .seealso: DMGetDS(), DMGetCellDS()
5168: @*/
5169: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5170: {
5174:   *Nds = dm->Nds;
5175:   return(0);
5176: }

5178: /*@
5179:   DMClearDS - Remove all discrete systems from the DM

5181:   Logically collective on dm

5183:   Input Parameter:
5184: . dm - The DM

5186:   Level: intermediate

5188: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5189: @*/
5190: PetscErrorCode DMClearDS(DM dm)
5191: {
5192:   PetscInt       s;

5197:   for (s = 0; s < dm->Nds; ++s) {
5198:     PetscDSDestroy(&dm->probs[s].ds);
5199:     DMLabelDestroy(&dm->probs[s].label);
5200:     ISDestroy(&dm->probs[s].fields);
5201:   }
5202:   PetscFree(dm->probs);
5203:   dm->probs = NULL;
5204:   dm->Nds   = 0;
5205:   return(0);
5206: }

5208: /*@
5209:   DMGetDS - Get the default PetscDS

5211:   Not collective

5213:   Input Parameter:
5214: . dm    - The DM

5216:   Output Parameter:
5217: . prob - The default PetscDS

5219:   Level: intermediate

5221: .seealso: DMGetCellDS(), DMGetRegionDS()
5222: @*/
5223: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5224: {

5230:   if (dm->Nds <= 0) {
5231:     PetscDS ds;

5233:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5234:     DMSetRegionDS(dm, NULL, NULL, ds);
5235:     PetscDSDestroy(&ds);
5236:   }
5237:   *prob = dm->probs[0].ds;
5238:   return(0);
5239: }

5241: /*@
5242:   DMGetCellDS - Get the PetscDS defined on a given cell

5244:   Not collective

5246:   Input Parameters:
5247: + dm    - The DM
5248: - point - Cell for the DS

5250:   Output Parameter:
5251: . prob - The PetscDS defined on the given cell

5253:   Level: developer

5255: .seealso: DMGetDS(), DMSetRegionDS()
5256: @*/
5257: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5258: {
5259:   PetscDS        probDef = NULL;
5260:   PetscInt       s;

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

5271:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5272:     else {
5273:       DMLabelGetValue(dm->probs[s].label, point, &val);
5274:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5275:     }
5276:   }
5277:   if (!*prob) *prob = probDef;
5278:   return(0);
5279: }

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

5284:   Not collective

5286:   Input Parameters:
5287: + dm    - The DM
5288: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5296:   Level: advanced

5298: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5299: @*/
5300: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5301: {
5302:   PetscInt Nds = dm->Nds, s;

5309:   for (s = 0; s < Nds; ++s) {
5310:     if (dm->probs[s].label == label) {
5311:       if (fields) *fields = dm->probs[s].fields;
5312:       if (ds)     *ds     = dm->probs[s].ds;
5313:       return(0);
5314:     }
5315:   }
5316:   return(0);
5317: }

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

5322:   Collective on dm

5324:   Input Parameters:
5325: + dm     - The DM
5326: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5327: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5328: - prob   - The PetscDS defined on the given cell

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

5333:   Level: advanced

5335: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5336: @*/
5337: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5338: {
5339:   PetscInt       Nds = dm->Nds, s;

5346:   for (s = 0; s < Nds; ++s) {
5347:     if (dm->probs[s].label == label) {
5348:       PetscDSDestroy(&dm->probs[s].ds);
5349:       dm->probs[s].ds = ds;
5350:       return(0);
5351:     }
5352:   }
5353:   DMDSEnlarge_Static(dm, Nds+1);
5354:   PetscObjectReference((PetscObject) label);
5355:   PetscObjectReference((PetscObject) fields);
5356:   PetscObjectReference((PetscObject) ds);
5357:   if (!label) {
5358:     /* Put the NULL label at the front, so it is returned as the default */
5359:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5360:     Nds = 0;
5361:   }
5362:   dm->probs[Nds].label  = label;
5363:   dm->probs[Nds].fields = fields;
5364:   dm->probs[Nds].ds     = ds;
5365:   return(0);
5366: }

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

5371:   Not collective

5373:   Input Parameters:
5374: + dm  - The DM
5375: - num - The region number, in [0, Nds)

5377:   Output Parameters:
5378: + label  - The region label, or NULL
5379: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5380: - ds     - The PetscDS defined on the given region, or NULL

5382:   Level: advanced

5384: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5385: @*/
5386: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5387: {
5388:   PetscInt       Nds;

5393:   DMGetNumDS(dm, &Nds);
5394:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5395:   if (label) {
5397:     *label = dm->probs[num].label;
5398:   }
5399:   if (fields) {
5401:     *fields = dm->probs[num].fields;
5402:   }
5403:   if (ds) {
5405:     *ds = dm->probs[num].ds;
5406:   }
5407:   return(0);
5408: }

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

5413:   Not collective

5415:   Input Parameters:
5416: + dm     - The DM
5417: . num    - The region number, in [0, Nds)
5418: . label  - The region label, or NULL
5419: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5420: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5422:   Level: advanced

5424: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5425: @*/
5426: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5427: {
5428:   PetscInt       Nds;

5434:   DMGetNumDS(dm, &Nds);
5435:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5436:   PetscObjectReference((PetscObject) label);
5437:   DMLabelDestroy(&dm->probs[num].label);
5438:   dm->probs[num].label = label;
5439:   if (fields) {
5441:     PetscObjectReference((PetscObject) fields);
5442:     ISDestroy(&dm->probs[num].fields);
5443:     dm->probs[num].fields = fields;
5444:   }
5445:   if (ds) {
5447:     PetscObjectReference((PetscObject) ds);
5448:     PetscDSDestroy(&dm->probs[num].ds);
5449:     dm->probs[num].ds = ds;
5450:   }
5451:   return(0);
5452: }

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

5457:   Not collective

5459:   Input Parameters:
5460: + dm  - The DM
5461: - ds  - The PetscDS defined on the given region

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

5466:   Level: advanced

5468: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5469: @*/
5470: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5471: {
5472:   PetscInt       Nds, n;

5479:   DMGetNumDS(dm, &Nds);
5480:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5481:   if (n >= Nds) *num = -1;
5482:   else          *num = n;
5483:   return(0);
5484: }

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

5489:   Collective on dm

5491:   Input Parameter:
5492: . dm - The DM

5494:   Options Database Keys:
5495: . -dm_petscds_view - View all the PetscDS objects in this DM

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

5499:   Level: intermediate

5501: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5502: @*/
5503: PetscErrorCode DMCreateDS(DM dm)
5504: {
5505:   MPI_Comm       comm;
5506:   PetscDS        dsDef;
5507:   DMLabel       *labelSet;
5508:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5509:   PetscBool      doSetup = PETSC_TRUE, flg;

5514:   if (!dm->fields) return(0);
5515:   PetscObjectGetComm((PetscObject) dm, &comm);
5516:   DMGetCoordinateDim(dm, &dE);
5517:   /* Determine how many regions we have */
5518:   PetscMalloc1(Nf, &labelSet);
5519:   Nl   = 0;
5520:   Ndef = 0;
5521:   for (f = 0; f < Nf; ++f) {
5522:     DMLabel  label = dm->fields[f].label;
5523:     PetscInt l;

5525:     if (!label) {++Ndef; continue;}
5526:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5527:     if (l < Nl) continue;
5528:     labelSet[Nl++] = label;
5529:   }
5530:   /* Create default DS if there are no labels to intersect with */
5531:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5532:   if (!dsDef && Ndef && !Nl) {
5533:     IS        fields;
5534:     PetscInt *fld, nf;

5536:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5537:     if (nf) {
5538:       PetscMalloc1(nf, &fld);
5539:       for (f = 0, nf = 0; f < Nf; ++f) if (!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);

5545:       PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5546:       DMSetRegionDS(dm, NULL, fields, dsDef);
5547:       PetscDSDestroy(&dsDef);
5548:       ISDestroy(&fields);
5549:     }
5550:   }
5551:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5552:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5553:   /* Intersect labels with default fields */
5554:   if (Ndef && Nl) {
5555:     DM              plex;
5556:     DMLabel         cellLabel;
5557:     IS              fieldIS, allcellIS, defcellIS = NULL;
5558:     PetscInt       *fields;
5559:     const PetscInt *cells;
5560:     PetscInt        depth, nf = 0, n, c;

5562:     DMConvert(dm, DMPLEX, &plex);
5563:     DMPlexGetDepth(plex, &depth);
5564:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5565:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5566:     for (l = 0; l < Nl; ++l) {
5567:       DMLabel label = labelSet[l];
5568:       IS      pointIS;

5570:       ISDestroy(&defcellIS);
5571:       DMLabelGetStratumIS(label, 1, &pointIS);
5572:       ISDifference(allcellIS, pointIS, &defcellIS);
5573:       ISDestroy(&pointIS);
5574:     }
5575:     ISDestroy(&allcellIS);

5577:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5578:     ISGetLocalSize(defcellIS, &n);
5579:     ISGetIndices(defcellIS, &cells);
5580:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5581:     ISRestoreIndices(defcellIS, &cells);
5582:     ISDestroy(&defcellIS);
5583:     DMPlexLabelComplete(plex, cellLabel);

5585:     PetscMalloc1(Ndef, &fields);
5586:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5587:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5588:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5589:     ISSetType(fieldIS, ISGENERAL);
5590:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5592:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5593:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5594:     DMLabelDestroy(&cellLabel);
5595:     PetscDSSetCoordinateDimension(dsDef, dE);
5596:     PetscDSDestroy(&dsDef);
5597:     ISDestroy(&fieldIS);
5598:     DMDestroy(&plex);
5599:   }
5600:   /* Create label DSes
5601:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5602:   */
5603:   /* TODO Should check that labels are disjoint */
5604:   for (l = 0; l < Nl; ++l) {
5605:     DMLabel   label = labelSet[l];
5606:     PetscDS   ds;
5607:     IS        fields;
5608:     PetscInt *fld, nf;

5610:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5611:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5612:     PetscMalloc1(nf, &fld);
5613:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5614:     ISCreate(PETSC_COMM_SELF, &fields);
5615:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5616:     ISSetType(fields, ISGENERAL);
5617:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5618:     DMSetRegionDS(dm, label, fields, ds);
5619:     ISDestroy(&fields);
5620:     PetscDSSetCoordinateDimension(ds, dE);
5621:     {
5622:       DMPolytopeType ct;
5623:       PetscInt       lStart, lEnd;
5624:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5626:       DMLabelGetBounds(label, &lStart, &lEnd);
5627:       if (lStart >= 0) {
5628:         DMPlexGetCellType(dm, lStart, &ct);
5629:         switch (ct) {
5630:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5631:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5632:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5633:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5634:             isHybridLocal = PETSC_TRUE;break;
5635:           default: break;
5636:         }
5637:       }
5638:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5639:       PetscDSSetHybrid(ds, isHybrid);
5640:     }
5641:     PetscDSDestroy(&ds);
5642:   }
5643:   PetscFree(labelSet);
5644:   /* Set fields in DSes */
5645:   for (s = 0; s < dm->Nds; ++s) {
5646:     PetscDS         ds     = dm->probs[s].ds;
5647:     IS              fields = dm->probs[s].fields;
5648:     const PetscInt *fld;
5649:     PetscInt        nf;

5651:     ISGetLocalSize(fields, &nf);
5652:     ISGetIndices(fields, &fld);
5653:     for (f = 0; f < nf; ++f) {
5654:       PetscObject  disc  = dm->fields[fld[f]].disc;
5655:       PetscBool    isHybrid;
5656:       PetscClassId id;

5658:       PetscDSGetHybrid(ds, &isHybrid);
5659:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5660:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5661:       PetscDSSetDiscretization(ds, f, disc);
5662:       /* We allow people to have placeholder fields and construct the Section by hand */
5663:       PetscObjectGetClassId(disc, &id);
5664:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5665:     }
5666:     ISRestoreIndices(fields, &fld);
5667:   }
5668:   /* Allow k-jet tabulation */
5669:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5670:   if (flg) {
5671:     for (s = 0; s < dm->Nds; ++s) {
5672:       PetscDS  ds = dm->probs[s].ds;
5673:       PetscInt Nf, f;

5675:       PetscDSGetNumFields(ds, &Nf);
5676:       for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5677:     }
5678:   }
5679:   /* Setup DSes */
5680:   if (doSetup) {
5681:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5682:   }
5683:   return(0);
5684: }

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

5689:   Collective on DM

5691:   Input Parameters:
5692: + dm   - The DM
5693: - time - The time

5695:   Output Parameters:
5696: + u    - The vector will be filled with exact solution values, or NULL
5697: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5699:   Note: The user must call PetscDSSetExactSolution() beforehand

5701:   Level: developer

5703: .seealso: PetscDSSetExactSolution()
5704: @*/
5705: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5706: {
5707:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5708:   void            **ectxs;
5709:   PetscInt          Nf, Nds, s;
5710:   PetscErrorCode    ierr;

5716:   DMGetNumFields(dm, &Nf);
5717:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5718:   DMGetNumDS(dm, &Nds);
5719:   for (s = 0; s < Nds; ++s) {
5720:     PetscDS         ds;
5721:     DMLabel         label;
5722:     IS              fieldIS;
5723:     const PetscInt *fields, id = 1;
5724:     PetscInt        dsNf, f;

5726:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5727:     PetscDSGetNumFields(ds, &dsNf);
5728:     ISGetIndices(fieldIS, &fields);
5729:     PetscArrayzero(exacts, Nf);
5730:     PetscArrayzero(ectxs, Nf);
5731:     if (u) {
5732:       for (f = 0; f < dsNf; ++f) {
5733:         const PetscInt field = fields[f];
5734:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5735:       }
5736:       ISRestoreIndices(fieldIS, &fields);
5737:       if (label) {
5738:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5739:       } else {
5740:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5741:       }
5742:     }
5743:     if (u_t) {
5744:       PetscArrayzero(exacts, Nf);
5745:       PetscArrayzero(ectxs, Nf);
5746:       for (f = 0; f < dsNf; ++f) {
5747:         const PetscInt field = fields[f];
5748:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5749:       }
5750:       ISRestoreIndices(fieldIS, &fields);
5751:       if (label) {
5752:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5753:       } else {
5754:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5755:       }
5756:     }
5757:   }
5758:   if (u) {
5759:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5760:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5761:   }
5762:   if (u_t) {
5763:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5764:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5765:   }
5766:   PetscFree2(exacts, ectxs);
5767:   return(0);
5768: }

5770: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5771: {
5772:   PetscDS        dsNew;
5773:   DSBoundary     b;
5774:   PetscInt       cdim, Nf, f;
5775:   void          *ctx;

5779:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5780:   PetscDSCopyConstants(ds, dsNew);
5781:   PetscDSCopyExactSolutions(ds, dsNew);
5782:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5783:   PetscDSCopyEquations(ds, dsNew);
5784:   PetscDSGetNumFields(ds, &Nf);
5785:   for (f = 0; f < Nf; ++f) {
5786:     PetscDSGetContext(ds, f, &ctx);
5787:     PetscDSSetContext(dsNew, f, ctx);
5788:   }
5789:   if (Nf) {
5790:     PetscDSGetCoordinateDimension(ds, &cdim);
5791:     PetscDSSetCoordinateDimension(dsNew, cdim);
5792:   }
5793:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5794:   for (b = dsNew->boundary; b; b = b->next) {
5795:     DMGetLabel(dm, b->lname, &b->label);
5796:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5797:     //if (!b->label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
5798:   }

5800:   DMSetRegionDS(dm, label, fields, dsNew);
5801:   PetscDSDestroy(&dsNew);
5802:   return(0);
5803: }

5805: /*@
5806:   DMCopyDS - Copy the discrete systems for the DM into another DM

5808:   Collective on dm

5810:   Input Parameter:
5811: . dm - The DM

5813:   Output Parameter:
5814: . newdm - The DM

5816:   Level: advanced

5818: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5819: @*/
5820: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5821: {
5822:   PetscInt       Nds, s;

5826:   if (dm == newdm) return(0);
5827:   DMGetNumDS(dm, &Nds);
5828:   DMClearDS(newdm);
5829:   for (s = 0; s < Nds; ++s) {
5830:     DMLabel  label;
5831:     IS       fields;
5832:     PetscDS  ds, newds;
5833:     PetscInt Nbd, bd;

5835:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5836:     DMTransferDS_Internal(newdm, label, fields, ds);
5837:     /* Commplete new labels in the new DS */
5838:     DMGetRegionDS(newdm, label, NULL, &newds);
5839:     PetscDSGetNumBoundary(newds, &Nbd);
5840:     for (bd = 0; bd < Nbd; ++bd) {
5841:       DMLabel  label;
5842:       PetscInt field;

5844:       PetscDSGetBoundary(newds, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5845:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5846:     }
5847:   }
5848:   return(0);
5849: }

5851: /*@
5852:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

5854:   Collective on dm

5856:   Input Parameter:
5857: . dm - The DM

5859:   Output Parameter:
5860: . newdm - The DM

5862:   Level: advanced

5864: .seealso: DMCopyFields(), DMCopyDS()
5865: @*/
5866: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5867: {

5871:   DMCopyFields(dm, newdm);
5872:   DMCopyDS(dm, newdm);
5873:   return(0);
5874: }

5876: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5877: {
5878:   DM dm_coord,dmc_coord;
5880:   Vec coords,ccoords;
5881:   Mat inject;
5883:   DMGetCoordinateDM(dm,&dm_coord);
5884:   DMGetCoordinateDM(dmc,&dmc_coord);
5885:   DMGetCoordinates(dm,&coords);
5886:   DMGetCoordinates(dmc,&ccoords);
5887:   if (coords && !ccoords) {
5888:     DMCreateGlobalVector(dmc_coord,&ccoords);
5889:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5890:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5891:     MatRestrict(inject,coords,ccoords);
5892:     MatDestroy(&inject);
5893:     DMSetCoordinates(dmc,ccoords);
5894:     VecDestroy(&ccoords);
5895:   }
5896:   return(0);
5897: }

5899: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5900: {
5901:   DM dm_coord,subdm_coord;
5903:   Vec coords,ccoords,clcoords;
5904:   VecScatter *scat_i,*scat_g;
5906:   DMGetCoordinateDM(dm,&dm_coord);
5907:   DMGetCoordinateDM(subdm,&subdm_coord);
5908:   DMGetCoordinates(dm,&coords);
5909:   DMGetCoordinates(subdm,&ccoords);
5910:   if (coords && !ccoords) {
5911:     DMCreateGlobalVector(subdm_coord,&ccoords);
5912:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5913:     DMCreateLocalVector(subdm_coord,&clcoords);
5914:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5915:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5916:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5917:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5918:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5919:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5920:     DMSetCoordinates(subdm,ccoords);
5921:     DMSetCoordinatesLocal(subdm,clcoords);
5922:     VecScatterDestroy(&scat_i[0]);
5923:     VecScatterDestroy(&scat_g[0]);
5924:     VecDestroy(&ccoords);
5925:     VecDestroy(&clcoords);
5926:     PetscFree(scat_i);
5927:     PetscFree(scat_g);
5928:   }
5929:   return(0);
5930: }

5932: /*@
5933:   DMGetDimension - Return the topological dimension of the DM

5935:   Not collective

5937:   Input Parameter:
5938: . dm - The DM

5940:   Output Parameter:
5941: . dim - The topological dimension

5943:   Level: beginner

5945: .seealso: DMSetDimension(), DMCreate()
5946: @*/
5947: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5948: {
5952:   *dim = dm->dim;
5953:   return(0);
5954: }

5956: /*@
5957:   DMSetDimension - Set the topological dimension of the DM

5959:   Collective on dm

5961:   Input Parameters:
5962: + dm - The DM
5963: - dim - The topological dimension

5965:   Level: beginner

5967: .seealso: DMGetDimension(), DMCreate()
5968: @*/
5969: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5970: {
5971:   PetscDS        ds;
5972:   PetscInt       Nds, n;

5978:   dm->dim = dim;
5979:   DMGetNumDS(dm, &Nds);
5980:   for (n = 0; n < Nds; ++n) {
5981:     DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
5982:     if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
5983:   }
5984:   return(0);
5985: }

5987: /*@
5988:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

5990:   Collective on dm

5992:   Input Parameters:
5993: + dm - the DM
5994: - dim - the dimension

5996:   Output Parameters:
5997: + pStart - The first point of the given dimension
5998: - pEnd - The first point following points of the given dimension

6000:   Note:
6001:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6002:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6003:   then the interval is empty.

6005:   Level: intermediate

6007: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
6008: @*/
6009: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6010: {
6011:   PetscInt       d;

6016:   DMGetDimension(dm, &d);
6017:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
6018:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
6019:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
6020:   return(0);
6021: }

6023: /*@
6024:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

6026:   Collective on dm

6028:   Input Parameters:
6029: + dm - the DM
6030: - c - coordinate vector

6032:   Notes:
6033:   The coordinates do include those for ghost points, which are in the local vector.

6035:   The vector c should be destroyed by the caller.

6037:   Level: intermediate

6039: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6040: @*/
6041: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6042: {

6048:   PetscObjectReference((PetscObject) c);
6049:   VecDestroy(&dm->coordinates);
6050:   dm->coordinates = c;
6051:   VecDestroy(&dm->coordinatesLocal);
6052:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6053:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6054:   return(0);
6055: }

6057: /*@
6058:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

6060:   Not collective

6062:    Input Parameters:
6063: +  dm - the DM
6064: -  c - coordinate vector

6066:   Notes:
6067:   The coordinates of ghost points can be set using DMSetCoordinates()
6068:   followed by DMGetCoordinatesLocal(). This is intended to enable the
6069:   setting of ghost coordinates outside of the domain.

6071:   The vector c should be destroyed by the caller.

6073:   Level: intermediate

6075: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6076: @*/
6077: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6078: {

6084:   PetscObjectReference((PetscObject) c);
6085:   VecDestroy(&dm->coordinatesLocal);

6087:   dm->coordinatesLocal = c;

6089:   VecDestroy(&dm->coordinates);
6090:   return(0);
6091: }

6093: /*@
6094:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

6096:   Collective on dm

6098:   Input Parameter:
6099: . dm - the DM

6101:   Output Parameter:
6102: . c - global coordinate vector

6104:   Note:
6105:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6106:   destroyed the array will no longer be valid.

6108:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

6110:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6111:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6113:   Level: intermediate

6115: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6116: @*/
6117: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6118: {

6124:   if (!dm->coordinates && dm->coordinatesLocal) {
6125:     DM        cdm = NULL;
6126:     PetscBool localized;

6128:     DMGetCoordinateDM(dm, &cdm);
6129:     DMCreateGlobalVector(cdm, &dm->coordinates);
6130:     DMGetCoordinatesLocalized(dm, &localized);
6131:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6132:     if (localized) {
6133:       PetscInt cdim;

6135:       DMGetCoordinateDim(dm, &cdim);
6136:       VecSetBlockSize(dm->coordinates, cdim);
6137:     }
6138:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6139:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6140:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6141:   }
6142:   *c = dm->coordinates;
6143:   return(0);
6144: }

6146: /*@
6147:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

6149:   Collective on dm

6151:   Input Parameter:
6152: . dm - the DM

6154:   Level: advanced

6156: .seealso: DMGetCoordinatesLocalNoncollective()
6157: @*/
6158: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6159: {

6164:   if (!dm->coordinatesLocal && dm->coordinates) {
6165:     DM        cdm = NULL;
6166:     PetscBool localized;

6168:     DMGetCoordinateDM(dm, &cdm);
6169:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6170:     DMGetCoordinatesLocalized(dm, &localized);
6171:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6172:     if (localized) {
6173:       PetscInt cdim;

6175:       DMGetCoordinateDim(dm, &cdim);
6176:       VecSetBlockSize(dm->coordinates, cdim);
6177:     }
6178:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6179:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6180:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6181:   }
6182:   return(0);
6183: }

6185: /*@
6186:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

6188:   Collective on dm

6190:   Input Parameter:
6191: . dm - the DM

6193:   Output Parameter:
6194: . c - coordinate vector

6196:   Note:
6197:   This is a borrowed reference, so the user should NOT destroy this vector

6199:   Each process has the local and ghost coordinates

6201:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6202:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6204:   Level: intermediate

6206: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6207: @*/
6208: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6209: {

6215:   DMGetCoordinatesLocalSetUp(dm);
6216:   *c = dm->coordinatesLocal;
6217:   return(0);
6218: }

6220: /*@
6221:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6223:   Not collective

6225:   Input Parameter:
6226: . dm - the DM

6228:   Output Parameter:
6229: . c - coordinate vector

6231:   Level: advanced

6233: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6234: @*/
6235: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6236: {
6240:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6241:   *c = dm->coordinatesLocal;
6242:   return(0);
6243: }

6245: /*@
6246:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6248:   Not collective

6250:   Input Parameter:
6251: + dm - the DM
6252: - p - the IS of points whose coordinates will be returned

6254:   Output Parameter:
6255: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6256: - pCoord - the Vec with coordinates of points in p

6258:   Note:
6259:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6261:   This creates a new vector, so the user SHOULD destroy this vector

6263:   Each process has the local and ghost coordinates

6265:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6266:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6268:   Level: advanced

6270: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6271: @*/
6272: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6273: {
6274:   PetscSection        cs, newcs;
6275:   Vec                 coords;
6276:   const PetscScalar   *arr;
6277:   PetscScalar         *newarr=NULL;
6278:   PetscInt            n;
6279:   PetscErrorCode      ierr;

6286:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6287:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6288:   cs = dm->coordinateDM->localSection;
6289:   coords = dm->coordinatesLocal;
6290:   VecGetArrayRead(coords, &arr);
6291:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6292:   VecRestoreArrayRead(coords, &arr);
6293:   if (pCoord) {
6294:     PetscSectionGetStorageSize(newcs, &n);
6295:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6296:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6297:     VecReplaceArray(*pCoord, newarr);
6298:   } else {
6299:     PetscFree(newarr);
6300:   }
6301:   if (pCoordSection) {*pCoordSection = newcs;}
6302:   else               {PetscSectionDestroy(&newcs);}
6303:   return(0);
6304: }

6306: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6307: {

6313:   if (!dm->coordinateField) {
6314:     if (dm->ops->createcoordinatefield) {
6315:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6316:     }
6317:   }
6318:   *field = dm->coordinateField;
6319:   return(0);
6320: }

6322: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6323: {

6329:   PetscObjectReference((PetscObject)field);
6330:   DMFieldDestroy(&dm->coordinateField);
6331:   dm->coordinateField = field;
6332:   return(0);
6333: }

6335: /*@
6336:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

6338:   Collective on dm

6340:   Input Parameter:
6341: . dm - the DM

6343:   Output Parameter:
6344: . cdm - coordinate DM

6346:   Level: intermediate

6348: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6349: @*/
6350: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6351: {

6357:   if (!dm->coordinateDM) {
6358:     DM cdm;

6360:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6361:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6362:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6363:      * until the call to CreateCoordinateDM) */
6364:     DMDestroy(&dm->coordinateDM);
6365:     dm->coordinateDM = cdm;
6366:   }
6367:   *cdm = dm->coordinateDM;
6368:   return(0);
6369: }

6371: /*@
6372:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

6374:   Logically Collective on dm

6376:   Input Parameters:
6377: + dm - the DM
6378: - cdm - coordinate DM

6380:   Level: intermediate

6382: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6383: @*/
6384: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6385: {

6391:   PetscObjectReference((PetscObject)cdm);
6392:   DMDestroy(&dm->coordinateDM);
6393:   dm->coordinateDM = cdm;
6394:   return(0);
6395: }

6397: /*@
6398:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

6400:   Not Collective

6402:   Input Parameter:
6403: . dm - The DM object

6405:   Output Parameter:
6406: . dim - The embedding dimension

6408:   Level: intermediate

6410: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6411: @*/
6412: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6413: {
6417:   if (dm->dimEmbed == PETSC_DEFAULT) {
6418:     dm->dimEmbed = dm->dim;
6419:   }
6420:   *dim = dm->dimEmbed;
6421:   return(0);
6422: }

6424: /*@
6425:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

6427:   Not Collective

6429:   Input Parameters:
6430: + dm  - The DM object
6431: - dim - The embedding dimension

6433:   Level: intermediate

6435: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6436: @*/
6437: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6438: {
6439:   PetscDS        ds;
6440:   PetscInt       Nds, n;

6445:   dm->dimEmbed = dim;
6446:   DMGetNumDS(dm, &Nds);
6447:   for (n = 0; n < Nds; ++n) {
6448:     DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6449:     PetscDSSetCoordinateDimension(ds, dim);
6450:   }
6451:   return(0);
6452: }

6454: /*@
6455:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6457:   Collective on dm

6459:   Input Parameter:
6460: . dm - The DM object

6462:   Output Parameter:
6463: . section - The PetscSection object

6465:   Level: intermediate

6467: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6468: @*/
6469: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6470: {
6471:   DM             cdm;

6477:   DMGetCoordinateDM(dm, &cdm);
6478:   DMGetLocalSection(cdm, section);
6479:   return(0);
6480: }

6482: /*@
6483:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6485:   Not Collective

6487:   Input Parameters:
6488: + dm      - The DM object
6489: . dim     - The embedding dimension, or PETSC_DETERMINE
6490: - section - The PetscSection object

6492:   Level: intermediate

6494: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6495: @*/
6496: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6497: {
6498:   DM             cdm;

6504:   DMGetCoordinateDM(dm, &cdm);
6505:   DMSetLocalSection(cdm, section);
6506:   if (dim == PETSC_DETERMINE) {
6507:     PetscInt d = PETSC_DEFAULT;
6508:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6510:     PetscSectionGetChart(section, &pStart, &pEnd);
6511:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6512:     pStart = PetscMax(vStart, pStart);
6513:     pEnd   = PetscMin(vEnd, pEnd);
6514:     for (v = pStart; v < pEnd; ++v) {
6515:       PetscSectionGetDof(section, v, &dd);
6516:       if (dd) {d = dd; break;}
6517:     }
6518:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6519:   }
6520:   return(0);
6521: }

6523: /*@
6524:   DMProjectCoordinates - Project coordinates to a different space

6526:   Input Parameters:
6527: + dm      - The DM object
6528: - disc    - The new coordinate discretization

6530:   Level: intermediate

6532: .seealso: DMGetCoordinateField()
6533: @*/
6534: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6535: {
6536:   PetscObject    discOld;
6537:   PetscClassId   classid;
6538:   DM             cdmOld,cdmNew;
6539:   Vec            coordsOld,coordsNew;
6540:   Mat            matInterp;


6547:   DMGetCoordinateDM(dm, &cdmOld);
6548:   /* Check current discretization is compatible */
6549:   DMGetField(cdmOld, 0, NULL, &discOld);
6550:   PetscObjectGetClassId(discOld, &classid);
6551:   if (classid != PETSCFE_CLASSID) {
6552:     if (classid == PETSC_CONTAINER_CLASSID) {
6553:       PetscFE        feLinear;
6554:       DMPolytopeType ct;
6555:       PetscInt       dim, dE, cStart;
6556:       PetscBool      simplex;

6558:       /* Assume linear vertex coordinates */
6559:       DMGetDimension(dm, &dim);
6560:       DMGetCoordinateDim(dm, &dE);
6561:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6562:       DMPlexGetCellType(dm, cStart, &ct);
6563:       switch (ct) {
6564:         case DM_POLYTOPE_TRI_PRISM:
6565:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6566:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6567:         default: break;
6568:       }
6569:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6570:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6571:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6572:       PetscFEDestroy(&feLinear);
6573:       DMCreateDS(cdmOld);
6574:     } else {
6575:       const char *discname;

6577:       PetscObjectGetType(discOld, &discname);
6578:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6579:     }
6580:   }
6581:   /* Make a fresh clone of the coordinate DM */
6582:   DMClone(cdmOld, &cdmNew);
6583:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6584:   DMCreateDS(cdmNew);
6585:   /* Project the coordinate vector from old to new space  */
6586:   DMGetCoordinates(dm, &coordsOld);
6587:   DMCreateGlobalVector(cdmNew, &coordsNew);
6588:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6589:   MatInterpolate(matInterp, coordsOld, coordsNew);
6590:   MatDestroy(&matInterp);
6591:   /* Set new coordinate structures */
6592:   DMSetCoordinateField(dm, NULL);
6593:   DMSetCoordinateDM(dm, cdmNew);
6594:   DMSetCoordinates(dm, coordsNew);
6595:   VecDestroy(&coordsNew);
6596:   DMDestroy(&cdmNew);
6597:   return(0);
6598: }

6600: /*@C
6601:   DMGetPeriodicity - Get the description of mesh periodicity

6603:   Input Parameters:
6604: . dm      - The DM object

6606:   Output Parameters:
6607: + per     - Whether the DM is periodic or not
6608: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6609: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6610: - bd      - This describes the type of periodicity in each topological dimension

6612:   Level: developer

6614: .seealso: DMGetPeriodicity()
6615: @*/
6616: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6617: {
6620:   if (per)     *per     = dm->periodic;
6621:   if (L)       *L       = dm->L;
6622:   if (maxCell) *maxCell = dm->maxCell;
6623:   if (bd)      *bd      = dm->bdtype;
6624:   return(0);
6625: }

6627: /*@C
6628:   DMSetPeriodicity - Set the description of mesh periodicity

6630:   Input Parameters:
6631: + dm      - The DM object
6632: . per     - Whether the DM is periodic or not.
6633: . 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.
6634: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6635: - bd      - This describes the type of periodicity in each topological dimension

6637:   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.

6639:   Level: developer

6641: .seealso: DMGetPeriodicity()
6642: @*/
6643: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6644: {
6645:   PetscInt       dim, d;

6654:   DMGetDimension(dm, &dim);
6655:   if (maxCell) {
6656:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6657:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6658:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6659:     PetscFree(dm->maxCell);
6660:   }

6662:   if (L) {
6663:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6664:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6665:   }
6666:   if (bd) {
6667:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6668:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6669:   }
6670:   dm->periodic = per;
6671:   return(0);
6672: }

6674: /*@
6675:   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.

6677:   Input Parameters:
6678: + dm     - The DM
6679: . in     - The input coordinate point (dim numbers)
6680: - endpoint - Include the endpoint L_i

6682:   Output Parameter:
6683: . out - The localized coordinate point

6685:   Level: developer

6687: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6688: @*/
6689: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6690: {
6691:   PetscInt       dim, d;

6695:   DMGetCoordinateDim(dm, &dim);
6696:   if (!dm->maxCell) {
6697:     for (d = 0; d < dim; ++d) out[d] = in[d];
6698:   } else {
6699:     if (endpoint) {
6700:       for (d = 0; d < dim; ++d) {
6701:         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)) {
6702:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6703:         } else {
6704:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6705:         }
6706:       }
6707:     } else {
6708:       for (d = 0; d < dim; ++d) {
6709:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6710:       }
6711:     }
6712:   }
6713:   return(0);
6714: }

6716: /*
6717:   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.

6719:   Input Parameters:
6720: + dm     - The DM
6721: . dim    - The spatial dimension
6722: . anchor - The anchor point, the input point can be no more than maxCell away from it
6723: - in     - The input coordinate point (dim numbers)

6725:   Output Parameter:
6726: . out - The localized coordinate point

6728:   Level: developer

6730:   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

6732: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6733: */
6734: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6735: {
6736:   PetscInt d;

6739:   if (!dm->maxCell) {
6740:     for (d = 0; d < dim; ++d) out[d] = in[d];
6741:   } else {
6742:     for (d = 0; d < dim; ++d) {
6743:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6744:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6745:       } else {
6746:         out[d] = in[d];
6747:       }
6748:     }
6749:   }
6750:   return(0);
6751: }

6753: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6754: {
6755:   PetscInt d;

6758:   if (!dm->maxCell) {
6759:     for (d = 0; d < dim; ++d) out[d] = in[d];
6760:   } else {
6761:     for (d = 0; d < dim; ++d) {
6762:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6763:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6764:       } else {
6765:         out[d] = in[d];
6766:       }
6767:     }
6768:   }
6769:   return(0);
6770: }

6772: /*
6773:   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.

6775:   Input Parameters:
6776: + dm     - The DM
6777: . dim    - The spatial dimension
6778: . anchor - The anchor point, the input point can be no more than maxCell away from it
6779: . in     - The input coordinate delta (dim numbers)
6780: - out    - The input coordinate point (dim numbers)

6782:   Output Parameter:
6783: . out    - The localized coordinate in + out

6785:   Level: developer

6787:   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

6789: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6790: */
6791: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6792: {
6793:   PetscInt d;

6796:   if (!dm->maxCell) {
6797:     for (d = 0; d < dim; ++d) out[d] += in[d];
6798:   } else {
6799:     for (d = 0; d < dim; ++d) {
6800:       const PetscReal maxC = dm->maxCell[d];

6802:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6803:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6805:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6806:           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]));
6807:         out[d] += newCoord;
6808:       } else {
6809:         out[d] += in[d];
6810:       }
6811:     }
6812:   }
6813:   return(0);
6814: }

6816: /*@
6817:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6819:   Not collective

6821:   Input Parameter:
6822: . dm - The DM

6824:   Output Parameter:
6825:   areLocalized - True if localized

6827:   Level: developer

6829: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6830: @*/
6831: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6832: {
6833:   DM             cdm;
6834:   PetscSection   coordSection;
6835:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6836:   PetscBool      isPlex, alreadyLocalized;

6842:   *areLocalized = PETSC_FALSE;

6844:   /* We need some generic way of refering to cells/vertices */
6845:   DMGetCoordinateDM(dm, &cdm);
6846:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6847:   if (!isPlex) return(0);

6849:   DMGetCoordinateSection(dm, &coordSection);
6850:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6851:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6852:   alreadyLocalized = PETSC_FALSE;
6853:   for (c = cStart; c < cEnd; ++c) {
6854:     if (c < sStart || c >= sEnd) continue;
6855:     PetscSectionGetDof(coordSection, c, &dof);
6856:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6857:   }
6858:   *areLocalized = alreadyLocalized;
6859:   return(0);
6860: }

6862: /*@
6863:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6865:   Collective on dm

6867:   Input Parameter:
6868: . dm - The DM

6870:   Output Parameter:
6871:   areLocalized - True if localized

6873:   Level: developer

6875: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6876: @*/
6877: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6878: {
6879:   PetscBool      localized;

6885:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6886:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6887:   return(0);
6888: }

6890: /*@
6891:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6893:   Collective on dm

6895:   Input Parameter:
6896: . dm - The DM

6898:   Level: developer

6900: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6901: @*/
6902: PetscErrorCode DMLocalizeCoordinates(DM dm)
6903: {
6904:   DM             cdm;
6905:   PetscSection   coordSection, cSection;
6906:   Vec            coordinates,  cVec;
6907:   PetscScalar   *coords, *coords2, *anchor, *localized;
6908:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6909:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6910:   PetscInt       maxHeight = 0, h;
6911:   PetscInt       *pStart = NULL, *pEnd = NULL;

6916:   if (!dm->periodic) return(0);
6917:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6918:   if (alreadyLocalized) return(0);

6920:   /* We need some generic way of refering to cells/vertices */
6921:   DMGetCoordinateDM(dm, &cdm);
6922:   {
6923:     PetscBool isplex;

6925:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6926:     if (isplex) {
6927:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6928:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6929:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6930:       pEnd = &pStart[maxHeight + 1];
6931:       newStart = vStart;
6932:       newEnd   = vEnd;
6933:       for (h = 0; h <= maxHeight; h++) {
6934:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6935:         newStart = PetscMin(newStart,pStart[h]);
6936:         newEnd   = PetscMax(newEnd,pEnd[h]);
6937:       }
6938:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6939:   }
6940:   DMGetCoordinatesLocal(dm, &coordinates);
6941:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6942:   DMGetCoordinateSection(dm, &coordSection);
6943:   VecGetBlockSize(coordinates, &bs);
6944:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6946:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6947:   PetscSectionSetNumFields(cSection, 1);
6948:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6949:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6950:   PetscSectionSetChart(cSection, newStart, newEnd);

6952:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6953:   localized = &anchor[bs];
6954:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6955:   for (h = 0; h <= maxHeight; h++) {
6956:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6958:     for (c = cStart; c < cEnd; ++c) {
6959:       PetscScalar *cellCoords = NULL;
6960:       PetscInt     b;

6962:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6963:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6964:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6965:       for (d = 0; d < dof/bs; ++d) {
6966:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6967:         for (b = 0; b < bs; b++) {
6968:           if (cellCoords[d*bs + b] != localized[b]) break;
6969:         }
6970:         if (b < bs) break;
6971:       }
6972:       if (d < dof/bs) {
6973:         if (c >= sStart && c < sEnd) {
6974:           PetscInt cdof;

6976:           PetscSectionGetDof(coordSection, c, &cdof);
6977:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6978:         }
6979:         PetscSectionSetDof(cSection, c, dof);
6980:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6981:       }
6982:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6983:     }
6984:   }
6985:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6986:   if (alreadyLocalizedGlobal) {
6987:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6988:     PetscSectionDestroy(&cSection);
6989:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6990:     return(0);
6991:   }
6992:   for (v = vStart; v < vEnd; ++v) {
6993:     PetscSectionGetDof(coordSection, v, &dof);
6994:     PetscSectionSetDof(cSection, v, dof);
6995:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6996:   }
6997:   PetscSectionSetUp(cSection);
6998:   PetscSectionGetStorageSize(cSection, &coordSize);
6999:   VecCreate(PETSC_COMM_SELF, &cVec);
7000:   PetscObjectSetName((PetscObject)cVec,"coordinates");
7001:   VecSetBlockSize(cVec, bs);
7002:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
7003:   VecSetType(cVec, VECSTANDARD);
7004:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
7005:   VecGetArray(cVec, &coords2);
7006:   for (v = vStart; v < vEnd; ++v) {
7007:     PetscSectionGetDof(coordSection, v, &dof);
7008:     PetscSectionGetOffset(coordSection, v, &off);
7009:     PetscSectionGetOffset(cSection,     v, &off2);
7010:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7011:   }
7012:   for (h = 0; h <= maxHeight; h++) {
7013:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7015:     for (c = cStart; c < cEnd; ++c) {
7016:       PetscScalar *cellCoords = NULL;
7017:       PetscInt     b, cdof;

7019:       PetscSectionGetDof(cSection,c,&cdof);
7020:       if (!cdof) continue;
7021:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7022:       PetscSectionGetOffset(cSection, c, &off2);
7023:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7024:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
7025:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7026:     }
7027:   }
7028:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7029:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7030:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
7031:   VecRestoreArray(cVec, &coords2);
7032:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
7033:   DMSetCoordinatesLocal(dm, cVec);
7034:   VecDestroy(&cVec);
7035:   PetscSectionDestroy(&cSection);
7036:   return(0);
7037: }

7039: /*@
7040:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

7042:   Collective on v (see explanation below)

7044:   Input Parameters:
7045: + dm - The DM
7046: . v - The Vec of points
7047: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
7048: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

7050:   Output Parameter:
7051: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7052: - cells - The PetscSF containing the ranks and local indices of the containing points.


7055:   Level: developer

7057:   Notes:
7058:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7059:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

7061:   If *cellSF is NULL on input, a PetscSF will be created.
7062:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

7064:   An array that maps each point to its containing cell can be obtained with

7066: $    const PetscSFNode *cells;
7067: $    PetscInt           nFound;
7068: $    const PetscInt    *found;
7069: $
7070: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

7072:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7073:   the index of the cell in its rank's local numbering.

7075: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7076: @*/
7077: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7078: {

7085:   if (*cellSF) {
7086:     PetscMPIInt result;

7089:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7090:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7091:   } else {
7092:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7093:   }
7094:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7095:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7096:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7097:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7098:   return(0);
7099: }

7101: /*@
7102:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7104:   Collective on dm

7106:   Input Parameter:
7107: . dm - The original DM

7109:   Output Parameter:
7110: . odm - The DM which provides the layout for output

7112:   Level: intermediate

7114: .seealso: VecView(), DMGetGlobalSection()
7115: @*/
7116: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7117: {
7118:   PetscSection   section;
7119:   PetscBool      hasConstraints, ghasConstraints;

7125:   DMGetLocalSection(dm, &section);
7126:   PetscSectionHasConstraints(section, &hasConstraints);
7127:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7128:   if (!ghasConstraints) {
7129:     *odm = dm;
7130:     return(0);
7131:   }
7132:   if (!dm->dmBC) {
7133:     PetscSection newSection, gsection;
7134:     PetscSF      sf;

7136:     DMClone(dm, &dm->dmBC);
7137:     DMCopyDisc(dm, dm->dmBC);
7138:     PetscSectionClone(section, &newSection);
7139:     DMSetLocalSection(dm->dmBC, newSection);
7140:     PetscSectionDestroy(&newSection);
7141:     DMGetPointSF(dm->dmBC, &sf);
7142:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7143:     DMSetGlobalSection(dm->dmBC, gsection);
7144:     PetscSectionDestroy(&gsection);
7145:   }
7146:   *odm = dm->dmBC;
7147:   return(0);
7148: }

7150: /*@
7151:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7153:   Input Parameter:
7154: . dm - The original DM

7156:   Output Parameters:
7157: + num - The output sequence number
7158: - val - The output sequence value

7160:   Level: intermediate

7162:   Note: This is intended for output that should appear in sequence, for instance
7163:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7165: .seealso: VecView()
7166: @*/
7167: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7168: {
7173:   return(0);
7174: }

7176: /*@
7177:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7179:   Input Parameters:
7180: + dm - The original DM
7181: . num - The output sequence number
7182: - val - The output sequence value

7184:   Level: intermediate

7186:   Note: This is intended for output that should appear in sequence, for instance
7187:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7189: .seealso: VecView()
7190: @*/
7191: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7192: {
7195:   dm->outputSequenceNum = num;
7196:   dm->outputSequenceVal = val;
7197:   return(0);
7198: }

7200: /*@C
7201:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7203:   Input Parameters:
7204: + dm   - The original DM
7205: . name - The sequence name
7206: - num  - The output sequence number

7208:   Output Parameter:
7209: . val  - The output sequence value

7211:   Level: intermediate

7213:   Note: This is intended for output that should appear in sequence, for instance
7214:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7216: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7217: @*/
7218: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7219: {
7220:   PetscBool      ishdf5;

7227:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7228:   if (ishdf5) {
7229: #if defined(PETSC_HAVE_HDF5)
7230:     PetscScalar value;

7232:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7233:     *val = PetscRealPart(value);
7234: #endif
7235:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7236:   return(0);
7237: }

7239: /*@
7240:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

7242:   Not collective

7244:   Input Parameter:
7245: . dm - The DM

7247:   Output Parameter:
7248: . useNatural - The flag to build the mapping to a natural order during distribution

7250:   Level: beginner

7252: .seealso: DMSetUseNatural(), DMCreate()
7253: @*/
7254: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7255: {
7259:   *useNatural = dm->useNatural;
7260:   return(0);
7261: }

7263: /*@
7264:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7266:   Collective on dm

7268:   Input Parameters:
7269: + dm - The DM
7270: - useNatural - The flag to build the mapping to a natural order during distribution

7272:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7274:   Level: beginner

7276: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7277: @*/
7278: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7279: {
7283:   dm->useNatural = useNatural;
7284:   return(0);
7285: }


7288: /*@C
7289:   DMCreateLabel - Create a label of the given name if it does not already exist

7291:   Not Collective

7293:   Input Parameters:
7294: + dm   - The DM object
7295: - name - The label name

7297:   Level: intermediate

7299: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7300: @*/
7301: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7302: {
7303:   PetscBool      flg;
7304:   DMLabel        label;

7310:   DMHasLabel(dm, name, &flg);
7311:   if (!flg) {
7312:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7313:     DMAddLabel(dm, label);
7314:     DMLabelDestroy(&label);
7315:   }
7316:   return(0);
7317: }

7319: /*@C
7320:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

7322:   Not Collective

7324:   Input Parameters:
7325: + dm   - The DM object
7326: . l    - The index for the label
7327: - name - The label name

7329:   Level: intermediate

7331: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7332: @*/
7333: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7334: {
7335:   DMLabelLink    orig, prev = NULL;
7336:   DMLabel        label;
7337:   PetscInt       Nl, m;
7338:   PetscBool      flg, match;
7339:   const char    *lname;

7345:   DMHasLabel(dm, name, &flg);
7346:   if (!flg) {
7347:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7348:     DMAddLabel(dm, label);
7349:     DMLabelDestroy(&label);
7350:   }
7351:   DMGetNumLabels(dm, &Nl);
7352:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7353:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7354:     PetscObjectGetName((PetscObject) orig->label, &lname);
7355:     PetscStrcmp(name, lname, &match);
7356:     if (match) break;
7357:   }
7358:   if (m == l) return(0);
7359:   if (!m) dm->labels = orig->next;
7360:   else    prev->next = orig->next;
7361:   if (!l) {
7362:     orig->next = dm->labels;
7363:     dm->labels = orig;
7364:   } else {
7365:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7366:     orig->next = prev->next;
7367:     prev->next = orig;
7368:   }
7369:   return(0);
7370: }

7372: /*@C
7373:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

7375:   Not Collective

7377:   Input Parameters:
7378: + dm   - The DM object
7379: . name - The label name
7380: - point - The mesh point

7382:   Output Parameter:
7383: . value - The label value for this point, or -1 if the point is not in the label

7385:   Level: beginner

7387: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7388: @*/
7389: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7390: {
7391:   DMLabel        label;

7397:   DMGetLabel(dm, name, &label);
7398:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7399:   DMLabelGetValue(label, point, value);
7400:   return(0);
7401: }

7403: /*@C
7404:   DMSetLabelValue - Add a point to a Sieve Label with given value

7406:   Not Collective

7408:   Input Parameters:
7409: + dm   - The DM object
7410: . name - The label name
7411: . point - The mesh point
7412: - value - The label value for this point

7414:   Output Parameter:

7416:   Level: beginner

7418: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7419: @*/
7420: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7421: {
7422:   DMLabel        label;

7428:   DMGetLabel(dm, name, &label);
7429:   if (!label) {
7430:     DMCreateLabel(dm, name);
7431:     DMGetLabel(dm, name, &label);
7432:   }
7433:   DMLabelSetValue(label, point, value);
7434:   return(0);
7435: }

7437: /*@C
7438:   DMClearLabelValue - Remove a point from a Sieve Label with given value

7440:   Not Collective

7442:   Input Parameters:
7443: + dm   - The DM object
7444: . name - The label name
7445: . point - The mesh point
7446: - value - The label value for this point

7448:   Output Parameter:

7450:   Level: beginner

7452: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7453: @*/
7454: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7455: {
7456:   DMLabel        label;

7462:   DMGetLabel(dm, name, &label);
7463:   if (!label) return(0);
7464:   DMLabelClearValue(label, point, value);
7465:   return(0);
7466: }

7468: /*@C
7469:   DMGetLabelSize - Get the number of different integer ids in a Label

7471:   Not Collective

7473:   Input Parameters:
7474: + dm   - The DM object
7475: - name - The label name

7477:   Output Parameter:
7478: . size - The number of different integer ids, or 0 if the label does not exist

7480:   Level: beginner

7482: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7483: @*/
7484: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7485: {
7486:   DMLabel        label;

7493:   DMGetLabel(dm, name, &label);
7494:   *size = 0;
7495:   if (!label) return(0);
7496:   DMLabelGetNumValues(label, size);
7497:   return(0);
7498: }

7500: /*@C
7501:   DMGetLabelIdIS - Get the integer ids in a label

7503:   Not Collective

7505:   Input Parameters:
7506: + mesh - The DM object
7507: - name - The label name

7509:   Output Parameter:
7510: . ids - The integer ids, or NULL if the label does not exist

7512:   Level: beginner

7514: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7515: @*/
7516: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7517: {
7518:   DMLabel        label;

7525:   DMGetLabel(dm, name, &label);
7526:   *ids = NULL;
7527:  if (label) {
7528:     DMLabelGetValueIS(label, ids);
7529:   } else {
7530:     /* returning an empty IS */
7531:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7532:   }
7533:   return(0);
7534: }

7536: /*@C
7537:   DMGetStratumSize - Get the number of points in a label stratum

7539:   Not Collective

7541:   Input Parameters:
7542: + dm - The DM object
7543: . name - The label name
7544: - value - The stratum value

7546:   Output Parameter:
7547: . size - The stratum size

7549:   Level: beginner

7551: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7552: @*/
7553: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7554: {
7555:   DMLabel        label;

7562:   DMGetLabel(dm, name, &label);
7563:   *size = 0;
7564:   if (!label) return(0);
7565:   DMLabelGetStratumSize(label, value, size);
7566:   return(0);
7567: }

7569: /*@C
7570:   DMGetStratumIS - Get the points in a label stratum

7572:   Not Collective

7574:   Input Parameters:
7575: + dm - The DM object
7576: . name - The label name
7577: - value - The stratum value

7579:   Output Parameter:
7580: . points - The stratum points, or NULL if the label does not exist or does not have that value

7582:   Level: beginner

7584: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7585: @*/
7586: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7587: {
7588:   DMLabel        label;

7595:   DMGetLabel(dm, name, &label);
7596:   *points = NULL;
7597:   if (!label) return(0);
7598:   DMLabelGetStratumIS(label, value, points);
7599:   return(0);
7600: }

7602: /*@C
7603:   DMSetStratumIS - Set the points in a label stratum

7605:   Not Collective

7607:   Input Parameters:
7608: + dm - The DM object
7609: . name - The label name
7610: . value - The stratum value
7611: - points - The stratum points

7613:   Level: beginner

7615: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7616: @*/
7617: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7618: {
7619:   DMLabel        label;

7626:   DMGetLabel(dm, name, &label);
7627:   if (!label) return(0);
7628:   DMLabelSetStratumIS(label, value, points);
7629:   return(0);
7630: }

7632: /*@C
7633:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7635:   Not Collective

7637:   Input Parameters:
7638: + dm   - The DM object
7639: . name - The label name
7640: - value - The label value for this point

7642:   Output Parameter:

7644:   Level: beginner

7646: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7647: @*/
7648: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7649: {
7650:   DMLabel        label;

7656:   DMGetLabel(dm, name, &label);
7657:   if (!label) return(0);
7658:   DMLabelClearStratum(label, value);
7659:   return(0);
7660: }

7662: /*@
7663:   DMGetNumLabels - Return the number of labels defined by the mesh

7665:   Not Collective

7667:   Input Parameter:
7668: . dm   - The DM object

7670:   Output Parameter:
7671: . numLabels - the number of Labels

7673:   Level: intermediate

7675: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7676: @*/
7677: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7678: {
7679:   DMLabelLink next = dm->labels;
7680:   PetscInt  n    = 0;

7685:   while (next) {++n; next = next->next;}
7686:   *numLabels = n;
7687:   return(0);
7688: }

7690: /*@C
7691:   DMGetLabelName - Return the name of nth label

7693:   Not Collective

7695:   Input Parameters:
7696: + dm - The DM object
7697: - n  - the label number

7699:   Output Parameter:
7700: . name - the label name

7702:   Level: intermediate

7704: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7705: @*/
7706: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7707: {
7708:   DMLabelLink    next = dm->labels;
7709:   PetscInt       l    = 0;

7715:   while (next) {
7716:     if (l == n) {
7717:       PetscObjectGetName((PetscObject) next->label, name);
7718:       return(0);
7719:     }
7720:     ++l;
7721:     next = next->next;
7722:   }
7723:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7724: }

7726: /*@C
7727:   DMHasLabel - Determine whether the mesh has a label of a given name

7729:   Not Collective

7731:   Input Parameters:
7732: + dm   - The DM object
7733: - name - The label name

7735:   Output Parameter:
7736: . hasLabel - PETSC_TRUE if the label is present

7738:   Level: intermediate

7740: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7741: @*/
7742: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7743: {
7744:   DMLabelLink    next = dm->labels;
7745:   const char    *lname;

7752:   *hasLabel = PETSC_FALSE;
7753:   while (next) {
7754:     PetscObjectGetName((PetscObject) next->label, &lname);
7755:     PetscStrcmp(name, lname, hasLabel);
7756:     if (*hasLabel) break;
7757:     next = next->next;
7758:   }
7759:   return(0);
7760: }

7762: /*@C
7763:   DMGetLabel - Return the label of a given name, or NULL

7765:   Not Collective

7767:   Input Parameters:
7768: + dm   - The DM object
7769: - name - The label name

7771:   Output Parameter:
7772: . label - The DMLabel, or NULL if the label is absent

7774:   Note: Some of the default labels in a DMPlex will be
7775: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7776: $ "celltype"    - Holds the topological type of each cell
7777: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7778: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7779: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7780: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7782:   Level: intermediate

7784: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7785: @*/
7786: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7787: {
7788:   DMLabelLink    next = dm->labels;
7789:   PetscBool      hasLabel;
7790:   const char    *lname;

7797:   *label = NULL;
7798:   while (next) {
7799:     PetscObjectGetName((PetscObject) next->label, &lname);
7800:     PetscStrcmp(name, lname, &hasLabel);
7801:     if (hasLabel) {
7802:       *label = next->label;
7803:       break;
7804:     }
7805:     next = next->next;
7806:   }
7807:   return(0);
7808: }

7810: /*@C
7811:   DMGetLabelByNum - Return the nth label

7813:   Not Collective

7815:   Input Parameters:
7816: + dm - The DM object
7817: - n  - the label number

7819:   Output Parameter:
7820: . label - the label

7822:   Level: intermediate

7824: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7825: @*/
7826: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7827: {
7828:   DMLabelLink next = dm->labels;
7829:   PetscInt    l    = 0;

7834:   while (next) {
7835:     if (l == n) {
7836:       *label = next->label;
7837:       return(0);
7838:     }
7839:     ++l;
7840:     next = next->next;
7841:   }
7842:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7843: }

7845: /*@C
7846:   DMAddLabel - Add the label to this mesh

7848:   Not Collective

7850:   Input Parameters:
7851: + dm   - The DM object
7852: - label - The DMLabel

7854:   Level: developer

7856: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7857: @*/
7858: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7859: {
7860:   DMLabelLink    l, *p, tmpLabel;
7861:   PetscBool      hasLabel;
7862:   const char    *lname;
7863:   PetscBool      flg;

7868:   PetscObjectGetName((PetscObject) label, &lname);
7869:   DMHasLabel(dm, lname, &hasLabel);
7870:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7871:   PetscCalloc1(1, &tmpLabel);
7872:   tmpLabel->label  = label;
7873:   tmpLabel->output = PETSC_TRUE;
7874:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7875:   *p = tmpLabel;
7876:   PetscObjectReference((PetscObject)label);
7877:   PetscStrcmp(lname, "depth", &flg);
7878:   if (flg) dm->depthLabel = label;
7879:   PetscStrcmp(lname, "celltype", &flg);
7880:   if (flg) dm->celltypeLabel = label;
7881:   return(0);
7882: }

7884: /*@C
7885:   DMRemoveLabel - Remove the label given by name from this mesh

7887:   Not Collective

7889:   Input Parameters:
7890: + dm   - The DM object
7891: - name - The label name

7893:   Output Parameter:
7894: . label - The DMLabel, or NULL if the label is absent

7896:   Level: developer

7898:   Notes:
7899:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7900:   DMLabelDestroy() on the label.

7902:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7903:   call DMLabelDestroy(). Instead, the label is returned and the user is
7904:   responsible of calling DMLabelDestroy() at some point.

7906: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7907: @*/
7908: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7909: {
7910:   DMLabelLink    link, *pnext;
7911:   PetscBool      hasLabel;
7912:   const char    *lname;

7918:   if (label) {
7920:     *label = NULL;
7921:   }
7922:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7923:     PetscObjectGetName((PetscObject) link->label, &lname);
7924:     PetscStrcmp(name, lname, &hasLabel);
7925:     if (hasLabel) {
7926:       *pnext = link->next; /* Remove from list */
7927:       PetscStrcmp(name, "depth", &hasLabel);
7928:       if (hasLabel) dm->depthLabel = NULL;
7929:       PetscStrcmp(name, "celltype", &hasLabel);
7930:       if (hasLabel) dm->celltypeLabel = NULL;
7931:       if (label) *label = link->label;
7932:       else       {DMLabelDestroy(&link->label);}
7933:       PetscFree(link);
7934:       break;
7935:     }
7936:   }
7937:   return(0);
7938: }

7940: /*@
7941:   DMRemoveLabelBySelf - Remove the label from this mesh

7943:   Not Collective

7945:   Input Parameters:
7946: + dm   - The DM object
7947: . label - (Optional) The DMLabel to be removed from the DM
7948: - failNotFound - Should it fail if the label is not found in the DM?

7950:   Level: developer

7952:   Notes:
7953:   Only exactly the same instance is removed if found, name match is ignored.
7954:   If the DM has an exclusive reference to the label, it gets destroyed and
7955:   *label nullified.

7957: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7958: @*/
7959: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7960: {
7961:   DMLabelLink    link, *pnext;
7962:   PetscBool      hasLabel = PETSC_FALSE;

7968:   if (!*label && !failNotFound) return(0);
7971:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7972:     if (*label == link->label) {
7973:       hasLabel = PETSC_TRUE;
7974:       *pnext = link->next; /* Remove from list */
7975:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7976:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7977:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7978:       DMLabelDestroy(&link->label);
7979:       PetscFree(link);
7980:       break;
7981:     }
7982:   }
7983:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7984:   return(0);
7985: }

7987: /*@C
7988:   DMGetLabelOutput - Get the output flag for a given label

7990:   Not Collective

7992:   Input Parameters:
7993: + dm   - The DM object
7994: - name - The label name

7996:   Output Parameter:
7997: . output - The flag for output

7999:   Level: developer

8001: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8002: @*/
8003: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8004: {
8005:   DMLabelLink    next = dm->labels;
8006:   const char    *lname;

8013:   while (next) {
8014:     PetscBool flg;

8016:     PetscObjectGetName((PetscObject) next->label, &lname);
8017:     PetscStrcmp(name, lname, &flg);
8018:     if (flg) {*output = next->output; return(0);}
8019:     next = next->next;
8020:   }
8021:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8022: }

8024: /*@C
8025:   DMSetLabelOutput - Set the output flag for a given label

8027:   Not Collective

8029:   Input Parameters:
8030: + dm     - The DM object
8031: . name   - The label name
8032: - output - The flag for output

8034:   Level: developer

8036: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8037: @*/
8038: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8039: {
8040:   DMLabelLink    next = dm->labels;
8041:   const char    *lname;

8047:   while (next) {
8048:     PetscBool flg;

8050:     PetscObjectGetName((PetscObject) next->label, &lname);
8051:     PetscStrcmp(name, lname, &flg);
8052:     if (flg) {next->output = output; return(0);}
8053:     next = next->next;
8054:   }
8055:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8056: }

8058: /*@
8059:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

8061:   Collective on dmA

8063:   Input Parameter:
8064: + dmA - The DM object with initial labels
8065: . dmB - The DM object with copied labels
8066: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8067: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

8069:   Level: intermediate

8071:   Note: This is typically used when interpolating or otherwise adding to a mesh

8073: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8074: @*/
8075: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8076: {
8077:   DMLabel        label, labelNew;
8078:   const char    *name;
8079:   PetscBool      flg;
8080:   DMLabelLink    link;

8088:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8089:   if (dmA == dmB) return(0);
8090:   for (link=dmA->labels; link; link=link->next) {
8091:     label=link->label;
8092:     PetscObjectGetName((PetscObject)label, &name);
8093:     if (!all) {
8094:       PetscStrcmp(name, "depth", &flg);
8095:       if (flg) continue;
8096:       PetscStrcmp(name, "dim", &flg);
8097:       if (flg) continue;
8098:       PetscStrcmp(name, "celltype", &flg);
8099:       if (flg) continue;
8100:     }
8101:     if (mode==PETSC_COPY_VALUES) {
8102:       DMLabelDuplicate(label, &labelNew);
8103:     } else {
8104:       labelNew = label;
8105:     }
8106:     DMAddLabel(dmB, labelNew);
8107:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8108:   }
8109:   return(0);
8110: }
8111: /*
8112:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8113:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8114:   (label, id) pair in the DM.

8116:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8117:   each label.
8118: */
8119: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8120: {
8121:   DMUniversalLabel ul;
8122:   PetscBool       *active;
8123:   PetscInt         pStart, pEnd, p, Nl, l, m;
8124:   PetscErrorCode   ierr;

8127:   PetscMalloc1(1, &ul);
8128:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8129:   DMGetNumLabels(dm, &Nl);
8130:   PetscCalloc1(Nl, &active);
8131:   ul->Nl = 0;
8132:   for (l = 0; l < Nl; ++l) {
8133:     PetscBool   isdepth, iscelltype;
8134:     const char *name;

8136:     DMGetLabelName(dm, l, &name);
8137:     PetscStrncmp(name, "depth", 6, &isdepth);
8138:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8139:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8140:     if (active[l]) ++ul->Nl;
8141:   }
8142:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8143:   ul->Nv = 0;
8144:   for (l = 0, m = 0; l < Nl; ++l) {
8145:     DMLabel     label;
8146:     PetscInt    nv;
8147:     const char *name;

8149:     if (!active[l]) continue;
8150:     DMGetLabelName(dm, l, &name);
8151:     DMGetLabelByNum(dm, l, &label);
8152:     DMLabelGetNumValues(label, &nv);
8153:     PetscStrallocpy(name, &ul->names[m]);
8154:     ul->indices[m]   = l;
8155:     ul->Nv          += nv;
8156:     ul->offsets[m+1] = nv;
8157:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8158:     ++m;
8159:   }
8160:   for (l = 1; l <= ul->Nl; ++l) {
8161:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8162:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8163:   }
8164:   for (l = 0; l < ul->Nl; ++l) {
8165:     PetscInt b;

8167:     ul->masks[l] = 0;
8168:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8169:   }
8170:   PetscMalloc1(ul->Nv, &ul->values);
8171:   for (l = 0, m = 0; l < Nl; ++l) {
8172:     DMLabel         label;
8173:     IS              valueIS;
8174:     const PetscInt *varr;
8175:     PetscInt        nv, v;

8177:     if (!active[l]) continue;
8178:     DMGetLabelByNum(dm, l, &label);
8179:     DMLabelGetNumValues(label, &nv);
8180:     DMLabelGetValueIS(label, &valueIS);
8181:     ISGetIndices(valueIS, &varr);
8182:     for (v = 0; v < nv; ++v) {
8183:       ul->values[ul->offsets[m]+v] = varr[v];
8184:     }
8185:     ISRestoreIndices(valueIS, &varr);
8186:     ISDestroy(&valueIS);
8187:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8188:     ++m;
8189:   }
8190:   DMPlexGetChart(dm, &pStart, &pEnd);
8191:   for (p = pStart; p < pEnd; ++p) {
8192:     PetscInt  uval = 0;
8193:     PetscBool marked = PETSC_FALSE;

8195:     for (l = 0, m = 0; l < Nl; ++l) {
8196:       DMLabel  label;
8197:       PetscInt val, defval, loc, nv;

8199:       if (!active[l]) continue;
8200:       DMGetLabelByNum(dm, l, &label);
8201:       DMLabelGetValue(label, p, &val);
8202:       DMLabelGetDefaultValue(label, &defval);
8203:       if (val == defval) {++m; continue;}
8204:       nv = ul->offsets[m+1]-ul->offsets[m];
8205:       marked = PETSC_TRUE;
8206:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8207:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8208:       uval += (loc+1) << ul->bits[m];
8209:       ++m;
8210:     }
8211:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8212:   }
8213:   PetscFree(active);
8214:   *universal = ul;
8215:   return(0);
8216: }

8218: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8219: {
8220:   PetscInt       l;

8224:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8225:   DMLabelDestroy(&(*universal)->label);
8226:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8227:   PetscFree((*universal)->values);
8228:   PetscFree(*universal);
8229:   *universal = NULL;
8230:   return(0);
8231: }

8233: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8234: {
8237:   *ulabel = ul->label;
8238:   return(0);
8239: }

8241: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8242: {
8243:   PetscInt       Nl = ul->Nl, l;

8248:   for (l = 0; l < Nl; ++l) {
8249:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8250:     else               {DMCreateLabel(dm, ul->names[l]);}
8251:   }
8252:   if (preserveOrder) {
8253:     for (l = 0; l < ul->Nl; ++l) {
8254:       const char *name;
8255:       PetscBool   match;

8257:       DMGetLabelName(dm, ul->indices[l], &name);
8258:       PetscStrcmp(name, ul->names[l], &match);
8259:       if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8260:     }
8261:   }
8262:   return(0);
8263: }

8265: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8266: {
8267:   PetscInt       l;

8271:   for (l = 0; l < ul->Nl; ++l) {
8272:     DMLabel  label;
8273:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

8275:     if (lval) {
8276:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8277:       else          {DMGetLabel(dm, ul->names[l], &label);}
8278:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8279:     }
8280:   }
8281:   return(0);
8282: }

8284: /*@
8285:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

8287:   Input Parameter:
8288: . dm - The DM object

8290:   Output Parameter:
8291: . cdm - The coarse DM

8293:   Level: intermediate

8295: .seealso: DMSetCoarseDM()
8296: @*/
8297: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8298: {
8302:   *cdm = dm->coarseMesh;
8303:   return(0);
8304: }

8306: /*@
8307:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

8309:   Input Parameters:
8310: + dm - The DM object
8311: - cdm - The coarse DM

8313:   Level: intermediate

8315: .seealso: DMGetCoarseDM()
8316: @*/
8317: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8318: {

8324:   PetscObjectReference((PetscObject)cdm);
8325:   DMDestroy(&dm->coarseMesh);
8326:   dm->coarseMesh = cdm;
8327:   return(0);
8328: }

8330: /*@
8331:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

8333:   Input Parameter:
8334: . dm - The DM object

8336:   Output Parameter:
8337: . fdm - The fine DM

8339:   Level: intermediate

8341: .seealso: DMSetFineDM()
8342: @*/
8343: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8344: {
8348:   *fdm = dm->fineMesh;
8349:   return(0);
8350: }

8352: /*@
8353:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

8355:   Input Parameters:
8356: + dm - The DM object
8357: - fdm - The fine DM

8359:   Level: intermediate

8361: .seealso: DMGetFineDM()
8362: @*/
8363: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8364: {

8370:   PetscObjectReference((PetscObject)fdm);
8371:   DMDestroy(&dm->fineMesh);
8372:   dm->fineMesh = fdm;
8373:   return(0);
8374: }

8376: /*=== DMBoundary code ===*/

8378: /*@C
8379:   DMAddBoundary - Add a boundary condition to the model

8381:   Collective on dm

8383:   Input Parameters:
8384: + dm       - The DM, with a PetscDS that matches the problem being constrained
8385: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8386: . name     - The BC name
8387: . label    - The label defining constrained points
8388: . Nv       - The number of DMLabel values for constrained points
8389: . values   - An array of values for constrained points
8390: . field    - The field to constrain
8391: . Nc       - The number of constrained field components (0 will constrain all fields)
8392: . comps    - An array of constrained component numbers
8393: . bcFunc   - A pointwise function giving boundary values
8394: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8395: - ctx      - An optional user context for bcFunc

8397:   Output Parameter:
8398: . bd          - (Optional) Boundary number

8400:   Options Database Keys:
8401: + -bc_<boundary name> <num> - Overrides the boundary ids
8402: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8404:   Note:
8405:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8407: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8409:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8411: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8412: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8413: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8414: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8416: + dim - the spatial dimension
8417: . Nf - the number of fields
8418: . uOff - the offset into u[] and u_t[] for each field
8419: . uOff_x - the offset into u_x[] for each field
8420: . u - each field evaluated at the current point
8421: . u_t - the time derivative of each field evaluated at the current point
8422: . u_x - the gradient of each field evaluated at the current point
8423: . aOff - the offset into a[] and a_t[] for each auxiliary field
8424: . aOff_x - the offset into a_x[] for each auxiliary field
8425: . a - each auxiliary field evaluated at the current point
8426: . a_t - the time derivative of each auxiliary field evaluated at the current point
8427: . a_x - the gradient of auxiliary each field evaluated at the current point
8428: . t - current time
8429: . x - coordinates of the current point
8430: . numConstants - number of constant parameters
8431: . constants - constant parameters
8432: - bcval - output values at the current point

8434:   Level: developer

8436: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8437: @*/
8438: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
8439: {
8440:   PetscDS        ds;

8450:   DMGetDS(dm, &ds);
8451:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8452:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8453:   return(0);
8454: }

8456: /* TODO Remove this since now the structures are the same */
8457: static PetscErrorCode DMPopulateBoundary(DM dm)
8458: {
8459:   PetscDS        ds;
8460:   DMBoundary    *lastnext;
8461:   DSBoundary     dsbound;

8465:   DMGetDS(dm, &ds);
8466:   dsbound = ds->boundary;
8467:   if (dm->boundary) {
8468:     DMBoundary next = dm->boundary;

8470:     /* quick check to see if the PetscDS has changed */
8471:     if (next->dsboundary == dsbound) return(0);
8472:     /* the PetscDS has changed: tear down and rebuild */
8473:     while (next) {
8474:       DMBoundary b = next;

8476:       next = b->next;
8477:       PetscFree(b);
8478:     }
8479:     dm->boundary = NULL;
8480:   }

8482:   lastnext = &(dm->boundary);
8483:   while (dsbound) {
8484:     DMBoundary dmbound;

8486:     PetscNew(&dmbound);
8487:     dmbound->dsboundary = dsbound;
8488:     dmbound->label      = dsbound->label;
8489:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8490:     *lastnext = dmbound;
8491:     lastnext = &(dmbound->next);
8492:     dsbound = dsbound->next;
8493:   }
8494:   return(0);
8495: }

8497: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8498: {
8499:   DMBoundary     b;

8505:   *isBd = PETSC_FALSE;
8506:   DMPopulateBoundary(dm);
8507:   b = dm->boundary;
8508:   while (b && !(*isBd)) {
8509:     DMLabel    label = b->label;
8510:     DSBoundary dsb   = b->dsboundary;
8511:     PetscInt   i;

8513:     if (label) {
8514:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
8515:     }
8516:     b = b->next;
8517:   }
8518:   return(0);
8519: }

8521: /*@C
8522:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8524:   Collective on DM

8526:   Input Parameters:
8527: + dm      - The DM
8528: . time    - The time
8529: . funcs   - The coordinate functions to evaluate, one per field
8530: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8531: - mode    - The insertion mode for values

8533:   Output Parameter:
8534: . X - vector

8536:    Calling sequence of func:
8537: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8539: +  dim - The spatial dimension
8540: .  time - The time at which to sample
8541: .  x   - The coordinates
8542: .  Nf  - The number of fields
8543: .  u   - The output field values
8544: -  ctx - optional user-defined function context

8546:   Level: developer

8548: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8549: @*/
8550: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8551: {
8552:   Vec            localX;

8557:   DMGetLocalVector(dm, &localX);
8558:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8559:   DMLocalToGlobalBegin(dm, localX, mode, X);
8560:   DMLocalToGlobalEnd(dm, localX, mode, X);
8561:   DMRestoreLocalVector(dm, &localX);
8562:   return(0);
8563: }

8565: /*@C
8566:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8568:   Not collective

8570:   Input Parameters:
8571: + dm      - The DM
8572: . time    - The time
8573: . funcs   - The coordinate functions to evaluate, one per field
8574: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8575: - mode    - The insertion mode for values

8577:   Output Parameter:
8578: . localX - vector

8580:    Calling sequence of func:
8581: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8583: +  dim - The spatial dimension
8584: .  x   - The coordinates
8585: .  Nf  - The number of fields
8586: .  u   - The output field values
8587: -  ctx - optional user-defined function context

8589:   Level: developer

8591: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8592: @*/
8593: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8594: {

8600:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8601:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8602:   return(0);
8603: }

8605: /*@C
8606:   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.

8608:   Collective on DM

8610:   Input Parameters:
8611: + dm      - The DM
8612: . time    - The time
8613: . label   - The DMLabel selecting the portion of the mesh for projection
8614: . funcs   - The coordinate functions to evaluate, one per field
8615: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8616: - mode    - The insertion mode for values

8618:   Output Parameter:
8619: . X - vector

8621:    Calling sequence of func:
8622: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8624: +  dim - The spatial dimension
8625: .  x   - The coordinates
8626: .  Nf  - The number of fields
8627: .  u   - The output field values
8628: -  ctx - optional user-defined function context

8630:   Level: developer

8632: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8633: @*/
8634: 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)
8635: {
8636:   Vec            localX;

8641:   DMGetLocalVector(dm, &localX);
8642:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8643:   DMLocalToGlobalBegin(dm, localX, mode, X);
8644:   DMLocalToGlobalEnd(dm, localX, mode, X);
8645:   DMRestoreLocalVector(dm, &localX);
8646:   return(0);
8647: }

8649: /*@C
8650:   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.

8652:   Not collective

8654:   Input Parameters:
8655: + dm      - The DM
8656: . time    - The time
8657: . label   - The DMLabel selecting the portion of the mesh for projection
8658: . funcs   - The coordinate functions to evaluate, one per field
8659: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8660: - mode    - The insertion mode for values

8662:   Output Parameter:
8663: . localX - vector

8665:    Calling sequence of func:
8666: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8668: +  dim - The spatial dimension
8669: .  x   - The coordinates
8670: .  Nf  - The number of fields
8671: .  u   - The output field values
8672: -  ctx - optional user-defined function context

8674:   Level: developer

8676: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8677: @*/
8678: 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)
8679: {

8685:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8686:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8687:   return(0);
8688: }

8690: /*@C
8691:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8693:   Not collective

8695:   Input Parameters:
8696: + dm      - The DM
8697: . time    - The time
8698: . localU  - The input field vector
8699: . funcs   - The functions to evaluate, one per field
8700: - mode    - The insertion mode for values

8702:   Output Parameter:
8703: . localX  - The output vector

8705:    Calling sequence of func:
8706: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8707: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8708: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8709: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8711: +  dim          - The spatial dimension
8712: .  Nf           - The number of input fields
8713: .  NfAux        - The number of input auxiliary fields
8714: .  uOff         - The offset of each field in u[]
8715: .  uOff_x       - The offset of each field in u_x[]
8716: .  u            - The field values at this point in space
8717: .  u_t          - The field time derivative at this point in space (or NULL)
8718: .  u_x          - The field derivatives at this point in space
8719: .  aOff         - The offset of each auxiliary field in u[]
8720: .  aOff_x       - The offset of each auxiliary field in u_x[]
8721: .  a            - The auxiliary field values at this point in space
8722: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8723: .  a_x          - The auxiliary field derivatives at this point in space
8724: .  t            - The current time
8725: .  x            - The coordinates of this point
8726: .  numConstants - The number of constants
8727: .  constants    - The value of each constant
8728: -  f            - The value of the function at this point in space

8730:   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.
8731:   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
8732:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8733:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8735:   Level: intermediate

8737: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8738: @*/
8739: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8740:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8741:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8742:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8743:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8744:                                    InsertMode mode, Vec localX)
8745: {

8752:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8753:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8754:   return(0);
8755: }

8757: /*@C
8758:   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.

8760:   Not collective

8762:   Input Parameters:
8763: + dm      - The DM
8764: . time    - The time
8765: . label   - The DMLabel marking the portion of the domain to output
8766: . numIds  - The number of label ids to use
8767: . ids     - The label ids to use for marking
8768: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8769: . comps   - The components to set in the output, or NULL for all components
8770: . localU  - The input field vector
8771: . funcs   - The functions to evaluate, one per field
8772: - mode    - The insertion mode for values

8774:   Output Parameter:
8775: . localX  - The output vector

8777:    Calling sequence of func:
8778: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8779: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8780: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8781: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8783: +  dim          - The spatial dimension
8784: .  Nf           - The number of input fields
8785: .  NfAux        - The number of input auxiliary fields
8786: .  uOff         - The offset of each field in u[]
8787: .  uOff_x       - The offset of each field in u_x[]
8788: .  u            - The field values at this point in space
8789: .  u_t          - The field time derivative at this point in space (or NULL)
8790: .  u_x          - The field derivatives at this point in space
8791: .  aOff         - The offset of each auxiliary field in u[]
8792: .  aOff_x       - The offset of each auxiliary field in u_x[]
8793: .  a            - The auxiliary field values at this point in space
8794: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8795: .  a_x          - The auxiliary field derivatives at this point in space
8796: .  t            - The current time
8797: .  x            - The coordinates of this point
8798: .  numConstants - The number of constants
8799: .  constants    - The value of each constant
8800: -  f            - The value of the function at this point in space

8802:   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.
8803:   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
8804:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8805:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8807:   Level: intermediate

8809: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8810: @*/
8811: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8812:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8813:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8814:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8815:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8816:                                         InsertMode mode, Vec localX)
8817: {

8824:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8825:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8826:   return(0);
8827: }

8829: /*@C
8830:   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.

8832:   Not collective

8834:   Input Parameters:
8835: + dm      - The DM
8836: . time    - The time
8837: . label   - The DMLabel marking the portion of the domain boundary to output
8838: . numIds  - The number of label ids to use
8839: . ids     - The label ids to use for marking
8840: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8841: . comps   - The components to set in the output, or NULL for all components
8842: . localU  - The input field vector
8843: . funcs   - The functions to evaluate, one per field
8844: - mode    - The insertion mode for values

8846:   Output Parameter:
8847: . localX  - The output vector

8849:    Calling sequence of func:
8850: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8851: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8852: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8853: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8855: +  dim          - The spatial dimension
8856: .  Nf           - The number of input fields
8857: .  NfAux        - The number of input auxiliary fields
8858: .  uOff         - The offset of each field in u[]
8859: .  uOff_x       - The offset of each field in u_x[]
8860: .  u            - The field values at this point in space
8861: .  u_t          - The field time derivative at this point in space (or NULL)
8862: .  u_x          - The field derivatives at this point in space
8863: .  aOff         - The offset of each auxiliary field in u[]
8864: .  aOff_x       - The offset of each auxiliary field in u_x[]
8865: .  a            - The auxiliary field values at this point in space
8866: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8867: .  a_x          - The auxiliary field derivatives at this point in space
8868: .  t            - The current time
8869: .  x            - The coordinates of this point
8870: .  n            - The face normal
8871: .  numConstants - The number of constants
8872: .  constants    - The value of each constant
8873: -  f            - The value of the function at this point in space

8875:   Note:
8876:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8877:   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
8878:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8879:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8881:   Level: intermediate

8883: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8884: @*/
8885: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8886:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8887:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8888:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8889:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8890:                                           InsertMode mode, Vec localX)
8891: {

8898:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8899:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8900:   return(0);
8901: }

8903: /*@C
8904:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8906:   Input Parameters:
8907: + dm    - The DM
8908: . time  - The time
8909: . funcs - The functions to evaluate for each field component
8910: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8911: - X     - The coefficient vector u_h, a global vector

8913:   Output Parameter:
8914: . diff - The diff ||u - u_h||_2

8916:   Level: developer

8918: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8919: @*/
8920: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8921: {

8927:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8928:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8929:   return(0);
8930: }

8932: /*@C
8933:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8935:   Collective on dm

8937:   Input Parameters:
8938: + dm    - The DM
8939: , time  - The time
8940: . funcs - The gradient functions to evaluate for each field component
8941: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8942: . X     - The coefficient vector u_h, a global vector
8943: - n     - The vector to project along

8945:   Output Parameter:
8946: . diff - The diff ||(grad u - grad u_h) . n||_2

8948:   Level: developer

8950: .seealso: DMProjectFunction(), DMComputeL2Diff()
8951: @*/
8952: 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)
8953: {

8959:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8960:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8961:   return(0);
8962: }

8964: /*@C
8965:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8967:   Collective on dm

8969:   Input Parameters:
8970: + dm    - The DM
8971: . time  - The time
8972: . funcs - The functions to evaluate for each field component
8973: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8974: - X     - The coefficient vector u_h, a global vector

8976:   Output Parameter:
8977: . diff - The array of differences, ||u^f - u^f_h||_2

8979:   Level: developer

8981: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8982: @*/
8983: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8984: {

8990:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8991:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8992:   return(0);
8993: }

8995: /*@C
8996:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8997:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

8999:   Collective on dm

9001:   Input parameters:
9002: + dm - the pre-adaptation DM object
9003: - label - label with the flags

9005:   Output parameters:
9006: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

9008:   Level: intermediate

9010: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9011: @*/
9012: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9013: {

9020:   *dmAdapt = NULL;
9021:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9022:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
9023:   if (*dmAdapt) {
9024:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
9025:     PetscFree((*dmAdapt)->vectype);
9026:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9027:     PetscFree((*dmAdapt)->mattype);
9028:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9029:   }
9030:   return(0);
9031: }

9033: /*@C
9034:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

9036:   Input Parameters:
9037: + dm - The DM object
9038: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9039: - 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_".

9041:   Output Parameter:
9042: . dmAdapt  - Pointer to the DM object containing the adapted mesh

9044:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

9046:   Level: advanced

9048: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9049: @*/
9050: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9051: {

9059:   *dmAdapt = NULL;
9060:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9061:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9062:   return(0);
9063: }

9065: /*@C
9066:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

9068:  Not Collective

9070:  Input Parameter:
9071: .  dm    - The DM

9073:  Output Parameters:
9074: +  nranks - the number of neighbours
9075: -  ranks - the neighbors ranks

9077:  Notes:
9078:  Do not free the array, it is freed when the DM is destroyed.

9080:  Level: beginner

9082:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9083: @*/
9084: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9085: {

9090:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9091:   (dm->ops->getneighbors)(dm,nranks,ranks);
9092:   return(0);
9093: }

9095: #include <petsc/private/matimpl.h>

9097: /*
9098:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9099:     This has be a different function because it requires DM which is not defined in the Mat library
9100: */
9101: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9102: {

9106:   if (coloring->ctype == IS_COLORING_LOCAL) {
9107:     Vec x1local;
9108:     DM  dm;
9109:     MatGetDM(J,&dm);
9110:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9111:     DMGetLocalVector(dm,&x1local);
9112:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9113:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9114:     x1   = x1local;
9115:   }
9116:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9117:   if (coloring->ctype == IS_COLORING_LOCAL) {
9118:     DM  dm;
9119:     MatGetDM(J,&dm);
9120:     DMRestoreLocalVector(dm,&x1);
9121:   }
9122:   return(0);
9123: }

9125: /*@
9126:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

9128:     Input Parameter:
9129: .    coloring - the MatFDColoring object

9131:     Developer Notes:
9132:     this routine exists because the PETSc Mat library does not know about the DM objects

9134:     Level: advanced

9136: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9137: @*/
9138: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9139: {
9141:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9142:   return(0);
9143: }

9145: /*@
9146:     DMGetCompatibility - determine if two DMs are compatible

9148:     Collective

9150:     Input Parameters:
9151: +    dm1 - the first DM
9152: -    dm2 - the second DM

9154:     Output Parameters:
9155: +    compatible - whether or not the two DMs are compatible
9156: -    set - whether or not the compatible value was set

9158:     Notes:
9159:     Two DMs are deemed compatible if they represent the same parallel decomposition
9160:     of the same topology. This implies that the section (field data) on one
9161:     "makes sense" with respect to the topology and parallel decomposition of the other.
9162:     Loosely speaking, compatible DMs represent the same domain and parallel
9163:     decomposition, but hold different data.

9165:     Typically, one would confirm compatibility if intending to simultaneously iterate
9166:     over a pair of vectors obtained from different DMs.

9168:     For example, two DMDA objects are compatible if they have the same local
9169:     and global sizes and the same stencil width. They can have different numbers
9170:     of degrees of freedom per node. Thus, one could use the node numbering from
9171:     either DM in bounds for a loop over vectors derived from either DM.

9173:     Consider the operation of summing data living on a 2-dof DMDA to data living
9174:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9175: .vb
9176:   ...
9177:   DMGetCompatibility(da1,da2,&compatible,&set);
9178:   if (set && compatible)  {
9179:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9180:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9181:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9182:     for (j=y; j<y+n; ++j) {
9183:       for (i=x; i<x+m, ++i) {
9184:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9185:       }
9186:     }
9187:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9188:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9189:   } else {
9190:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9191:   }
9192:   ...
9193: .ve

9195:     Checking compatibility might be expensive for a given implementation of DM,
9196:     or might be impossible to unambiguously confirm or deny. For this reason,
9197:     this function may decline to determine compatibility, and hence users should
9198:     always check the "set" output parameter.

9200:     A DM is always compatible with itself.

9202:     In the current implementation, DMs which live on "unequal" communicators
9203:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9204:     incompatible.

9206:     This function is labeled "Collective," as information about all subdomains
9207:     is required on each rank. However, in DM implementations which store all this
9208:     information locally, this function may be merely "Logically Collective".

9210:     Developer Notes:
9211:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9212:     iff B is compatible with A. Thus, this function checks the implementations
9213:     of both dm and dmc (if they are of different types), attempting to determine
9214:     compatibility. It is left to DM implementers to ensure that symmetry is
9215:     preserved. The simplest way to do this is, when implementing type-specific
9216:     logic for this function, is to check for existing logic in the implementation
9217:     of other DM types and let *set = PETSC_FALSE if found.

9219:     Level: advanced

9221: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9222: @*/

9224: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9225: {
9227:   PetscMPIInt    compareResult;
9228:   DMType         type,type2;
9229:   PetscBool      sameType;


9235:   /* Declare a DM compatible with itself */
9236:   if (dm1 == dm2) {
9237:     *set = PETSC_TRUE;
9238:     *compatible = PETSC_TRUE;
9239:     return(0);
9240:   }

9242:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9243:      communicator. Note that this does not preclude compatibility with
9244:      DMs living on "congruent" or "similar" communicators, but this must be
9245:      determined by the implementation-specific logic */
9246:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9247:   if (compareResult == MPI_UNEQUAL) {
9248:     *set = PETSC_TRUE;
9249:     *compatible = PETSC_FALSE;
9250:     return(0);
9251:   }

9253:   /* Pass to the implementation-specific routine, if one exists. */
9254:   if (dm1->ops->getcompatibility) {
9255:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9256:     if (*set) return(0);
9257:   }

9259:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9260:      with an implementation of this function from dm2 */
9261:   DMGetType(dm1,&type);
9262:   DMGetType(dm2,&type2);
9263:   PetscStrcmp(type,type2,&sameType);
9264:   if (!sameType && dm2->ops->getcompatibility) {
9265:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9266:   } else {
9267:     *set = PETSC_FALSE;
9268:   }
9269:   return(0);
9270: }

9272: /*@C
9273:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

9275:   Logically Collective on DM

9277:   Input Parameters:
9278: + DM - the DM
9279: . f - the monitor function
9280: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9281: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

9283:   Options Database Keys:
9284: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9285:                             does not cancel those set via the options database.

9287:   Notes:
9288:   Several different monitoring routines may be set by calling
9289:   DMMonitorSet() multiple times; all will be called in the
9290:   order in which they were set.

9292:   Fortran Notes:
9293:   Only a single monitor function can be set for each DM object

9295:   Level: intermediate

9297: .seealso: DMMonitorCancel()
9298: @*/
9299: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9300: {
9301:   PetscInt       m;

9306:   for (m = 0; m < dm->numbermonitors; ++m) {
9307:     PetscBool identical;

9309:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9310:     if (identical) return(0);
9311:   }
9312:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9313:   dm->monitor[dm->numbermonitors]          = f;
9314:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9315:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9316:   return(0);
9317: }

9319: /*@
9320:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9322:   Logically Collective on DM

9324:   Input Parameter:
9325: . dm - the DM

9327:   Options Database Key:
9328: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9329:   into a code by calls to DMonitorSet(), but does not cancel those
9330:   set via the options database

9332:   Notes:
9333:   There is no way to clear one specific monitor from a DM object.

9335:   Level: intermediate

9337: .seealso: DMMonitorSet()
9338: @*/
9339: PetscErrorCode DMMonitorCancel(DM dm)
9340: {
9342:   PetscInt       m;

9346:   for (m = 0; m < dm->numbermonitors; ++m) {
9347:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9348:   }
9349:   dm->numbermonitors = 0;
9350:   return(0);
9351: }

9353: /*@C
9354:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9356:   Collective on DM

9358:   Input Parameters:
9359: + dm   - DM object you wish to monitor
9360: . name - the monitor type one is seeking
9361: . help - message indicating what monitoring is done
9362: . manual - manual page for the monitor
9363: . monitor - the monitor function
9364: - 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

9366:   Output Parameter:
9367: . flg - Flag set if the monitor was created

9369:   Level: developer

9371: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9372:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9373:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9374:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9375:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9376:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9377:           PetscOptionsFList(), PetscOptionsEList()
9378: @*/
9379: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9380: {
9381:   PetscViewer       viewer;
9382:   PetscViewerFormat format;
9383:   PetscErrorCode    ierr;

9387:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9388:   if (*flg) {
9389:     PetscViewerAndFormat *vf;

9391:     PetscViewerAndFormatCreate(viewer, format, &vf);
9392:     PetscObjectDereference((PetscObject) viewer);
9393:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9394:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9395:   }
9396:   return(0);
9397: }

9399: /*@
9400:    DMMonitor - runs the user provided monitor routines, if they exist

9402:    Collective on DM

9404:    Input Parameters:
9405: .  dm - The DM

9407:    Level: developer

9409: .seealso: DMMonitorSet()
9410: @*/
9411: PetscErrorCode DMMonitor(DM dm)
9412: {
9413:   PetscInt       m;

9417:   if (!dm) return(0);
9419:   for (m = 0; m < dm->numbermonitors; ++m) {
9420:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9421:   }
9422:   return(0);
9423: }

9425: /*@
9426:   DMComputeError - Computes the error assuming the user has given exact solution functions

9428:   Collective on DM

9430:   Input Parameters:
9431: + dm     - The DM
9432: . sol    - The solution vector
9433: . errors - An array of length Nf, the number of fields, or NULL for no output
9434: - errorVec - A Vec pointer, or NULL for no output

9436:   Output Parameters:
9437: + errors   - The error in each field
9438: - errorVec - Creates a vector to hold the cellwise error

9440:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

9442:   Level: developer

9444: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9445: @*/
9446: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9447: {
9448:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9449:   void            **ctxs;
9450:   PetscReal         time;
9451:   PetscInt          Nf, f, Nds, s;
9452:   PetscErrorCode    ierr;

9455:   DMGetNumFields(dm, &Nf);
9456:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9457:   DMGetNumDS(dm, &Nds);
9458:   for (s = 0; s < Nds; ++s) {
9459:     PetscDS         ds;
9460:     DMLabel         label;
9461:     IS              fieldIS;
9462:     const PetscInt *fields;
9463:     PetscInt        dsNf;

9465:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9466:     PetscDSGetNumFields(ds, &dsNf);
9467:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9468:     for (f = 0; f < dsNf; ++f) {
9469:       const PetscInt field = fields[f];
9470:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9471:     }
9472:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9473:   }
9474:   for (f = 0; f < Nf; ++f) {
9475:     if (!exactSol[f]) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %D", f);
9476:   }
9477:   DMGetOutputSequenceNumber(dm, NULL, &time);
9478:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9479:   if (errorVec) {
9480:     DM             edm;
9481:     DMPolytopeType ct;
9482:     PetscBool      simplex;
9483:     PetscInt       dim, cStart, Nf;

9485:     DMClone(dm, &edm);
9486:     DMGetDimension(edm, &dim);
9487:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9488:     DMPlexGetCellType(dm, cStart, &ct);
9489:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9490:     DMGetNumFields(dm, &Nf);
9491:     for (f = 0; f < Nf; ++f) {
9492:       PetscFE         fe, efe;
9493:       PetscQuadrature q;
9494:       const char     *name;

9496:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
9497:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9498:       PetscObjectGetName((PetscObject) fe, &name);
9499:       PetscObjectSetName((PetscObject) efe, name);
9500:       PetscFEGetQuadrature(fe, &q);
9501:       PetscFESetQuadrature(efe, q);
9502:       DMSetField(edm, f, NULL, (PetscObject) efe);
9503:       PetscFEDestroy(&efe);
9504:     }
9505:     DMCreateDS(edm);

9507:     DMCreateGlobalVector(edm, errorVec);
9508:     PetscObjectSetName((PetscObject) *errorVec, "Error");
9509:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9510:     DMDestroy(&edm);
9511:   }
9512:   PetscFree2(exactSol, ctxs);
9513:   return(0);
9514: }

9516: /*@
9517:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

9519:   Not collective

9521:   Input Parameter:
9522: . dm     - The DM

9524:   Output Parameter:
9525: . numAux - The nubmer of auxiliary data vectors

9527:   Level: advanced

9529: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9530: @*/
9531: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9532: {

9537:   PetscHMapAuxGetSize(dm->auxData, numAux);
9538:   return(0);
9539: }

9541: /*@
9542:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value

9544:   Not collective

9546:   Input Parameters:
9547: + dm     - The DM
9548: . label  - The DMLabel
9549: - value  - The label value indicating the region

9551:   Output Parameter:
9552: . aux    - The Vec holding auxiliary field data

9554:   Level: advanced

9556: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9557: @*/
9558: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec *aux)
9559: {
9560:   PetscHashAuxKey key;
9561:   PetscErrorCode  ierr;

9566:   key.label = label;
9567:   key.value = value;
9568:   PetscHMapAuxGet(dm->auxData, key, aux);
9569:   return(0);
9570: }

9572: /*@
9573:   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value

9575:   Not collective

9577:   Input Parameters:
9578: + dm     - The DM
9579: . label  - The DMLabel
9580: . value  - The label value indicating the region
9581: - aux    - The Vec holding auxiliary field data

9583:   Level: advanced

9585: .seealso: DMGetAuxiliaryVec()
9586: @*/
9587: PetscErrorCode DMSetAuxiliaryVec(DM dm,