Actual source code: dm.c

  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: #ifdef PETSC_HAVE_LIBCEED
 11: #include <petscfeceed.h>
 12: #endif

 14: #if defined(PETSC_HAVE_VALGRIND)
 15: #  include <valgrind/memcheck.h>
 16: #endif

 18: PetscClassId  DM_CLASSID;
 19: PetscClassId  DMLABEL_CLASSID;
 20: 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;

 22: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
 23: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","ESSENTIAL_BD_FIELD","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
 24: 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};

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

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

 32:   Collective

 34:   Input Parameter:
 35: . comm - The communicator for the DM object

 37:   Output Parameter:
 38: . dm - The DM object

 40:   Level: beginner

 42: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
 43: @*/
 44: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
 45: {
 46:   DM             v;
 47:   PetscDS        ds;

 52:   *dm = NULL;
 53:   DMInitializePackage();

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

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

 96:   *dm = v;
 97:   return(0);
 98: }

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

103:   Collective

105:   Input Parameter:
106: . dm - The original DM object

108:   Output Parameter:
109: . newdm  - The new DM object

111:   Level: beginner

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

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

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

122: @*/
123: PetscErrorCode DMClone(DM dm, DM *newdm)
124: {
125:   PetscSF        sf;
126:   Vec            coords;
127:   void          *ctx;
128:   PetscInt       dim, cdim;

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

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

188:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
189:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
190:   }
191:   return(0);
192: }

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

197:    Logically Collective on da

199:    Input Parameter:
200: +  da - initial distributed array
201: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

203:    Options Database:
204: .   -dm_vec_type ctype

206:    Level: intermediate

208: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
209: @*/
210: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
211: {

216:   PetscFree(da->vectype);
217:   PetscStrallocpy(ctype,(char**)&da->vectype);
218:   return(0);
219: }

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

224:    Logically Collective on da

226:    Input Parameter:
227: .  da - initial distributed array

229:    Output Parameter:
230: .  ctype - the vector type

232:    Level: intermediate

234: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
235: @*/
236: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
237: {
240:   *ctype = da->vectype;
241:   return(0);
242: }

244: /*@
245:   VecGetDM - Gets the DM defining the data layout of the vector

247:   Not collective

249:   Input Parameter:
250: . v - The Vec

252:   Output Parameter:
253: . dm - The DM

255:   Level: intermediate

257: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
258: @*/
259: PetscErrorCode VecGetDM(Vec v, DM *dm)
260: {

266:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
267:   return(0);
268: }

270: /*@
271:   VecSetDM - Sets the DM defining the data layout of the vector.

273:   Not collective

275:   Input Parameters:
276: + v - The Vec
277: - dm - The DM

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

281:   Level: intermediate

283: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
284: @*/
285: PetscErrorCode VecSetDM(Vec v, DM dm)
286: {

292:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
293:   return(0);
294: }

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

299:    Logically Collective on dm

301:    Input Parameters:
302: +  dm - the DM context
303: -  ctype - the matrix type

305:    Options Database:
306: .   -dm_is_coloring_type - global or local

308:    Level: intermediate

310: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
311:           DMGetISColoringType()
312: @*/
313: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
314: {
317:   dm->coloringtype = ctype;
318:   return(0);
319: }

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

324:    Logically Collective on dm

326:    Input Parameter:
327: .  dm - the DM context

329:    Output Parameter:
330: .  ctype - the matrix type

332:    Options Database:
333: .   -dm_is_coloring_type - global or local

335:    Level: intermediate

337: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
338:           DMGetISColoringType()
339: @*/
340: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
341: {
344:   *ctype = dm->coloringtype;
345:   return(0);
346: }

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

351:    Logically Collective on dm

353:    Input Parameters:
354: +  dm - the DM context
355: -  ctype - the matrix type

357:    Options Database:
358: .   -dm_mat_type ctype

360:    Level: intermediate

362: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
363: @*/
364: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
365: {

370:   PetscFree(dm->mattype);
371:   PetscStrallocpy(ctype,(char**)&dm->mattype);
372:   return(0);
373: }

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

378:    Logically Collective on dm

380:    Input Parameter:
381: .  dm - the DM context

383:    Output Parameter:
384: .  ctype - the matrix type

386:    Options Database:
387: .   -dm_mat_type ctype

389:    Level: intermediate

391: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
392: @*/
393: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
394: {
397:   *ctype = dm->mattype;
398:   return(0);
399: }

401: /*@
402:   MatGetDM - Gets the DM defining the data layout of the matrix

404:   Not collective

406:   Input Parameter:
407: . A - The Mat

409:   Output Parameter:
410: . dm - The DM

412:   Level: intermediate

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

417: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
418: @*/
419: PetscErrorCode MatGetDM(Mat A, DM *dm)
420: {

426:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
427:   return(0);
428: }

430: /*@
431:   MatSetDM - Sets the DM defining the data layout of the matrix

433:   Not collective

435:   Input Parameters:
436: + A - The Mat
437: - dm - The DM

439:   Level: intermediate

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

444: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
445: @*/
446: PetscErrorCode MatSetDM(Mat A, DM dm)
447: {

453:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
454:   return(0);
455: }

457: /*@C
458:    DMSetOptionsPrefix - Sets the prefix used for searching for all
459:    DM options in the database.

461:    Logically Collective on dm

463:    Input Parameters:
464: +  da - the DM context
465: -  prefix - the prefix to prepend to all option names

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

471:    Level: advanced

473: .seealso: DMSetFromOptions()
474: @*/
475: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
476: {

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

491: /*@C
492:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
493:    DM options in the database.

495:    Logically Collective on dm

497:    Input Parameters:
498: +  dm - the DM context
499: -  prefix - the prefix string to prepend to all DM option requests

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

505:    Level: advanced

507: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
508: @*/
509: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
510: {

515:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
516:   return(0);
517: }

519: /*@C
520:    DMGetOptionsPrefix - Gets the prefix used for searching for all
521:    DM options in the database.

523:    Not Collective

525:    Input Parameters:
526: .  dm - the DM context

528:    Output Parameters:
529: .  prefix - pointer to the prefix string used is returned

531:    Notes:
532:     On the fortran side, the user should pass in a string 'prefix' of
533:    sufficient length to hold the prefix.

535:    Level: advanced

537: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
538: @*/
539: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
540: {

545:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
546:   return(0);
547: }

549: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
550: {
551:   PetscInt       refct = ((PetscObject) dm)->refct;

555:   *ncrefct = 0;
556:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
557:     refct--;
558:     if (recurseCoarse) {
559:       PetscInt coarseCount;

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

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

578: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
579: {
580:   DMLabelLink    next = dm->labels;

584:   /* destroy the labels */
585:   while (next) {
586:     DMLabelLink tmp = next->next;

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

598: /*@C
599:     DMDestroy - Destroys a vector packer or DM.

601:     Collective on dm

603:     Input Parameter:
604: .   dm - the DM object to destroy

606:     Level: developer

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

610: @*/
611: PetscErrorCode  DMDestroy(DM *dm)
612: {
613:   PetscInt       cnt;
614:   DMNamedVecLink nlink,nnext;

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

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

628:   DMClearGlobalVectors(*dm);
629:   DMClearLocalVectors(*dm);

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

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

712:       next = b->next;
713:       PetscFree(b);
714:     }
715:   }

717:   PetscObjectDestroy(&(*dm)->dmksp);
718:   PetscObjectDestroy(&(*dm)->dmsnes);
719:   PetscObjectDestroy(&(*dm)->dmts);

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

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

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

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

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

778:   if ((*dm)->ops->destroy) {
779:     (*(*dm)->ops->destroy)(*dm);
780:   }
781:   DMMonitorCancel(*dm);
782: #ifdef PETSC_HAVE_LIBCEED
783:   CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
784:   CeedDestroy(&(*dm)->ceed);
785: #endif
786:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
787:   PetscHeaderDestroy(dm);
788:   return(0);
789: }

791: /*@
792:     DMSetUp - sets up the data structures inside a DM object

794:     Collective on dm

796:     Input Parameter:
797: .   dm - the DM object to setup

799:     Level: developer

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

803: @*/
804: PetscErrorCode  DMSetUp(DM dm)
805: {

810:   if (dm->setupcalled) return(0);
811:   if (dm->ops->setup) {
812:     (*dm->ops->setup)(dm);
813:   }
814:   dm->setupcalled = PETSC_TRUE;
815:   return(0);
816: }

818: /*@
819:     DMSetFromOptions - sets parameters in a DM from the options database

821:     Collective on dm

823:     Input Parameter:
824: .   dm - the DM object to set options for

826:     Options Database:
827: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
828: .   -dm_vec_type <type>  - type of vector to create inside DM
829: .   -dm_mat_type <type>  - type of matrix to create inside DM
830: -   -dm_is_coloring_type - <global or local>

832:     DMPLEX Specific creation options
833: + -dm_plex_filename <str>           - File containing a mesh
834: . -dm_plex_boundary_filename <str>  - File containing a mesh boundary
835: . -dm_plex_shape <shape>            - The domain shape, such as DM_SHAPE_BOX, DM_SHAPE_SPHERE, etc.
836: . -dm_plex_cell <ct>                - Cell shape
837: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
838: . -dm_plex_dim <dim>                - Set the topological dimension
839: . -dm_plex_simplex <bool>           - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
840: . -dm_plex_interpolate <bool>       - PETSC_TRUE turns on topological interpolation (creating edges and faces)
841: . -dm_plex_scale <sc>               - Scale factor for mesh coordinates
842: . -dm_plex_box_faces <m,n,p>        - Number of faces along each dimension
843: . -dm_plex_box_lower <x,y,z>        - Specify lower-left-bottom coordinates for the box
844: . -dm_plex_box_upper <x,y,z>        - Specify upper-right-top coordinates for the box
845: . -dm_plex_box_bd <bx,by,bz>        - Specify the DMBoundaryType for each direction
846: . -dm_plex_sphere_radius <r>        - The sphere radius
847: . -dm_plex_ball_radius <r>          - Radius of the ball
848: . -dm_plex_cylinder_bd <bz>         - Boundary type in the z direction
849: . -dm_plex_cylinder_num_wedges <n>  - Number of wedges around the cylinder
850: . -dm_refine_pre <n>                - The number of refinements before distribution
851: . -dm_refine_uniform_pre <bool>     - Flag for uniform refinement before distribution
852: . -dm_refine_volume_limit_pre <v>   - The maximum cell volume after refinement before distribution
853: . -dm_refine <n>                    - The number of refinements after distribution
854: . -dm_extrude_layers <l>            - The number of layers to extrude
855: . -dm_extrude_thickness <t>         - The thickness of the layer to be extruded
856: . -dm_extrude_column_first <bool>   - Order the cells in a vertical column first
857: . -dm_plex_create_fv_ghost_cells    - Flag to create finite volume ghost cells on the boundary
858: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
859: . -dm_distribute <bool>             - Flag to redistribute a mesh among processes
860: . -dm_distribute_overlap <n>        - The size of the overlap halo
861: . -dm_plex_adj_cone <bool>          - Set adjacency direction
862: - -dm_plex_adj_closure <bool>       - Set adjacency size

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

873:     Level: intermediate

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

878: @*/
879: PetscErrorCode DMSetFromOptions(DM dm)
880: {
881:   char           typeName[256];
882:   PetscBool      flg;

887:   dm->setfromoptionscalled = PETSC_TRUE;
888:   if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
889:   if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
890:   PetscObjectOptionsBegin((PetscObject)dm);
891:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
892:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
893:   if (flg) {
894:     DMSetVecType(dm,typeName);
895:   }
896:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
897:   if (flg) {
898:     DMSetMatType(dm,typeName);
899:   }
900:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
901:   if (dm->ops->setfromoptions) {
902:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
903:   }
904:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
905:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
906:   PetscOptionsEnd();
907:   return(0);
908: }

910: /*@C
911:    DMViewFromOptions - View from Options

913:    Collective on DM

915:    Input Parameters:
916: +  dm - the DM object
917: .  obj - Optional object
918: -  name - command line option

920:    Level: intermediate
921: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
922: @*/
923: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
924: {

929:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
930:   return(0);
931: }

933: /*@C
934:     DMView - Views a DM

936:     Collective on dm

938:     Input Parameters:
939: +   dm - the DM object to view
940: -   v - the viewer

942:     Level: beginner

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

946: @*/
947: PetscErrorCode  DMView(DM dm,PetscViewer v)
948: {
949:   PetscErrorCode    ierr;
950:   PetscBool         isbinary;
951:   PetscMPIInt       size;
952:   PetscViewerFormat format;

956:   if (!v) {
957:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
958:   }
960:   /* Ideally, we would like to have this test on.
961:      However, it currently breaks socket viz via GLVis.
962:      During DMView(parallel_mesh,glvis_viewer), each
963:      process opens a sequential ASCII socket to visualize
964:      the local mesh, and PetscObjectView(dm,local_socket)
965:      is internally called inside VecView_GLVis, incurring
966:      in an error here */
968:   PetscViewerCheckWritable(v);

970:   PetscViewerGetFormat(v,&format);
971:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
972:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
973:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
974:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
975:   if (isbinary) {
976:     PetscInt classid = DM_FILE_CLASSID;
977:     char     type[256];

979:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
980:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
981:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
982:   }
983:   if (dm->ops->view) {
984:     (*dm->ops->view)(dm,v);
985:   }
986:   return(0);
987: }

989: /*@
990:     DMCreateGlobalVector - Creates a global vector from a DM object

992:     Collective on dm

994:     Input Parameter:
995: .   dm - the DM object

997:     Output Parameter:
998: .   vec - the global vector

1000:     Level: beginner

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

1004: @*/
1005: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
1006: {

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

1017:     VecGetDM(*vec,&vdm);
1018:     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);
1019:   }
1020:   return(0);
1021: }

1023: /*@
1024:     DMCreateLocalVector - Creates a local vector from a DM object

1026:     Not Collective

1028:     Input Parameter:
1029: .   dm - the DM object

1031:     Output Parameter:
1032: .   vec - the local vector

1034:     Level: beginner

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

1038: @*/
1039: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
1040: {

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

1051:     VecGetDM(*vec,&vdm);
1052:     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);
1053:   }
1054:   return(0);
1055: }

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

1060:    Collective on dm

1062:    Input Parameter:
1063: .  dm - the DM that provides the mapping

1065:    Output Parameter:
1066: .  ltog - the mapping

1068:    Level: intermediate

1070:    Notes:
1071:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1072:    MatSetLocalToGlobalMapping().

1074: .seealso: DMCreateLocalVector()
1075: @*/
1076: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1077: {
1078:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1084:   if (!dm->ltogmap) {
1085:     PetscSection section, sectionGlobal;

1087:     DMGetLocalSection(dm, &section);
1088:     if (section) {
1089:       const PetscInt *cdofs;
1090:       PetscInt       *ltog;
1091:       PetscInt        pStart, pEnd, n, p, k, l;

1093:       DMGetGlobalSection(dm, &sectionGlobal);
1094:       PetscSectionGetChart(section, &pStart, &pEnd);
1095:       PetscSectionGetStorageSize(section, &n);
1096:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1097:       for (p = pStart, l = 0; p < pEnd; ++p) {
1098:         PetscInt bdof, cdof, dof, off, c, cind = 0;

1100:         /* Should probably use constrained dofs */
1101:         PetscSectionGetDof(section, p, &dof);
1102:         PetscSectionGetConstraintDof(section, p, &cdof);
1103:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1104:         PetscSectionGetOffset(sectionGlobal, p, &off);
1105:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1106:         bdof = cdof && (dof-cdof) ? 1 : dof;
1107:         if (dof) {
1108:           if (bs < 0)          {bs = bdof;}
1109:           else if (bs != bdof) {bs = 1;}
1110:         }
1111:         for (c = 0; c < dof; ++c, ++l) {
1112:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1113:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
1114:         }
1115:       }
1116:       /* Must have same blocksize on all procs (some might have no points) */
1117:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1118:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1119:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1120:       else                            {bs = bsMinMax[0];}
1121:       bs = bs < 0 ? 1 : bs;
1122:       /* Must reduce indices by blocksize */
1123:       if (bs > 1) {
1124:         for (l = 0, k = 0; l < n; l += bs, ++k) {
1125:           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1126:           ltog[k] = ltog[l] >= 0 ? ltog[l]/bs : -(-(ltog[l]+1)/bs + 1);
1127:         }
1128:         n /= bs;
1129:       }
1130:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1131:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1132:     } else {
1133:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1134:       (*dm->ops->getlocaltoglobalmapping)(dm);
1135:     }
1136:   }
1137:   *ltog = dm->ltogmap;
1138:   return(0);
1139: }

1141: /*@
1142:    DMGetBlockSize - Gets the inherent block size associated with a DM

1144:    Not Collective

1146:    Input Parameter:
1147: .  dm - the DM with block structure

1149:    Output Parameter:
1150: .  bs - the block size, 1 implies no exploitable block structure

1152:    Level: intermediate

1154: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1155: @*/
1156: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1157: {
1161:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1162:   *bs = dm->bs;
1163:   return(0);
1164: }

1166: /*@C
1167:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1169:     Collective on dmc

1171:     Input Parameters:
1172: +   dmc - the DM object
1173: -   dmf - the second, finer DM object

1175:     Output Parameters:
1176: +  mat - the interpolation
1177: -  vec - the scaling (optional)

1179:     Level: developer

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

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

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

1190: @*/
1191: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1192: {

1199:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1200:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1201:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1202:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1203:   return(0);
1204: }

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

1209:   Input Parameters:
1210: +      dac - DM that defines a coarse mesh
1211: .      daf - DM that defines a fine mesh
1212: -      mat - the restriction (or interpolation operator) from fine to coarse

1214:   Output Parameter:
1215: .    scale - the scaled vector

1217:   Level: developer

1219: .seealso: DMCreateInterpolation()

1221: @*/
1222: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1223: {
1225:   Vec            fine;
1226:   PetscScalar    one = 1.0;

1229:   DMCreateGlobalVector(daf,&fine);
1230:   DMCreateGlobalVector(dac,scale);
1231:   VecSet(fine,one);
1232:   MatRestrict(mat,fine,*scale);
1233:   VecDestroy(&fine);
1234:   VecReciprocal(*scale);
1235:   return(0);
1236: }

1238: /*@
1239:     DMCreateRestriction - Gets restriction matrix between two DM objects

1241:     Collective on dmc

1243:     Input Parameters:
1244: +   dmc - the DM object
1245: -   dmf - the second, finer DM object

1247:     Output Parameter:
1248: .  mat - the restriction

1250:     Level: developer

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

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

1258: @*/
1259: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1260: {

1267:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1268:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1269:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1270:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1271:   return(0);
1272: }

1274: /*@
1275:     DMCreateInjection - Gets injection matrix between two DM objects

1277:     Collective on dac

1279:     Input Parameters:
1280: +   dac - the DM object
1281: -   daf - the second, finer DM object

1283:     Output Parameter:
1284: .   mat - the injection

1286:     Level: developer

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

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

1294: @*/
1295: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1296: {

1303:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1304:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1305:   (*dac->ops->createinjection)(dac,daf,mat);
1306:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1307:   return(0);
1308: }

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

1313:   Collective on dac

1315:   Input Parameters:
1316: + dac - the DM object
1317: - daf - the second, finer DM object

1319:   Output Parameter:
1320: . mat - the interpolation

1322:   Level: developer

1324: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1325: @*/
1326: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1327: {

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

1339: /*@
1340:     DMCreateColoring - Gets coloring for a DM

1342:     Collective on dm

1344:     Input Parameters:
1345: +   dm - the DM object
1346: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1348:     Output Parameter:
1349: .   coloring - the coloring

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

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

1357:     Level: developer

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

1361: @*/
1362: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1363: {

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

1374: /*@
1375:     DMCreateMatrix - Gets empty Jacobian for a DM

1377:     Collective on dm

1379:     Input Parameter:
1380: .   dm - the DM object

1382:     Output Parameter:
1383: .   mat - the empty Jacobian

1385:     Level: beginner

1387:     Options Database Keys:
1388: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros

1390:     Notes:
1391:     This properly preallocates the number of nonzeros in the sparse matrix so you
1392:        do not need to do it yourself.

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

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

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

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

1405: @*/
1406: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1407: {

1413:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1414:   MatInitializePackage();
1415:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1416:   (*dm->ops->creatematrix)(dm,mat);
1417:   if (PetscDefined(USE_DEBUG)) {
1418:     DM mdm;

1420:     MatGetDM(*mat,&mdm);
1421:     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);
1422:   }
1423:   /* Handle nullspace and near nullspace */
1424:   if (dm->Nf) {
1425:     MatNullSpace nullSpace;
1426:     PetscInt     Nf, f;

1428:     DMGetNumFields(dm, &Nf);
1429:     for (f = 0; f < Nf; ++f) {
1430:       if (dm->nullspaceConstructors[f]) {
1431:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1432:         MatSetNullSpace(*mat, nullSpace);
1433:         MatNullSpaceDestroy(&nullSpace);
1434:         break;
1435:       }
1436:     }
1437:     for (f = 0; f < Nf; ++f) {
1438:       if (dm->nearnullspaceConstructors[f]) {
1439:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1440:         MatSetNearNullSpace(*mat, nullSpace);
1441:         MatNullSpaceDestroy(&nullSpace);
1442:       }
1443:     }
1444:   }
1445:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1446:   return(0);
1447: }

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

1453:   Logically Collective on dm

1455:   Input Parameters:
1456: + dm - the DM
1457: - only - PETSC_TRUE if only want preallocation

1459:   Level: developer

1461:   Options Database Keys:
1462: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros

1464: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1465: @*/
1466: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1467: {
1470:   dm->prealloc_only = only;
1471:   return(0);
1472: }

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

1478:   Logically Collective on dm

1480:   Input Parameters:
1481: + dm - the DM
1482: - only - PETSC_TRUE if only want matrix stucture

1484:   Level: developer
1485: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1486: @*/
1487: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1488: {
1491:   dm->structure_only = only;
1492:   return(0);
1493: }

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

1498:   Not Collective

1500:   Input Parameters:
1501: + dm - the DM object
1502: . count - The minimum size
1503: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1505:   Output Parameter:
1506: . array - the work array

1508:   Level: developer

1510: .seealso DMDestroy(), DMCreate()
1511: @*/
1512: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1513: {
1515:   DMWorkLink     link;
1516:   PetscMPIInt    dsize;

1521:   if (dm->workin) {
1522:     link       = dm->workin;
1523:     dm->workin = dm->workin->next;
1524:   } else {
1525:     PetscNewLog(dm,&link);
1526:   }
1527:   MPI_Type_size(dtype,&dsize);
1528:   if (((size_t)dsize*count) > link->bytes) {
1529:     PetscFree(link->mem);
1530:     PetscMalloc(dsize*count,&link->mem);
1531:     link->bytes = dsize*count;
1532:   }
1533:   link->next   = dm->workout;
1534:   dm->workout  = link;
1535: #if defined(PETSC_HAVE_VALGRIND)
1536:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1537:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1538: #endif
1539:   *(void**)mem = link->mem;
1540:   return(0);
1541: }

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

1546:   Not Collective

1548:   Input Parameters:
1549: + dm - the DM object
1550: . count - The minimum size
1551: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1553:   Output Parameter:
1554: . array - the work array

1556:   Level: developer

1558:   Developer Notes:
1559:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1560: .seealso DMDestroy(), DMCreate()
1561: @*/
1562: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1563: {
1564:   DMWorkLink *p,link;

1569:   for (p=&dm->workout; (link=*p); p=&link->next) {
1570:     if (link->mem == *(void**)mem) {
1571:       *p           = link->next;
1572:       link->next   = dm->workin;
1573:       dm->workin   = link;
1574:       *(void**)mem = NULL;
1575:       return(0);
1576:     }
1577:   }
1578:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1579: }

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

1584:   Logically collective on DM

1586:   Input Parameters:
1587: + dm     - The DM
1588: . field  - The field number for the nullspace
1589: - nullsp - A callback to create the nullspace

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

1599:   This function is currently not available from Fortran.

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

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

1615:   Not collective

1617:   Input Parameters:
1618: + dm     - The DM
1619: - field  - The field number for the nullspace

1621:   Output Parameter:
1622: . nullsp - A callback to create the nullspace

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

1632:   This function is currently not available from Fortran.

1634: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1635: */
1636: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1637: {
1641:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1642:   *nullsp = dm->nullspaceConstructors[field];
1643:   return(0);
1644: }

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

1649:   Logically collective on DM

1651:   Input Parameters:
1652: + dm     - The DM
1653: . field  - The field number for the nullspace
1654: - nullsp - A callback to create the near-nullspace

1656:   Notes:
1657:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1658: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1659: $ dm        - The present DM
1660: $ origField - The field number given above, in the original DM
1661: $ field     - The field number in dm
1662: $ nullSpace - The nullspace for the given field

1664:   This function is currently not available from Fortran.

1666: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1667: */
1668: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1669: {
1672:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1673:   dm->nearnullspaceConstructors[field] = nullsp;
1674:   return(0);
1675: }

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

1680:   Not collective

1682:   Input Parameters:
1683: + dm     - The DM
1684: - field  - The field number for the nullspace

1686:   Output Parameter:
1687: . nullsp - A callback to create the near-nullspace

1689:   Notes:
1690:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1691: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1692: $ dm        - The present DM
1693: $ origField - The field number given above, in the original DM
1694: $ field     - The field number in dm
1695: $ nullSpace - The nullspace for the given field

1697:   This function is currently not available from Fortran.

1699: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1700: */
1701: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1702: {
1706:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1707:   *nullsp = dm->nearnullspaceConstructors[field];
1708:   return(0);
1709: }

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

1714:   Not collective

1716:   Input Parameter:
1717: . dm - the DM object

1719:   Output Parameters:
1720: + numFields  - The number of fields (or NULL if not requested)
1721: . fieldNames - The name for each field (or NULL if not requested)
1722: - fields     - The global indices for each field (or NULL if not requested)

1724:   Level: intermediate

1726:   Notes:
1727:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1728:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1729:   PetscFree().

1731: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1732: @*/
1733: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1734: {
1735:   PetscSection   section, sectionGlobal;

1740:   if (numFields) {
1742:     *numFields = 0;
1743:   }
1744:   if (fieldNames) {
1746:     *fieldNames = NULL;
1747:   }
1748:   if (fields) {
1750:     *fields = NULL;
1751:   }
1752:   DMGetLocalSection(dm, &section);
1753:   if (section) {
1754:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1755:     PetscInt nF, f, pStart, pEnd, p;

1757:     DMGetGlobalSection(dm, &sectionGlobal);
1758:     PetscSectionGetNumFields(section, &nF);
1759:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1760:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1761:     for (f = 0; f < nF; ++f) {
1762:       fieldSizes[f] = 0;
1763:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1764:     }
1765:     for (p = pStart; p < pEnd; ++p) {
1766:       PetscInt gdof;

1768:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1769:       if (gdof > 0) {
1770:         for (f = 0; f < nF; ++f) {
1771:           PetscInt fdof, fcdof, fpdof;

1773:           PetscSectionGetFieldDof(section, p, f, &fdof);
1774:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1775:           fpdof = fdof-fcdof;
1776:           if (fpdof && fpdof != fieldNc[f]) {
1777:             /* Layout does not admit a pointwise block size */
1778:             fieldNc[f] = 1;
1779:           }
1780:           fieldSizes[f] += fpdof;
1781:         }
1782:       }
1783:     }
1784:     for (f = 0; f < nF; ++f) {
1785:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1786:       fieldSizes[f] = 0;
1787:     }
1788:     for (p = pStart; p < pEnd; ++p) {
1789:       PetscInt gdof, goff;

1791:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1792:       if (gdof > 0) {
1793:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1794:         for (f = 0; f < nF; ++f) {
1795:           PetscInt fdof, fcdof, fc;

1797:           PetscSectionGetFieldDof(section, p, f, &fdof);
1798:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1799:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1800:             fieldIndices[f][fieldSizes[f]] = goff++;
1801:           }
1802:         }
1803:       }
1804:     }
1805:     if (numFields) *numFields = nF;
1806:     if (fieldNames) {
1807:       PetscMalloc1(nF, fieldNames);
1808:       for (f = 0; f < nF; ++f) {
1809:         const char *fieldName;

1811:         PetscSectionGetFieldName(section, f, &fieldName);
1812:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1813:       }
1814:     }
1815:     if (fields) {
1816:       PetscMalloc1(nF, fields);
1817:       for (f = 0; f < nF; ++f) {
1818:         PetscInt bs, in[2], out[2];

1820:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1821:         in[0] = -fieldNc[f];
1822:         in[1] = fieldNc[f];
1823:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1824:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1825:         ISSetBlockSize((*fields)[f], bs);
1826:       }
1827:     }
1828:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1829:   } else if (dm->ops->createfieldis) {
1830:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1831:   }
1832:   return(0);
1833: }

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

1841:   Not collective

1843:   Input Parameter:
1844: . dm - the DM object

1846:   Output Parameters:
1847: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1848: . namelist  - The name for each field (or NULL if not requested)
1849: . islist    - The global indices for each field (or NULL if not requested)
1850: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1852:   Level: intermediate

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

1859: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1860: @*/
1861: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1862: {

1867:   if (len) {
1869:     *len = 0;
1870:   }
1871:   if (namelist) {
1873:     *namelist = NULL;
1874:   }
1875:   if (islist) {
1877:     *islist = NULL;
1878:   }
1879:   if (dmlist) {
1881:     *dmlist = NULL;
1882:   }
1883:   /*
1884:    Is it a good idea to apply the following check across all impls?
1885:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1886:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1887:    */
1888:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1889:   if (!dm->ops->createfielddecomposition) {
1890:     PetscSection section;
1891:     PetscInt     numFields, f;

1893:     DMGetLocalSection(dm, &section);
1894:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1895:     if (section && numFields && dm->ops->createsubdm) {
1896:       if (len) *len = numFields;
1897:       if (namelist) {PetscMalloc1(numFields,namelist);}
1898:       if (islist)   {PetscMalloc1(numFields,islist);}
1899:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1900:       for (f = 0; f < numFields; ++f) {
1901:         const char *fieldName;

1903:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1904:         if (namelist) {
1905:           PetscSectionGetFieldName(section, f, &fieldName);
1906:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1907:         }
1908:       }
1909:     } else {
1910:       DMCreateFieldIS(dm, len, namelist, islist);
1911:       /* By default there are no DMs associated with subproblems. */
1912:       if (dmlist) *dmlist = NULL;
1913:     }
1914:   } else {
1915:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1916:   }
1917:   return(0);
1918: }

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

1924:   Not collective

1926:   Input Parameters:
1927: + dm        - The DM object
1928: . numFields - The number of fields in this subproblem
1929: - fields    - The field numbers of the selected fields

1931:   Output Parameters:
1932: + is - The global indices for the subproblem
1933: - subdm - The DM for the subproblem

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

1937:   Level: intermediate

1939: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1940: @*/
1941: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1942: {

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

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

1958:   Not collective

1960:   Input Parameters:
1961: + dms - The DM objects
1962: - len - The number of DMs

1964:   Output Parameters:
1965: + is - The global indices for the subproblem, or NULL
1966: - superdm - The DM for the superproblem

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

1970:   Level: intermediate

1972: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1973: @*/
1974: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1975: {
1976:   PetscInt       i;

1984:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1985:   if (len) {
1986:     DM dm = dms[0];
1987:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1988:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1989:   }
1990:   return(0);
1991: }

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

2000:   Not collective

2002:   Input Parameter:
2003: . dm - the DM object

2005:   Output Parameters:
2006: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
2007: . namelist    - The name for each subdomain (or NULL if not requested)
2008: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2009: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2010: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

2012:   Level: intermediate

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

2019: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
2020: @*/
2021: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2022: {
2023:   PetscErrorCode      ierr;
2024:   DMSubDomainHookLink link;
2025:   PetscInt            i,l;

2034:   /*
2035:    Is it a good idea to apply the following check across all impls?
2036:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2037:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2038:    */
2039:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2040:   if (dm->ops->createdomaindecomposition) {
2041:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
2042:     /* copy subdomain hooks and context over to the subdomain DMs */
2043:     if (dmlist && *dmlist) {
2044:       for (i = 0; i < l; i++) {
2045:         for (link=dm->subdomainhook; link; link=link->next) {
2046:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
2047:         }
2048:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2049:       }
2050:     }
2051:     if (len) *len = l;
2052:   }
2053:   return(0);
2054: }

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

2059:   Not collective

2061:   Input Parameters:
2062: + dm - the DM object
2063: . n  - the number of subdomain scatters
2064: - subdms - the local subdomains

2066:   Output Parameters:
2067: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2068: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2069: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

2077:   Level: developer

2079: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2080: @*/
2081: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2082: {

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

2093: /*@
2094:   DMRefine - Refines a DM object

2096:   Collective on dm

2098:   Input Parameters:
2099: + dm   - the DM object
2100: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2102:   Output Parameter:
2103: . dmf - the refined DM, or NULL

2105:   Options Database Keys:
2106: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex

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

2110:   Level: developer

2112: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2113: @*/
2114: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2115: {
2116:   PetscErrorCode   ierr;
2117:   DMRefineHookLink link;

2121:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2122:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
2123:   (*dm->ops->refine)(dm,comm,dmf);
2124:   if (*dmf) {
2125:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2129:     (*dmf)->ctx       = dm->ctx;
2130:     (*dmf)->leveldown = dm->leveldown;
2131:     (*dmf)->levelup   = dm->levelup + 1;

2133:     DMSetMatType(*dmf,dm->mattype);
2134:     for (link=dm->refinehook; link; link=link->next) {
2135:       if (link->refinehook) {
2136:         (*link->refinehook)(dm,*dmf,link->ctx);
2137:       }
2138:     }
2139:   }
2140:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2141:   return(0);
2142: }

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

2147:    Logically Collective

2149:    Input Parameters:
2150: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2151: .  refinehook - function to run when setting up a coarser level
2152: .  interphook - function to run to update data on finer levels (once per SNESSolve())
2153: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2158: +  coarse - coarse level DM
2159: .  fine - fine level DM to interpolate problem to
2160: -  ctx - optional user-defined function context

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

2165: +  coarse - coarse level DM
2166: .  interp - matrix interpolating a coarse-level solution to the finer grid
2167: .  fine - fine level DM to update
2168: -  ctx - optional user-defined function context

2170:    Level: advanced

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

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

2177:    This function is currently not available from Fortran.

2179: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2180: @*/
2181: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2182: {
2183:   PetscErrorCode   ierr;
2184:   DMRefineHookLink link,*p;

2188:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2189:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2190:   }
2191:   PetscNew(&link);
2192:   link->refinehook = refinehook;
2193:   link->interphook = interphook;
2194:   link->ctx        = ctx;
2195:   link->next       = NULL;
2196:   *p               = link;
2197:   return(0);
2198: }

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

2203:    Logically Collective

2205:    Input Parameters:
2206: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2207: .  refinehook - function to run when setting up a coarser level
2208: .  interphook - function to run to update data on finer levels (once per SNESSolve())
2209: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2211:    Level: advanced

2213:    Notes:
2214:    This function does nothing if the hook is not in the list.

2216:    This function is currently not available from Fortran.

2218: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2219: @*/
2220: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2221: {
2222:   PetscErrorCode   ierr;
2223:   DMRefineHookLink link,*p;

2227:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2228:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2229:       link = *p;
2230:       *p = link->next;
2231:       PetscFree(link);
2232:       break;
2233:     }
2234:   }
2235:   return(0);
2236: }

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

2241:    Collective if any hooks are

2243:    Input Parameters:
2244: +  coarse - coarser DM to use as a base
2245: .  interp - interpolation matrix, apply using MatInterpolate()
2246: -  fine - finer DM to update

2248:    Level: developer

2250: .seealso: DMRefineHookAdd(), MatInterpolate()
2251: @*/
2252: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2253: {
2254:   PetscErrorCode   ierr;
2255:   DMRefineHookLink link;

2258:   for (link=fine->refinehook; link; link=link->next) {
2259:     if (link->interphook) {
2260:       (*link->interphook)(coarse,interp,fine,link->ctx);
2261:     }
2262:   }
2263:   return(0);
2264: }

2266: /*@
2267:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2269:    Collective on DM

2271:    Input Parameters:
2272: +  coarse - coarse DM
2273: .  fine   - fine DM
2274: .  interp - (optional) the matrix computed by DMCreateInterpolation().  Implementations may not need this, but if it
2275:             is available it can avoid some recomputation.  If it is provided, MatInterpolate() will be used if
2276:             the coarse DM does not have a specialized implementation.
2277: -  coarseSol - solution on the coarse mesh

2279:    Output Parameter:
2280: .  fineSol - the interpolation of coarseSol to the fine mesh

2282:    Level: developer

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

2289: .seealso DMInterpolate(), DMCreateInterpolation()
2290: @*/
2291: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2292: {
2293:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;


2302:   PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2303:   if (interpsol) {
2304:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2305:   } else if (interp) {
2306:     MatInterpolate(interp, coarseSol, fineSol);
2307:   } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2308:   return(0);
2309: }

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

2314:     Not Collective

2316:     Input Parameter:
2317: .   dm - the DM object

2319:     Output Parameter:
2320: .   level - number of refinements

2322:     Level: developer

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

2326: @*/
2327: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2328: {
2331:   *level = dm->levelup;
2332:   return(0);
2333: }

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

2338:     Not Collective

2340:     Input Parameters:
2341: +   dm - the DM object
2342: -   level - number of refinements

2344:     Level: advanced

2346:     Notes:
2347:     This value is used by PCMG to determine how many multigrid levels to use

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

2351: @*/
2352: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2353: {
2356:   dm->levelup = level;
2357:   return(0);
2358: }

2360: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2361: {
2365:   *tdm = dm->transformDM;
2366:   return(0);
2367: }

2369: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2370: {
2374:   *tv = dm->transform;
2375:   return(0);
2376: }

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

2381:   Input Parameter:
2382: . dm - The DM

2384:   Output Parameter:
2385: . flg - PETSC_TRUE if a basis transformation should be done

2387:   Level: developer

2389: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2390: @*/
2391: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2392: {
2393:   Vec            tv;

2399:   DMGetBasisTransformVec_Internal(dm, &tv);
2400:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2401:   return(0);
2402: }

2404: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2405: {
2406:   PetscSection   s, ts;
2407:   PetscScalar   *ta;
2408:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2412:   DMGetCoordinateDim(dm, &cdim);
2413:   DMGetLocalSection(dm, &s);
2414:   PetscSectionGetChart(s, &pStart, &pEnd);
2415:   PetscSectionGetNumFields(s, &Nf);
2416:   DMClone(dm, &dm->transformDM);
2417:   DMGetLocalSection(dm->transformDM, &ts);
2418:   PetscSectionSetNumFields(ts, Nf);
2419:   PetscSectionSetChart(ts, pStart, pEnd);
2420:   for (f = 0; f < Nf; ++f) {
2421:     PetscSectionGetFieldComponents(s, f, &Nc);
2422:     /* We could start to label fields by their transformation properties */
2423:     if (Nc != cdim) continue;
2424:     for (p = pStart; p < pEnd; ++p) {
2425:       PetscSectionGetFieldDof(s, p, f, &dof);
2426:       if (!dof) continue;
2427:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2428:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2429:     }
2430:   }
2431:   PetscSectionSetUp(ts);
2432:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2433:   VecGetArray(dm->transform, &ta);
2434:   for (p = pStart; p < pEnd; ++p) {
2435:     for (f = 0; f < Nf; ++f) {
2436:       PetscSectionGetFieldDof(ts, p, f, &dof);
2437:       if (dof) {
2438:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2439:         PetscScalar       *tva;
2440:         const PetscScalar *A;

2442:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2443:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2444:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2445:         PetscArraycpy(tva, A, PetscSqr(cdim));
2446:       }
2447:     }
2448:   }
2449:   VecRestoreArray(dm->transform, &ta);
2450:   return(0);
2451: }

2453: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2454: {

2460:   newdm->transformCtx       = dm->transformCtx;
2461:   newdm->transformSetUp     = dm->transformSetUp;
2462:   newdm->transformDestroy   = NULL;
2463:   newdm->transformGetMatrix = dm->transformGetMatrix;
2464:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2465:   return(0);
2466: }

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

2471:    Logically Collective

2473:    Input Parameters:
2474: +  dm - the DM
2475: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2476: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2477: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2482: +  dm - global DM
2483: .  g - global vector
2484: .  mode - mode
2485: .  l - local vector
2486: -  ctx - optional user-defined function context

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

2491: +  global - global DM
2492: -  ctx - optional user-defined function context

2494:    Level: advanced

2496: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2497: @*/
2498: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2499: {
2500:   PetscErrorCode          ierr;
2501:   DMGlobalToLocalHookLink link,*p;

2505:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2506:   PetscNew(&link);
2507:   link->beginhook = beginhook;
2508:   link->endhook   = endhook;
2509:   link->ctx       = ctx;
2510:   link->next      = NULL;
2511:   *p              = link;
2512:   return(0);
2513: }

2515: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2516: {
2517:   Mat cMat;
2518:   Vec cVec;
2519:   PetscSection section, cSec;
2520:   PetscInt pStart, pEnd, p, dof;

2525:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2526:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2527:     PetscInt nRows;

2529:     MatGetSize(cMat,&nRows,NULL);
2530:     if (nRows <= 0) return(0);
2531:     DMGetLocalSection(dm,&section);
2532:     MatCreateVecs(cMat,NULL,&cVec);
2533:     MatMult(cMat,l,cVec);
2534:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2535:     for (p = pStart; p < pEnd; p++) {
2536:       PetscSectionGetDof(cSec,p,&dof);
2537:       if (dof) {
2538:         PetscScalar *vals;
2539:         VecGetValuesSection(cVec,cSec,p,&vals);
2540:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2541:       }
2542:     }
2543:     VecDestroy(&cVec);
2544:   }
2545:   return(0);
2546: }

2548: /*@
2549:     DMGlobalToLocal - update local vectors from global vector

2551:     Neighbor-wise Collective on dm

2553:     Input Parameters:
2554: +   dm - the DM object
2555: .   g - the global vector
2556: .   mode - INSERT_VALUES or ADD_VALUES
2557: -   l - the local vector

2559:     Notes:
2560:     The communication involved in this update can be overlapped with computation by using
2561:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2563:     Level: beginner

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

2567: @*/
2568: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2569: {

2573:   DMGlobalToLocalBegin(dm,g,mode,l);
2574:   DMGlobalToLocalEnd(dm,g,mode,l);
2575:   return(0);
2576: }

2578: /*@
2579:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2581:     Neighbor-wise Collective on dm

2583:     Input Parameters:
2584: +   dm - the DM object
2585: .   g - the global vector
2586: .   mode - INSERT_VALUES or ADD_VALUES
2587: -   l - the local vector

2589:     Level: intermediate

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

2593: @*/
2594: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2595: {
2596:   PetscSF                 sf;
2597:   PetscErrorCode          ierr;
2598:   DMGlobalToLocalHookLink link;

2602:   for (link=dm->gtolhook; link; link=link->next) {
2603:     if (link->beginhook) {
2604:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2605:     }
2606:   }
2607:   DMGetSectionSF(dm, &sf);
2608:   if (sf) {
2609:     const PetscScalar *gArray;
2610:     PetscScalar       *lArray;
2611:     PetscMemType      lmtype,gmtype;

2613:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2614:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2615:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2616:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2617:     VecRestoreArrayAndMemType(l, &lArray);
2618:     VecRestoreArrayReadAndMemType(g, &gArray);
2619:   } else {
2620:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2621:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2622:   }
2623:   return(0);
2624: }

2626: /*@
2627:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2629:     Neighbor-wise Collective on dm

2631:     Input Parameters:
2632: +   dm - the DM object
2633: .   g - the global vector
2634: .   mode - INSERT_VALUES or ADD_VALUES
2635: -   l - the local vector

2637:     Level: intermediate

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

2641: @*/
2642: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2643: {
2644:   PetscSF                 sf;
2645:   PetscErrorCode          ierr;
2646:   const PetscScalar      *gArray;
2647:   PetscScalar            *lArray;
2648:   PetscBool               transform;
2649:   DMGlobalToLocalHookLink link;
2650:   PetscMemType            lmtype,gmtype;

2654:   DMGetSectionSF(dm, &sf);
2655:   DMHasBasisTransform(dm, &transform);
2656:   if (sf) {
2657:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2659:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2660:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2661:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2662:     VecRestoreArrayAndMemType(l, &lArray);
2663:     VecRestoreArrayReadAndMemType(g, &gArray);
2664:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2665:   } else {
2666:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2667:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2668:   }
2669:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2670:   for (link=dm->gtolhook; link; link=link->next) {
2671:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2672:   }
2673:   return(0);
2674: }

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

2679:    Logically Collective

2681:    Input Parameters:
2682: +  dm - the DM
2683: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2684: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2685: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2690: +  dm - global DM
2691: .  l - local vector
2692: .  mode - mode
2693: .  g - global vector
2694: -  ctx - optional user-defined function context

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

2699: +  global - global DM
2700: .  l - local vector
2701: .  mode - mode
2702: .  g - global vector
2703: -  ctx - optional user-defined function context

2705:    Level: advanced

2707: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2708: @*/
2709: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2710: {
2711:   PetscErrorCode          ierr;
2712:   DMLocalToGlobalHookLink link,*p;

2716:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2717:   PetscNew(&link);
2718:   link->beginhook = beginhook;
2719:   link->endhook   = endhook;
2720:   link->ctx       = ctx;
2721:   link->next      = NULL;
2722:   *p              = link;
2723:   return(0);
2724: }

2726: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2727: {
2728:   Mat cMat;
2729:   Vec cVec;
2730:   PetscSection section, cSec;
2731:   PetscInt pStart, pEnd, p, dof;

2736:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2737:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2738:     PetscInt nRows;

2740:     MatGetSize(cMat,&nRows,NULL);
2741:     if (nRows <= 0) return(0);
2742:     DMGetLocalSection(dm,&section);
2743:     MatCreateVecs(cMat,NULL,&cVec);
2744:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2745:     for (p = pStart; p < pEnd; p++) {
2746:       PetscSectionGetDof(cSec,p,&dof);
2747:       if (dof) {
2748:         PetscInt d;
2749:         PetscScalar *vals;
2750:         VecGetValuesSection(l,section,p,&vals);
2751:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2752:         /* for this to be the true transpose, we have to zero the values that
2753:          * we just extracted */
2754:         for (d = 0; d < dof; d++) {
2755:           vals[d] = 0.;
2756:         }
2757:       }
2758:     }
2759:     MatMultTransposeAdd(cMat,cVec,l,l);
2760:     VecDestroy(&cVec);
2761:   }
2762:   return(0);
2763: }
2764: /*@
2765:     DMLocalToGlobal - updates global vectors from local vectors

2767:     Neighbor-wise Collective on dm

2769:     Input Parameters:
2770: +   dm - the DM object
2771: .   l - the local vector
2772: .   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.
2773: -   g - the global vector

2775:     Notes:
2776:     The communication involved in this update can be overlapped with computation by using
2777:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2782:     Level: beginner

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

2786: @*/
2787: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2788: {

2792:   DMLocalToGlobalBegin(dm,l,mode,g);
2793:   DMLocalToGlobalEnd(dm,l,mode,g);
2794:   return(0);
2795: }

2797: /*@
2798:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2800:     Neighbor-wise Collective on dm

2802:     Input Parameters:
2803: +   dm - the DM object
2804: .   l - the local vector
2805: .   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.
2806: -   g - the global vector

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

2812:     Level: intermediate

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

2816: @*/
2817: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2818: {
2819:   PetscSF                 sf;
2820:   PetscSection            s, gs;
2821:   DMLocalToGlobalHookLink link;
2822:   Vec                     tmpl;
2823:   const PetscScalar      *lArray;
2824:   PetscScalar            *gArray;
2825:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2826:   PetscErrorCode          ierr;
2827:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

2831:   for (link=dm->ltoghook; link; link=link->next) {
2832:     if (link->beginhook) {
2833:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2834:     }
2835:   }
2836:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2837:   DMGetSectionSF(dm, &sf);
2838:   DMGetLocalSection(dm, &s);
2839:   switch (mode) {
2840:   case INSERT_VALUES:
2841:   case INSERT_ALL_VALUES:
2842:   case INSERT_BC_VALUES:
2843:     isInsert = PETSC_TRUE; break;
2844:   case ADD_VALUES:
2845:   case ADD_ALL_VALUES:
2846:   case ADD_BC_VALUES:
2847:     isInsert = PETSC_FALSE; break;
2848:   default:
2849:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2850:   }
2851:   if ((sf && !isInsert) || (s && isInsert)) {
2852:     DMHasBasisTransform(dm, &transform);
2853:     if (transform) {
2854:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2855:       VecCopy(l, tmpl);
2856:       DMPlexLocalToGlobalBasis(dm, tmpl);
2857:       VecGetArrayRead(tmpl, &lArray);
2858:     } else if (isInsert) {
2859:       VecGetArrayRead(l, &lArray);
2860:     } else {
2861:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2862:       l_inplace = PETSC_TRUE;
2863:     }
2864:     if (s && isInsert) {
2865:       VecGetArray(g, &gArray);
2866:     } else {
2867:       VecGetArrayAndMemType(g, &gArray, &gmtype);
2868:       g_inplace = PETSC_TRUE;
2869:     }
2870:     if (sf && !isInsert) {
2871:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2872:     } else if (s && isInsert) {
2873:       PetscInt gStart, pStart, pEnd, p;

2875:       DMGetGlobalSection(dm, &gs);
2876:       PetscSectionGetChart(s, &pStart, &pEnd);
2877:       VecGetOwnershipRange(g, &gStart, NULL);
2878:       for (p = pStart; p < pEnd; ++p) {
2879:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2881:         PetscSectionGetDof(s, p, &dof);
2882:         PetscSectionGetDof(gs, p, &gdof);
2883:         PetscSectionGetConstraintDof(s, p, &cdof);
2884:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2885:         PetscSectionGetOffset(s, p, &off);
2886:         PetscSectionGetOffset(gs, p, &goff);
2887:         /* Ignore off-process data and points with no global data */
2888:         if (!gdof || goff < 0) continue;
2889:         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);
2890:         /* If no constraints are enforced in the global vector */
2891:         if (!gcdof) {
2892:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2893:           /* If constraints are enforced in the global vector */
2894:         } else if (cdof == gcdof) {
2895:           const PetscInt *cdofs;
2896:           PetscInt        cind = 0;

2898:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2899:           for (d = 0, e = 0; d < dof; ++d) {
2900:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2901:             gArray[goff-gStart+e++] = lArray[off+d];
2902:           }
2903:         } 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);
2904:       }
2905:     }
2906:     if (g_inplace) {
2907:       VecRestoreArrayAndMemType(g, &gArray);
2908:     } else {
2909:       VecRestoreArray(g, &gArray);
2910:     }
2911:     if (transform) {
2912:       VecRestoreArrayRead(tmpl, &lArray);
2913:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2914:     } else if (l_inplace) {
2915:       VecRestoreArrayReadAndMemType(l, &lArray);
2916:     } else {
2917:       VecRestoreArrayRead(l, &lArray);
2918:     }
2919:   } else {
2920:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2921:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2922:   }
2923:   return(0);
2924: }

2926: /*@
2927:     DMLocalToGlobalEnd - updates global vectors from local vectors

2929:     Neighbor-wise Collective on dm

2931:     Input Parameters:
2932: +   dm - the DM object
2933: .   l - the local vector
2934: .   mode - INSERT_VALUES or ADD_VALUES
2935: -   g - the global vector

2937:     Level: intermediate

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

2941: @*/
2942: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2943: {
2944:   PetscSF                 sf;
2945:   PetscSection            s;
2946:   DMLocalToGlobalHookLink link;
2947:   PetscBool               isInsert, transform;
2948:   PetscErrorCode          ierr;

2952:   DMGetSectionSF(dm, &sf);
2953:   DMGetLocalSection(dm, &s);
2954:   switch (mode) {
2955:   case INSERT_VALUES:
2956:   case INSERT_ALL_VALUES:
2957:     isInsert = PETSC_TRUE; break;
2958:   case ADD_VALUES:
2959:   case ADD_ALL_VALUES:
2960:     isInsert = PETSC_FALSE; break;
2961:   default:
2962:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2963:   }
2964:   if (sf && !isInsert) {
2965:     const PetscScalar *lArray;
2966:     PetscScalar       *gArray;
2967:     Vec                tmpl;

2969:     DMHasBasisTransform(dm, &transform);
2970:     if (transform) {
2971:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2972:       VecGetArrayRead(tmpl, &lArray);
2973:     } else {
2974:       VecGetArrayReadAndMemType(l, &lArray, NULL);
2975:     }
2976:     VecGetArrayAndMemType(g, &gArray, NULL);
2977:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2978:     if (transform) {
2979:       VecRestoreArrayRead(tmpl, &lArray);
2980:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2981:     } else {
2982:       VecRestoreArrayReadAndMemType(l, &lArray);
2983:     }
2984:     VecRestoreArrayAndMemType(g, &gArray);
2985:   } else if (s && isInsert) {
2986:   } else {
2987:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2988:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2989:   }
2990:   for (link=dm->ltoghook; link; link=link->next) {
2991:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2992:   }
2993:   return(0);
2994: }

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

3001:    Neighbor-wise Collective on dm

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

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

3011:    Level: intermediate

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

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

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

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

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

3038:    Neighbor-wise Collective on dm

3040:    Input Parameters:
3041: +  da - the DM object
3042: .  g - the original local vector
3043: -  mode - one of INSERT_VALUES or ADD_VALUES

3045:    Output Parameter:
3046: .  l  - the local vector with correct ghost values

3048:    Level: intermediate

3050:    Notes:
3051:    The local vectors used here need not be the same as those
3052:    obtained from DMCreateLocalVector(), BUT they
3053:    must have the same parallel data layout; they could, for example, be
3054:    obtained with VecDuplicate() from the DM originating vectors.

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

3058: @*/
3059: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3060: {
3061:   PetscErrorCode          ierr;

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

3070: /*@
3071:     DMCoarsen - Coarsens a DM object

3073:     Collective on dm

3075:     Input Parameters:
3076: +   dm - the DM object
3077: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

3079:     Output Parameter:
3080: .   dmc - the coarsened DM

3082:     Level: developer

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

3086: @*/
3087: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3088: {
3089:   PetscErrorCode    ierr;
3090:   DMCoarsenHookLink link;

3094:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
3095:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3096:   (*dm->ops->coarsen)(dm, comm, dmc);
3097:   if (*dmc) {
3098:     DMSetCoarseDM(dm,*dmc);
3099:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3100:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3101:     (*dmc)->ctx               = dm->ctx;
3102:     (*dmc)->levelup           = dm->levelup;
3103:     (*dmc)->leveldown         = dm->leveldown + 1;
3104:     DMSetMatType(*dmc,dm->mattype);
3105:     for (link=dm->coarsenhook; link; link=link->next) {
3106:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3107:     }
3108:   }
3109:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3110:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3111:   return(0);
3112: }

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

3117:    Logically Collective

3119:    Input Parameters:
3120: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3121: .  coarsenhook - function to run when setting up a coarser level
3122: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3123: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

3128: +  fine - fine level DM
3129: .  coarse - coarse level DM to restrict problem to
3130: -  ctx - optional user-defined function context

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

3135: +  fine - fine level DM
3136: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
3137: .  rscale - scaling vector for restriction
3138: .  inject - matrix restricting by injection
3139: .  coarse - coarse level DM to update
3140: -  ctx - optional user-defined function context

3142:    Level: advanced

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

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

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

3152:    This function is currently not available from Fortran.

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

3163:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3164:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3165:   }
3166:   PetscNew(&link);
3167:   link->coarsenhook  = coarsenhook;
3168:   link->restricthook = restricthook;
3169:   link->ctx          = ctx;
3170:   link->next         = NULL;
3171:   *p                 = link;
3172:   return(0);
3173: }

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

3178:    Logically Collective

3180:    Input Parameters:
3181: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3182: .  coarsenhook - function to run when setting up a coarser level
3183: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3184: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3186:    Level: advanced

3188:    Notes:
3189:    This function does nothing if the hook is not in the list.

3191:    This function is currently not available from Fortran.

3193: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3194: @*/
3195: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3196: {
3197:   PetscErrorCode    ierr;
3198:   DMCoarsenHookLink link,*p;

3202:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3203:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3204:       link = *p;
3205:       *p = link->next;
3206:       PetscFree(link);
3207:       break;
3208:     }
3209:   }
3210:   return(0);
3211: }

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

3216:    Collective if any hooks are

3218:    Input Parameters:
3219: +  fine - finer DM to use as a base
3220: .  restrct - restriction matrix, apply using MatRestrict()
3221: .  rscale - scaling vector for restriction
3222: .  inject - injection matrix, also use MatRestrict()
3223: -  coarse - coarser DM to update

3225:    Level: developer

3227: .seealso: DMCoarsenHookAdd(), MatRestrict()
3228: @*/
3229: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3230: {
3231:   PetscErrorCode    ierr;
3232:   DMCoarsenHookLink link;

3235:   for (link=fine->coarsenhook; link; link=link->next) {
3236:     if (link->restricthook) {
3237:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3238:     }
3239:   }
3240:   return(0);
3241: }

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

3246:    Logically Collective on global

3248:    Input Parameters:
3249: +  global - global DM
3250: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3251: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3252: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3254:    Calling sequence for ddhook:
3255: $    ddhook(DM global,DM block,void *ctx)

3257: +  global - global DM
3258: .  block  - block DM
3259: -  ctx - optional user-defined function context

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

3264: +  global - global DM
3265: .  out    - scatter to the outer (with ghost and overlap points) block vector
3266: .  in     - scatter to block vector values only owned locally
3267: .  block  - block DM
3268: -  ctx - optional user-defined function context

3270:    Level: advanced

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

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

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

3280:    This function is currently not available from Fortran.

3282: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3283: @*/
3284: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3285: {
3286:   PetscErrorCode      ierr;
3287:   DMSubDomainHookLink link,*p;

3291:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3292:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3293:   }
3294:   PetscNew(&link);
3295:   link->restricthook = restricthook;
3296:   link->ddhook       = ddhook;
3297:   link->ctx          = ctx;
3298:   link->next         = NULL;
3299:   *p                 = link;
3300:   return(0);
3301: }

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

3306:    Logically Collective

3308:    Input Parameters:
3309: +  global - global DM
3310: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3311: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3312: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3314:    Level: advanced

3316:    Notes:

3318:    This function is currently not available from Fortran.

3320: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3321: @*/
3322: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3323: {
3324:   PetscErrorCode      ierr;
3325:   DMSubDomainHookLink link,*p;

3329:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3330:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3331:       link = *p;
3332:       *p = link->next;
3333:       PetscFree(link);
3334:       break;
3335:     }
3336:   }
3337:   return(0);
3338: }

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

3343:    Collective if any hooks are

3345:    Input Parameters:
3346: +  fine - finer DM to use as a base
3347: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3348: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3349: -  coarse - coarer DM to update

3351:    Level: developer

3353: .seealso: DMCoarsenHookAdd(), MatRestrict()
3354: @*/
3355: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3356: {
3357:   PetscErrorCode      ierr;
3358:   DMSubDomainHookLink link;

3361:   for (link=global->subdomainhook; link; link=link->next) {
3362:     if (link->restricthook) {
3363:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3364:     }
3365:   }
3366:   return(0);
3367: }

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

3372:     Not Collective

3374:     Input Parameter:
3375: .   dm - the DM object

3377:     Output Parameter:
3378: .   level - number of coarsenings

3380:     Level: developer

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

3384: @*/
3385: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3386: {
3390:   *level = dm->leveldown;
3391:   return(0);
3392: }

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

3397:     Not Collective

3399:     Input Parameters:
3400: +   dm - the DM object
3401: -   level - number of coarsenings

3403:     Level: developer

3405: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3406: @*/
3407: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3408: {
3411:   dm->leveldown = level;
3412:   return(0);
3413: }

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

3418:     Collective on dm

3420:     Input Parameters:
3421: +   dm - the DM object
3422: -   nlevels - the number of levels of refinement

3424:     Output Parameter:
3425: .   dmf - the refined DM hierarchy

3427:     Level: developer

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

3431: @*/
3432: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3433: {

3438:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3439:   if (nlevels == 0) return(0);
3441:   if (dm->ops->refinehierarchy) {
3442:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3443:   } else if (dm->ops->refine) {
3444:     PetscInt i;

3446:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3447:     for (i=1; i<nlevels; i++) {
3448:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3449:     }
3450:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3451:   return(0);
3452: }

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

3457:     Collective on dm

3459:     Input Parameters:
3460: +   dm - the DM object
3461: -   nlevels - the number of levels of coarsening

3463:     Output Parameter:
3464: .   dmc - the coarsened DM hierarchy

3466:     Level: developer

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

3470: @*/
3471: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3472: {

3477:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3478:   if (nlevels == 0) return(0);
3480:   if (dm->ops->coarsenhierarchy) {
3481:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3482:   } else if (dm->ops->coarsen) {
3483:     PetscInt i;

3485:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3486:     for (i=1; i<nlevels; i++) {
3487:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3488:     }
3489:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3490:   return(0);
3491: }

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

3496:     Not Collective

3498:     Input Parameters:
3499: +   dm - the DM object
3500: -   destroy - the destroy function

3502:     Level: intermediate

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

3506: @*/
3507: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3508: {
3511:   dm->ctxdestroy = destroy;
3512:   return(0);
3513: }

3515: /*@
3516:     DMSetApplicationContext - Set a user context into a DM object

3518:     Not Collective

3520:     Input Parameters:
3521: +   dm - the DM object
3522: -   ctx - the user context

3524:     Level: intermediate

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

3528: @*/
3529: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3530: {
3533:   dm->ctx = ctx;
3534:   return(0);
3535: }

3537: /*@
3538:     DMGetApplicationContext - Gets a user context from a DM object

3540:     Not Collective

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

3545:     Output Parameter:
3546: .   ctx - the user context

3548:     Level: intermediate

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

3552: @*/
3553: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3554: {
3557:   *(void**)ctx = dm->ctx;
3558:   return(0);
3559: }

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

3564:     Logically Collective on dm

3566:     Input Parameters:
3567: +   dm - the DM object
3568: -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)

3570:     Level: intermediate

3572: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3573:          DMSetJacobian()

3575: @*/
3576: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3577: {
3580:   dm->ops->computevariablebounds = f;
3581:   return(0);
3582: }

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

3587:     Not Collective

3589:     Input Parameter:
3590: .   dm - the DM object to destroy

3592:     Output Parameter:
3593: .   flg - PETSC_TRUE if the variable bounds function exists

3595:     Level: developer

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

3599: @*/
3600: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3601: {
3605:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3606:   return(0);
3607: }

3609: /*@C
3610:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3612:     Logically Collective on dm

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

3617:     Output parameters:
3618: +   xl - lower bound
3619: -   xu - upper bound

3621:     Level: advanced

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

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

3628: @*/
3629: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3630: {

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

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

3645:     Not Collective

3647:     Input Parameter:
3648: .   dm - the DM object

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

3653:     Level: developer

3655: .seealso DMCreateColoring()

3657: @*/
3658: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3659: {
3663:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3664:   return(0);
3665: }

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

3670:     Not Collective

3672:     Input Parameter:
3673: .   dm - the DM object

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

3678:     Level: developer

3680: .seealso DMCreateRestriction()

3682: @*/
3683: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3684: {
3688:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3689:   return(0);
3690: }

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

3695:     Not Collective

3697:     Input Parameter:
3698: .   dm - the DM object

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

3703:     Level: developer

3705: .seealso DMCreateInjection()

3707: @*/
3708: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3709: {

3715:   if (dm->ops->hascreateinjection) {
3716:     (*dm->ops->hascreateinjection)(dm,flg);
3717:   } else {
3718:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3719:   }
3720:   return(0);
3721: }

3723: PetscFunctionList DMList              = NULL;
3724: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3726: /*@C
3727:   DMSetType - Builds a DM, for a particular DM implementation.

3729:   Collective on dm

3731:   Input Parameters:
3732: + dm     - The DM object
3733: - method - The name of the DM type

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

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

3741:   Level: intermediate

3743: .seealso: DMGetType(), DMCreate()
3744: @*/
3745: PetscErrorCode  DMSetType(DM dm, DMType method)
3746: {
3747:   PetscErrorCode (*r)(DM);
3748:   PetscBool      match;

3753:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3754:   if (match) return(0);

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

3760:   if (dm->ops->destroy) {
3761:     (*dm->ops->destroy)(dm);
3762:   }
3763:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3764:   PetscObjectChangeTypeName((PetscObject)dm,method);
3765:   (*r)(dm);
3766:   return(0);
3767: }

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

3772:   Not Collective

3774:   Input Parameter:
3775: . dm  - The DM

3777:   Output Parameter:
3778: . type - The DM type name

3780:   Level: intermediate

3782: .seealso: DMSetType(), DMCreate()
3783: @*/
3784: PetscErrorCode  DMGetType(DM dm, DMType *type)
3785: {

3791:   DMRegisterAll();
3792:   *type = ((PetscObject)dm)->type_name;
3793:   return(0);
3794: }

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

3799:   Collective on dm

3801:   Input Parameters:
3802: + dm - the DM
3803: - newtype - new DM type (use "same" for the same type)

3805:   Output Parameter:
3806: . M - pointer to new DM

3808:   Notes:
3809:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3810:   the MPI communicator of the generated DM is always the same as the communicator
3811:   of the input DM.

3813:   Level: intermediate

3815: .seealso: DMCreate()
3816: @*/
3817: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3818: {
3819:   DM             B;
3820:   char           convname[256];
3821:   PetscBool      sametype/*, issame */;

3828:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3829:   /* PetscStrcmp(newtype, "same", &issame); */
3830:   if (sametype) {
3831:     *M   = dm;
3832:     PetscObjectReference((PetscObject) dm);
3833:     return(0);
3834:   } else {
3835:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3837:     /*
3838:        Order of precedence:
3839:        1) See if a specialized converter is known to the current DM.
3840:        2) See if a specialized converter is known to the desired DM class.
3841:        3) See if a good general converter is registered for the desired class
3842:        4) See if a good general converter is known for the current matrix.
3843:        5) Use a really basic converter.
3844:     */

3846:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3847:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3848:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3849:     PetscStrlcat(convname,"_",sizeof(convname));
3850:     PetscStrlcat(convname,newtype,sizeof(convname));
3851:     PetscStrlcat(convname,"_C",sizeof(convname));
3852:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3853:     if (conv) goto foundconv;

3855:     /* 2)  See if a specialized converter is known to the desired DM class. */
3856:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3857:     DMSetType(B, newtype);
3858:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3859:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3860:     PetscStrlcat(convname,"_",sizeof(convname));
3861:     PetscStrlcat(convname,newtype,sizeof(convname));
3862:     PetscStrlcat(convname,"_C",sizeof(convname));
3863:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3864:     if (conv) {
3865:       DMDestroy(&B);
3866:       goto foundconv;
3867:     }

3869: #if 0
3870:     /* 3) See if a good general converter is registered for the desired class */
3871:     conv = B->ops->convertfrom;
3872:     DMDestroy(&B);
3873:     if (conv) goto foundconv;

3875:     /* 4) See if a good general converter is known for the current matrix */
3876:     if (dm->ops->convert) {
3877:       conv = dm->ops->convert;
3878:     }
3879:     if (conv) goto foundconv;
3880: #endif

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

3885: foundconv:
3886:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3887:     (*conv)(dm,newtype,M);
3888:     /* Things that are independent of DM type: We should consult DMClone() here */
3889:     {
3890:       PetscBool             isper;
3891:       const PetscReal      *maxCell, *L;
3892:       const DMBoundaryType *bd;
3893:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3894:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3895:       (*M)->prealloc_only = dm->prealloc_only;
3896:       PetscFree((*M)->vectype);
3897:       PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3898:       PetscFree((*M)->mattype);
3899:       PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3900:     }
3901:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3902:   }
3903:   PetscObjectStateIncrease((PetscObject) *M);
3904:   return(0);
3905: }

3907: /*--------------------------------------------------------------------------------------------------------------------*/

3909: /*@C
3910:   DMRegister -  Adds a new DM component implementation

3912:   Not Collective

3914:   Input Parameters:
3915: + name        - The name of a new user-defined creation routine
3916: - create_func - The creation routine itself

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

3921:   Sample usage:
3922: .vb
3923:     DMRegister("my_da", MyDMCreate);
3924: .ve

3926:   Then, your DM type can be chosen with the procedural interface via
3927: .vb
3928:     DMCreate(MPI_Comm, DM *);
3929:     DMSetType(DM,"my_da");
3930: .ve
3931:    or at runtime via the option
3932: .vb
3933:     -da_type my_da
3934: .ve

3936:   Level: advanced

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

3940: @*/
3941: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3942: {

3946:   DMInitializePackage();
3947:   PetscFunctionListAdd(&DMList,sname,function);
3948:   return(0);
3949: }

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

3954:   Collective on viewer

3956:   Input Parameters:
3957: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3958:            some related function before a call to DMLoad().
3959: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3960:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3962:    Level: intermediate

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

3967:   Notes for advanced users:
3968:   Most users should not need to know the details of the binary storage
3969:   format, since DMLoad() and DMView() completely hide these details.
3970:   But for anyone who's interested, the standard binary matrix storage
3971:   format is
3972: .vb
3973:      has not yet been determined
3974: .ve

3976: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3977: @*/
3978: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3979: {
3980:   PetscBool      isbinary, ishdf5;

3986:   PetscViewerCheckReadable(viewer);
3987:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3988:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3989:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3990:   if (isbinary) {
3991:     PetscInt classid;
3992:     char     type[256];

3994:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3995:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3996:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3997:     DMSetType(newdm, type);
3998:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3999:   } else if (ishdf5) {
4000:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
4001:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4002:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
4003:   return(0);
4004: }

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

4009:   Not collective

4011:   Input Parameter:
4012: . dm - the DM

4014:   Output Parameters:
4015: + lmin - local minimum coordinates (length coord dim, optional)
4016: - lmax - local maximim coordinates (length coord dim, optional)

4018:   Level: beginner

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

4022: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
4023: @*/
4024: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
4025: {
4026:   Vec                coords = NULL;
4027:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
4028:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
4029:   const PetscScalar *local_coords;
4030:   PetscInt           N, Ni;
4031:   PetscInt           cdim, i, j;
4032:   PetscErrorCode     ierr;

4036:   DMGetCoordinateDim(dm, &cdim);
4037:   DMGetCoordinates(dm, &coords);
4038:   if (coords) {
4039:     VecGetArrayRead(coords, &local_coords);
4040:     VecGetLocalSize(coords, &N);
4041:     Ni   = N/cdim;
4042:     for (i = 0; i < Ni; ++i) {
4043:       for (j = 0; j < 3; ++j) {
4044:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4045:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
4046:       }
4047:     }
4048:     VecRestoreArrayRead(coords, &local_coords);
4049:   } else {
4050:     PetscBool isda;

4052:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4053:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4054:   }
4055:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
4056:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
4057:   return(0);
4058: }

4060: /*@
4061:   DMGetBoundingBox - Returns the global bounding box for the DM.

4063:   Collective

4065:   Input Parameter:
4066: . dm - the DM

4068:   Output Parameters:
4069: + gmin - global minimum coordinates (length coord dim, optional)
4070: - gmax - global maximim coordinates (length coord dim, optional)

4072:   Level: beginner

4074: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4075: @*/
4076: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4077: {
4078:   PetscReal      lmin[3], lmax[3];
4079:   PetscInt       cdim;
4080:   PetscMPIInt    count;

4085:   DMGetCoordinateDim(dm, &cdim);
4086:   PetscMPIIntCast(cdim, &count);
4087:   DMGetLocalBoundingBox(dm, lmin, lmax);
4088:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4089:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4090:   return(0);
4091: }

4093: /******************************** FEM Support **********************************/

4095: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4096: {
4097:   PetscInt       f;

4101:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4102:   for (f = 0; f < len; ++f) {
4103:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
4104:   }
4105:   return(0);
4106: }

4108: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4109: {
4110:   PetscInt       f, g;

4114:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4115:   for (f = 0; f < rows; ++f) {
4116:     PetscPrintf(PETSC_COMM_SELF, "  |");
4117:     for (g = 0; g < cols; ++g) {
4118:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4119:     }
4120:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4121:   }
4122:   return(0);
4123: }

4125: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4126: {
4127:   PetscInt          localSize, bs;
4128:   PetscMPIInt       size;
4129:   Vec               x, xglob;
4130:   const PetscScalar *xarray;
4131:   PetscErrorCode    ierr;

4134:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4135:   VecDuplicate(X, &x);
4136:   VecCopy(X, x);
4137:   VecChop(x, tol);
4138:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4139:   if (size > 1) {
4140:     VecGetLocalSize(x,&localSize);
4141:     VecGetArrayRead(x,&xarray);
4142:     VecGetBlockSize(x,&bs);
4143:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4144:   } else {
4145:     xglob = x;
4146:   }
4147:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4148:   if (size > 1) {
4149:     VecDestroy(&xglob);
4150:     VecRestoreArrayRead(x,&xarray);
4151:   }
4152:   VecDestroy(&x);
4153:   return(0);
4154: }

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

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: advanced

4170:   Notes:
4171:   Use DMGetLocalSection() in new code.

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

4175: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4176: @*/
4177: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4178: {

4182:   DMGetLocalSection(dm,section);
4183:   return(0);
4184: }

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

4189:   Input Parameter:
4190: . dm - The DM

4192:   Output Parameter:
4193: . section - The PetscSection

4195:   Options Database Keys:
4196: . -dm_petscsection_view - View the Section created by the DM

4198:   Level: intermediate

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

4202: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4203: @*/
4204: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4205: {

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

4214:     if (dm->setfromoptionscalled) {
4215:       PetscObject       obj = (PetscObject) dm;
4216:       PetscViewer       viewer;
4217:       PetscViewerFormat format;
4218:       PetscBool         flg;

4220:       PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4221:       if (flg) {PetscViewerPushFormat(viewer, format);}
4222:       for (d = 0; d < dm->Nds; ++d) {
4223:         PetscDSSetFromOptions(dm->probs[d].ds);
4224:         if (flg) {PetscDSView(dm->probs[d].ds, viewer);}
4225:       }
4226:       if (flg) {
4227:         PetscViewerFlush(viewer);
4228:         PetscViewerPopFormat(viewer);
4229:         PetscViewerDestroy(&viewer);
4230:       }
4231:     }
4232:     (*dm->ops->createlocalsection)(dm);
4233:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4234:   }
4235:   *section = dm->localSection;
4236:   return(0);
4237: }

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

4242:   Input Parameters:
4243: + dm - The DM
4244: - section - The PetscSection

4246:   Level: advanced

4248:   Notes:
4249:   Use DMSetLocalSection() in new code.

4251:   Any existing Section will be destroyed

4253: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4254: @*/
4255: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4256: {

4260:   DMSetLocalSection(dm,section);
4261:   return(0);
4262: }

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

4267:   Input Parameters:
4268: + dm - The DM
4269: - section - The PetscSection

4271:   Level: intermediate

4273:   Note: Any existing Section will be destroyed

4275: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4276: @*/
4277: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4278: {
4279:   PetscInt       numFields = 0;
4280:   PetscInt       f;

4286:   PetscObjectReference((PetscObject)section);
4287:   PetscSectionDestroy(&dm->localSection);
4288:   dm->localSection = section;
4289:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4290:   if (numFields) {
4291:     DMSetNumFields(dm, numFields);
4292:     for (f = 0; f < numFields; ++f) {
4293:       PetscObject disc;
4294:       const char *name;

4296:       PetscSectionGetFieldName(dm->localSection, f, &name);
4297:       DMGetField(dm, f, NULL, &disc);
4298:       PetscObjectSetName(disc, name);
4299:     }
4300:   }
4301:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4302:   PetscSectionDestroy(&dm->globalSection);
4303:   return(0);
4304: }

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

4309:   not collective

4311:   Input Parameter:
4312: . dm - The DM

4314:   Output Parameters:
4315: + 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.
4316: - 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.

4318:   Level: advanced

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

4322: .seealso: DMSetDefaultConstraints()
4323: @*/
4324: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4325: {

4330:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4331:   if (section) {*section = dm->defaultConstraintSection;}
4332:   if (mat) {*mat = dm->defaultConstraintMat;}
4333:   return(0);
4334: }

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

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

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

4343:   collective on dm

4345:   Input Parameters:
4346: + dm - The DM
4347: + 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).
4348: - 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).

4350:   Level: advanced

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

4354: .seealso: DMGetDefaultConstraints()
4355: @*/
4356: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4357: {
4358:   PetscMPIInt result;

4363:   if (section) {
4365:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4366:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4367:   }
4368:   if (mat) {
4370:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4371:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4372:   }
4373:   PetscObjectReference((PetscObject)section);
4374:   PetscSectionDestroy(&dm->defaultConstraintSection);
4375:   dm->defaultConstraintSection = section;
4376:   PetscObjectReference((PetscObject)mat);
4377:   MatDestroy(&dm->defaultConstraintMat);
4378:   dm->defaultConstraintMat = mat;
4379:   return(0);
4380: }

4382: #if defined(PETSC_USE_DEBUG)
4383: /*
4384:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4386:   Input Parameters:
4387: + dm - The DM
4388: . localSection - PetscSection describing the local data layout
4389: - globalSection - PetscSection describing the global data layout

4391:   Level: intermediate

4393: .seealso: DMGetSectionSF(), DMSetSectionSF()
4394: */
4395: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4396: {
4397:   MPI_Comm        comm;
4398:   PetscLayout     layout;
4399:   const PetscInt *ranges;
4400:   PetscInt        pStart, pEnd, p, nroots;
4401:   PetscMPIInt     size, rank;
4402:   PetscBool       valid = PETSC_TRUE, gvalid;
4403:   PetscErrorCode  ierr;

4406:   PetscObjectGetComm((PetscObject)dm,&comm);
4408:   MPI_Comm_size(comm, &size);
4409:   MPI_Comm_rank(comm, &rank);
4410:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4411:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4412:   PetscLayoutCreate(comm, &layout);
4413:   PetscLayoutSetBlockSize(layout, 1);
4414:   PetscLayoutSetLocalSize(layout, nroots);
4415:   PetscLayoutSetUp(layout);
4416:   PetscLayoutGetRanges(layout, &ranges);
4417:   for (p = pStart; p < pEnd; ++p) {
4418:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4420:     PetscSectionGetDof(localSection, p, &dof);
4421:     PetscSectionGetOffset(localSection, p, &off);
4422:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4423:     PetscSectionGetDof(globalSection, p, &gdof);
4424:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4425:     PetscSectionGetOffset(globalSection, p, &goff);
4426:     if (!gdof) continue; /* Censored point */
4427:     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;}
4428:     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;}
4429:     if (gdof < 0) {
4430:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4431:       for (d = 0; d < gsize; ++d) {
4432:         PetscInt offset = -(goff+1) + d, r;

4434:         PetscFindInt(offset,size+1,ranges,&r);
4435:         if (r < 0) r = -(r+2);
4436:         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;}
4437:       }
4438:     }
4439:   }
4440:   PetscLayoutDestroy(&layout);
4441:   PetscSynchronizedFlush(comm, NULL);
4442:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4443:   if (!gvalid) {
4444:     DMView(dm, NULL);
4445:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4446:   }
4447:   return(0);
4448: }
4449: #endif

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

4454:   Collective on dm

4456:   Input Parameter:
4457: . dm - The DM

4459:   Output Parameter:
4460: . section - The PetscSection

4462:   Level: intermediate

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

4466: .seealso: DMSetLocalSection(), DMGetLocalSection()
4467: @*/
4468: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4469: {

4475:   if (!dm->globalSection) {
4476:     PetscSection s;

4478:     DMGetLocalSection(dm, &s);
4479:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4480:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4481:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4482:     PetscLayoutDestroy(&dm->map);
4483:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4484:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4485:   }
4486:   *section = dm->globalSection;
4487:   return(0);
4488: }

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

4493:   Input Parameters:
4494: + dm - The DM
4495: - section - The PetscSection, or NULL

4497:   Level: intermediate

4499:   Note: Any existing Section will be destroyed

4501: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4502: @*/
4503: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4504: {

4510:   PetscObjectReference((PetscObject)section);
4511:   PetscSectionDestroy(&dm->globalSection);
4512:   dm->globalSection = section;
4513: #if defined(PETSC_USE_DEBUG)
4514:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4515: #endif
4516:   return(0);
4517: }

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

4523:   Input Parameter:
4524: . dm - The DM

4526:   Output Parameter:
4527: . sf - The PetscSF

4529:   Level: intermediate

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

4533: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4534: @*/
4535: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4536: {
4537:   PetscInt       nroots;

4543:   if (!dm->sectionSF) {
4544:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4545:   }
4546:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4547:   if (nroots < 0) {
4548:     PetscSection section, gSection;

4550:     DMGetLocalSection(dm, &section);
4551:     if (section) {
4552:       DMGetGlobalSection(dm, &gSection);
4553:       DMCreateSectionSF(dm, section, gSection);
4554:     } else {
4555:       *sf = NULL;
4556:       return(0);
4557:     }
4558:   }
4559:   *sf = dm->sectionSF;
4560:   return(0);
4561: }

4563: /*@
4564:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4566:   Input Parameters:
4567: + dm - The DM
4568: - sf - The PetscSF

4570:   Level: intermediate

4572:   Note: Any previous SF is destroyed

4574: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4575: @*/
4576: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4577: {

4583:   PetscObjectReference((PetscObject) sf);
4584:   PetscSFDestroy(&dm->sectionSF);
4585:   dm->sectionSF = sf;
4586:   return(0);
4587: }

4589: /*@C
4590:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4591:   describing the data layout.

4593:   Input Parameters:
4594: + dm - The DM
4595: . localSection - PetscSection describing the local data layout
4596: - globalSection - PetscSection describing the global data layout

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

4600:   Level: developer

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

4606: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4607: @*/
4608: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4609: {

4614:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4615:   return(0);
4616: }

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

4621:   Input Parameter:
4622: . dm - The DM

4624:   Output Parameter:
4625: . sf - The PetscSF

4627:   Level: intermediate

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

4631: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4632: @*/
4633: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4634: {
4638:   *sf = dm->sf;
4639:   return(0);
4640: }

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

4645:   Input Parameters:
4646: + dm - The DM
4647: - sf - The PetscSF

4649:   Level: intermediate

4651: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4652: @*/
4653: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4654: {

4660:   PetscObjectReference((PetscObject) sf);
4661:   PetscSFDestroy(&dm->sf);
4662:   dm->sf = sf;
4663:   return(0);
4664: }

4666: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4667: {
4668:   PetscClassId   id;

4672:   PetscObjectGetClassId(disc, &id);
4673:   if (id == PETSCFE_CLASSID) {
4674:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4675:   } else if (id == PETSCFV_CLASSID) {
4676:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4677:   } else {
4678:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4679:   }
4680:   return(0);
4681: }

4683: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4684: {
4685:   RegionField   *tmpr;
4686:   PetscInt       Nf = dm->Nf, f;

4690:   if (Nf >= NfNew) return(0);
4691:   PetscMalloc1(NfNew, &tmpr);
4692:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4693:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4694:   PetscFree(dm->fields);
4695:   dm->Nf     = NfNew;
4696:   dm->fields = tmpr;
4697:   return(0);
4698: }

4700: /*@
4701:   DMClearFields - Remove all fields from the DM

4703:   Logically collective on dm

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

4708:   Level: intermediate

4710: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4711: @*/
4712: PetscErrorCode DMClearFields(DM dm)
4713: {
4714:   PetscInt       f;

4719:   for (f = 0; f < dm->Nf; ++f) {
4720:     PetscObjectDestroy(&dm->fields[f].disc);
4721:     DMLabelDestroy(&dm->fields[f].label);
4722:   }
4723:   PetscFree(dm->fields);
4724:   dm->fields = NULL;
4725:   dm->Nf     = 0;
4726:   return(0);
4727: }

4729: /*@
4730:   DMGetNumFields - Get the number of fields in the DM

4732:   Not collective

4734:   Input Parameter:
4735: . dm - The DM

4737:   Output Parameter:
4738: . Nf - The number of fields

4740:   Level: intermediate

4742: .seealso: DMSetNumFields(), DMSetField()
4743: @*/
4744: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4745: {
4749:   *numFields = dm->Nf;
4750:   return(0);
4751: }

4753: /*@
4754:   DMSetNumFields - Set the number of fields in the DM

4756:   Logically collective on dm

4758:   Input Parameters:
4759: + dm - The DM
4760: - Nf - The number of fields

4762:   Level: intermediate

4764: .seealso: DMGetNumFields(), DMSetField()
4765: @*/
4766: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4767: {
4768:   PetscInt       Nf, f;

4773:   DMGetNumFields(dm, &Nf);
4774:   for (f = Nf; f < numFields; ++f) {
4775:     PetscContainer obj;

4777:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4778:     DMAddField(dm, NULL, (PetscObject) obj);
4779:     PetscContainerDestroy(&obj);
4780:   }
4781:   return(0);
4782: }

4784: /*@
4785:   DMGetField - Return the discretization object for a given DM field

4787:   Not collective

4789:   Input Parameters:
4790: + dm - The DM
4791: - f  - The field number

4793:   Output Parameters:
4794: + label - The label indicating the support of the field, or NULL for the entire mesh
4795: - field - The discretization object

4797:   Level: intermediate

4799: .seealso: DMAddField(), DMSetField()
4800: @*/
4801: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4802: {
4806:   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);
4807:   if (label) *label = dm->fields[f].label;
4808:   if (field) *field = dm->fields[f].disc;
4809:   return(0);
4810: }

4812: /* Does not clear the DS */
4813: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4814: {

4818:   DMFieldEnlarge_Static(dm, f+1);
4819:   DMLabelDestroy(&dm->fields[f].label);
4820:   PetscObjectDestroy(&dm->fields[f].disc);
4821:   dm->fields[f].label = label;
4822:   dm->fields[f].disc  = field;
4823:   PetscObjectReference((PetscObject) label);
4824:   PetscObjectReference((PetscObject) field);
4825:   return(0);
4826: }

4828: /*@
4829:   DMSetField - Set the discretization object for a given DM field

4831:   Logically collective on dm

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

4839:   Level: intermediate

4841: .seealso: DMAddField(), DMGetField()
4842: @*/
4843: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4844: {

4851:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4852:   DMSetField_Internal(dm, f, label, field);
4853:   DMSetDefaultAdjacency_Private(dm, f, field);
4854:   DMClearDS(dm);
4855:   return(0);
4856: }

4858: /*@
4859:   DMAddField - Add the discretization object for the given DM field

4861:   Logically collective on dm

4863:   Input Parameters:
4864: + dm    - The DM
4865: . label - The label indicating the support of the field, or NULL for the entire mesh
4866: - field - The discretization object

4868:   Level: intermediate

4870: .seealso: DMSetField(), DMGetField()
4871: @*/
4872: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4873: {
4874:   PetscInt       Nf = dm->Nf;

4881:   DMFieldEnlarge_Static(dm, Nf+1);
4882:   dm->fields[Nf].label = label;
4883:   dm->fields[Nf].disc  = field;
4884:   PetscObjectReference((PetscObject) label);
4885:   PetscObjectReference((PetscObject) field);
4886:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4887:   DMClearDS(dm);
4888:   return(0);
4889: }

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

4894:   Logically collective on dm

4896:   Input Parameters:
4897: + dm          - The DM
4898: . f           - The field index
4899: - avoidTensor - The flag to avoid defining the field on tensor cells

4901:   Level: intermediate

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

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

4916:   Logically collective on dm

4918:   Input Parameters:
4919: + dm          - The DM
4920: - f           - The field index

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

4925:   Level: intermediate

4927: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4928: @*/
4929: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4930: {
4932:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4933:   *avoidTensor = dm->fields[f].avoidTensor;
4934:   return(0);
4935: }

4937: /*@
4938:   DMCopyFields - Copy the discretizations for the DM into another DM

4940:   Collective on dm

4942:   Input Parameter:
4943: . dm - The DM

4945:   Output Parameter:
4946: . newdm - The DM

4948:   Level: advanced

4950: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4951: @*/
4952: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4953: {
4954:   PetscInt       Nf, f;

4958:   if (dm == newdm) return(0);
4959:   DMGetNumFields(dm, &Nf);
4960:   DMClearFields(newdm);
4961:   for (f = 0; f < Nf; ++f) {
4962:     DMLabel     label;
4963:     PetscObject field;
4964:     PetscBool   useCone, useClosure;

4966:     DMGetField(dm, f, &label, &field);
4967:     DMSetField(newdm, f, label, field);
4968:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4969:     DMSetAdjacency(newdm, f, useCone, useClosure);
4970:   }
4971:   return(0);
4972: }

4974: /*@
4975:   DMGetAdjacency - Returns the flags for determining variable influence

4977:   Not collective

4979:   Input Parameters:
4980: + dm - The DM object
4981: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4983:   Output Parameters:
4984: + useCone    - Flag for variable influence starting with the cone operation
4985: - useClosure - Flag for variable influence using transitive closure

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

4993:   Level: developer

4995: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4996: @*/
4997: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4998: {
5003:   if (f < 0) {
5004:     if (useCone)    *useCone    = dm->adjacency[0];
5005:     if (useClosure) *useClosure = dm->adjacency[1];
5006:   } else {
5007:     PetscInt       Nf;

5010:     DMGetNumFields(dm, &Nf);
5011:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5012:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
5013:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5014:   }
5015:   return(0);
5016: }

5018: /*@
5019:   DMSetAdjacency - Set the flags for determining variable influence

5021:   Not collective

5023:   Input Parameters:
5024: + dm         - The DM object
5025: . f          - The field number
5026: . useCone    - Flag for variable influence starting with the cone operation
5027: - useClosure - Flag for variable influence using transitive closure

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

5035:   Level: developer

5037: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
5038: @*/
5039: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5040: {
5043:   if (f < 0) {
5044:     dm->adjacency[0] = useCone;
5045:     dm->adjacency[1] = useClosure;
5046:   } else {
5047:     PetscInt       Nf;

5050:     DMGetNumFields(dm, &Nf);
5051:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5052:     dm->fields[f].adjacency[0] = useCone;
5053:     dm->fields[f].adjacency[1] = useClosure;
5054:   }
5055:   return(0);
5056: }

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

5061:   Not collective

5063:   Input Parameter:
5064: . dm - The DM object

5066:   Output Parameters:
5067: + useCone    - Flag for variable influence starting with the cone operation
5068: - useClosure - Flag for variable influence using transitive closure

5070:   Notes:
5071: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5072: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5073: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5075:   Level: developer

5077: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5078: @*/
5079: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5080: {
5081:   PetscInt       Nf;

5088:   DMGetNumFields(dm, &Nf);
5089:   if (!Nf) {
5090:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5091:   } else {
5092:     DMGetAdjacency(dm, 0, useCone, useClosure);
5093:   }
5094:   return(0);
5095: }

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

5100:   Not collective

5102:   Input Parameters:
5103: + dm         - The DM object
5104: . useCone    - Flag for variable influence starting with the cone operation
5105: - useClosure - Flag for variable influence using transitive closure

5107:   Notes:
5108: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5109: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5110: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5112:   Level: developer

5114: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5115: @*/
5116: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5117: {
5118:   PetscInt       Nf;

5123:   DMGetNumFields(dm, &Nf);
5124:   if (!Nf) {
5125:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5126:   } else {
5127:     DMSetAdjacency(dm, 0, useCone, useClosure);
5128:   }
5129:   return(0);
5130: }

5132: /* Complete labels that are being used for FEM BC */
5133: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
5134: {
5135:   PetscObject    obj;
5136:   PetscClassId   id;
5137:   PetscInt       Nbd, bd;
5138:   PetscBool      isFE      = PETSC_FALSE;
5139:   PetscBool      duplicate = PETSC_FALSE;

5143:   DMGetField(dm, field, NULL, &obj);
5144:   PetscObjectGetClassId(obj, &id);
5145:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5146:   if (isFE && label) {
5147:     /* Only want to modify label once */
5148:     PetscDSGetNumBoundary(ds, &Nbd);
5149:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5150:       DMLabel l;

5152:       PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5153:       duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
5154:       if (duplicate) break;
5155:     }
5156:     if (!duplicate) {
5157:       DM plex;

5159:       DMConvert(dm, DMPLEX, &plex);
5160:       if (plex) {DMPlexLabelComplete(plex, label);}
5161:       DMDestroy(&plex);
5162:     }
5163:   }
5164:   return(0);
5165: }

5167: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5168: {
5169:   DMSpace       *tmpd;
5170:   PetscInt       Nds = dm->Nds, s;

5174:   if (Nds >= NdsNew) return(0);
5175:   PetscMalloc1(NdsNew, &tmpd);
5176:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5177:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5178:   PetscFree(dm->probs);
5179:   dm->Nds   = NdsNew;
5180:   dm->probs = tmpd;
5181:   return(0);
5182: }

5184: /*@
5185:   DMGetNumDS - Get the number of discrete systems in the DM

5187:   Not collective

5189:   Input Parameter:
5190: . dm - The DM

5192:   Output Parameter:
5193: . Nds - The number of PetscDS objects

5195:   Level: intermediate

5197: .seealso: DMGetDS(), DMGetCellDS()
5198: @*/
5199: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5200: {
5204:   *Nds = dm->Nds;
5205:   return(0);
5206: }

5208: /*@
5209:   DMClearDS - Remove all discrete systems from the DM

5211:   Logically collective on dm

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

5216:   Level: intermediate

5218: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5219: @*/
5220: PetscErrorCode DMClearDS(DM dm)
5221: {
5222:   PetscInt       s;

5227:   for (s = 0; s < dm->Nds; ++s) {
5228:     PetscDSDestroy(&dm->probs[s].ds);
5229:     DMLabelDestroy(&dm->probs[s].label);
5230:     ISDestroy(&dm->probs[s].fields);
5231:   }
5232:   PetscFree(dm->probs);
5233:   dm->probs = NULL;
5234:   dm->Nds   = 0;
5235:   return(0);
5236: }

5238: /*@
5239:   DMGetDS - Get the default PetscDS

5241:   Not collective

5243:   Input Parameter:
5244: . dm    - The DM

5246:   Output Parameter:
5247: . prob - The default PetscDS

5249:   Level: intermediate

5251: .seealso: DMGetCellDS(), DMGetRegionDS()
5252: @*/
5253: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5254: {

5260:   if (dm->Nds <= 0) {
5261:     PetscDS ds;

5263:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5264:     DMSetRegionDS(dm, NULL, NULL, ds);
5265:     PetscDSDestroy(&ds);
5266:   }
5267:   *prob = dm->probs[0].ds;
5268:   return(0);
5269: }

5271: /*@
5272:   DMGetCellDS - Get the PetscDS defined on a given cell

5274:   Not collective

5276:   Input Parameters:
5277: + dm    - The DM
5278: - point - Cell for the DS

5280:   Output Parameter:
5281: . prob - The PetscDS defined on the given cell

5283:   Level: developer

5285: .seealso: DMGetDS(), DMSetRegionDS()
5286: @*/
5287: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5288: {
5289:   PetscDS        probDef = NULL;
5290:   PetscInt       s;

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

5301:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5302:     else {
5303:       DMLabelGetValue(dm->probs[s].label, point, &val);
5304:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5305:     }
5306:   }
5307:   if (!*prob) *prob = probDef;
5308:   return(0);
5309: }

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

5314:   Not collective

5316:   Input Parameters:
5317: + dm    - The DM
5318: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5326:   Level: advanced

5328: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5329: @*/
5330: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5331: {
5332:   PetscInt Nds = dm->Nds, s;

5339:   for (s = 0; s < Nds; ++s) {
5340:     if (dm->probs[s].label == label) {
5341:       if (fields) *fields = dm->probs[s].fields;
5342:       if (ds)     *ds     = dm->probs[s].ds;
5343:       return(0);
5344:     }
5345:   }
5346:   return(0);
5347: }

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

5352:   Collective on dm

5354:   Input Parameters:
5355: + dm     - The DM
5356: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5357: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5358: - prob   - The PetscDS defined on the given cell

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

5363:   Level: advanced

5365: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5366: @*/
5367: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5368: {
5369:   PetscInt       Nds = dm->Nds, s;

5376:   for (s = 0; s < Nds; ++s) {
5377:     if (dm->probs[s].label == label) {
5378:       PetscDSDestroy(&dm->probs[s].ds);
5379:       dm->probs[s].ds = ds;
5380:       return(0);
5381:     }
5382:   }
5383:   DMDSEnlarge_Static(dm, Nds+1);
5384:   PetscObjectReference((PetscObject) label);
5385:   PetscObjectReference((PetscObject) fields);
5386:   PetscObjectReference((PetscObject) ds);
5387:   if (!label) {
5388:     /* Put the NULL label at the front, so it is returned as the default */
5389:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5390:     Nds = 0;
5391:   }
5392:   dm->probs[Nds].label  = label;
5393:   dm->probs[Nds].fields = fields;
5394:   dm->probs[Nds].ds     = ds;
5395:   return(0);
5396: }

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

5401:   Not collective

5403:   Input Parameters:
5404: + dm  - The DM
5405: - num - The region number, in [0, Nds)

5407:   Output Parameters:
5408: + label  - The region label, or NULL
5409: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5410: - ds     - The PetscDS defined on the given region, or NULL

5412:   Level: advanced

5414: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5415: @*/
5416: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5417: {
5418:   PetscInt       Nds;

5423:   DMGetNumDS(dm, &Nds);
5424:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5425:   if (label) {
5427:     *label = dm->probs[num].label;
5428:   }
5429:   if (fields) {
5431:     *fields = dm->probs[num].fields;
5432:   }
5433:   if (ds) {
5435:     *ds = dm->probs[num].ds;
5436:   }
5437:   return(0);
5438: }

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

5443:   Not collective

5445:   Input Parameters:
5446: + dm     - The DM
5447: . num    - The region number, in [0, Nds)
5448: . label  - The region label, or NULL
5449: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5450: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5452:   Level: advanced

5454: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5455: @*/
5456: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5457: {
5458:   PetscInt       Nds;

5464:   DMGetNumDS(dm, &Nds);
5465:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5466:   PetscObjectReference((PetscObject) label);
5467:   DMLabelDestroy(&dm->probs[num].label);
5468:   dm->probs[num].label = label;
5469:   if (fields) {
5471:     PetscObjectReference((PetscObject) fields);
5472:     ISDestroy(&dm->probs[num].fields);
5473:     dm->probs[num].fields = fields;
5474:   }
5475:   if (ds) {
5477:     PetscObjectReference((PetscObject) ds);
5478:     PetscDSDestroy(&dm->probs[num].ds);
5479:     dm->probs[num].ds = ds;
5480:   }
5481:   return(0);
5482: }

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

5487:   Not collective

5489:   Input Parameters:
5490: + dm  - The DM
5491: - ds  - The PetscDS defined on the given region

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

5496:   Level: advanced

5498: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5499: @*/
5500: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5501: {
5502:   PetscInt       Nds, n;

5509:   DMGetNumDS(dm, &Nds);
5510:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5511:   if (n >= Nds) *num = -1;
5512:   else          *num = n;
5513:   return(0);
5514: }

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

5519:   Collective on dm

5521:   Input Parameter:
5522: . dm - The DM

5524:   Options Database Keys:
5525: . -dm_petscds_view - View all the PetscDS objects in this DM

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

5529:   Level: intermediate

5531: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5532: @*/
5533: PetscErrorCode DMCreateDS(DM dm)
5534: {
5535:   MPI_Comm       comm;
5536:   PetscDS        dsDef;
5537:   DMLabel       *labelSet;
5538:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5539:   PetscBool      doSetup = PETSC_TRUE, flg;

5544:   if (!dm->fields) return(0);
5545:   PetscObjectGetComm((PetscObject) dm, &comm);
5546:   DMGetCoordinateDim(dm, &dE);
5547:   /* Determine how many regions we have */
5548:   PetscMalloc1(Nf, &labelSet);
5549:   Nl   = 0;
5550:   Ndef = 0;
5551:   for (f = 0; f < Nf; ++f) {
5552:     DMLabel  label = dm->fields[f].label;
5553:     PetscInt l;

5555: #ifdef PETSC_HAVE_LIBCEED
5556:     /* Move CEED context to discretizations */
5557:     {
5558:       PetscClassId id;

5560:       PetscObjectGetClassId(dm->fields[f].disc, &id);
5561:       if (id == PETSCFE_CLASSID) {
5562:         Ceed ceed;

5564:         DMGetCeed(dm, &ceed);
5565:         PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
5566:       }
5567:     }
5568: #endif
5569:     if (!label) {++Ndef; continue;}
5570:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5571:     if (l < Nl) continue;
5572:     labelSet[Nl++] = label;
5573:   }
5574:   /* Create default DS if there are no labels to intersect with */
5575:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5576:   if (!dsDef && Ndef && !Nl) {
5577:     IS        fields;
5578:     PetscInt *fld, nf;

5580:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5581:     if (nf) {
5582:       PetscMalloc1(nf, &fld);
5583:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5584:       ISCreate(PETSC_COMM_SELF, &fields);
5585:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5586:       ISSetType(fields, ISGENERAL);
5587:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5589:       PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5590:       DMSetRegionDS(dm, NULL, fields, dsDef);
5591:       PetscDSDestroy(&dsDef);
5592:       ISDestroy(&fields);
5593:     }
5594:   }
5595:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5596:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5597:   /* Intersect labels with default fields */
5598:   if (Ndef && Nl) {
5599:     DM              plex;
5600:     DMLabel         cellLabel;
5601:     IS              fieldIS, allcellIS, defcellIS = NULL;
5602:     PetscInt       *fields;
5603:     const PetscInt *cells;
5604:     PetscInt        depth, nf = 0, n, c;

5606:     DMConvert(dm, DMPLEX, &plex);
5607:     DMPlexGetDepth(plex, &depth);
5608:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5609:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5610:     for (l = 0; l < Nl; ++l) {
5611:       DMLabel label = labelSet[l];
5612:       IS      pointIS;

5614:       ISDestroy(&defcellIS);
5615:       DMLabelGetStratumIS(label, 1, &pointIS);
5616:       ISDifference(allcellIS, pointIS, &defcellIS);
5617:       ISDestroy(&pointIS);
5618:     }
5619:     ISDestroy(&allcellIS);

5621:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5622:     ISGetLocalSize(defcellIS, &n);
5623:     ISGetIndices(defcellIS, &cells);
5624:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5625:     ISRestoreIndices(defcellIS, &cells);
5626:     ISDestroy(&defcellIS);
5627:     DMPlexLabelComplete(plex, cellLabel);

5629:     PetscMalloc1(Ndef, &fields);
5630:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5631:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5632:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5633:     ISSetType(fieldIS, ISGENERAL);
5634:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5636:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5637:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5638:     DMLabelDestroy(&cellLabel);
5639:     PetscDSSetCoordinateDimension(dsDef, dE);
5640:     PetscDSDestroy(&dsDef);
5641:     ISDestroy(&fieldIS);
5642:     DMDestroy(&plex);
5643:   }
5644:   /* Create label DSes
5645:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5646:   */
5647:   /* TODO Should check that labels are disjoint */
5648:   for (l = 0; l < Nl; ++l) {
5649:     DMLabel   label = labelSet[l];
5650:     PetscDS   ds;
5651:     IS        fields;
5652:     PetscInt *fld, nf;

5654:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5655:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5656:     PetscMalloc1(nf, &fld);
5657:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5658:     ISCreate(PETSC_COMM_SELF, &fields);
5659:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5660:     ISSetType(fields, ISGENERAL);
5661:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5662:     DMSetRegionDS(dm, label, fields, ds);
5663:     ISDestroy(&fields);
5664:     PetscDSSetCoordinateDimension(ds, dE);
5665:     {
5666:       DMPolytopeType ct;
5667:       PetscInt       lStart, lEnd;
5668:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5670:       DMLabelGetBounds(label, &lStart, &lEnd);
5671:       if (lStart >= 0) {
5672:         DMPlexGetCellType(dm, lStart, &ct);
5673:         switch (ct) {
5674:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5675:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5676:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5677:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5678:             isHybridLocal = PETSC_TRUE;break;
5679:           default: break;
5680:         }
5681:       }
5682:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5683:       PetscDSSetHybrid(ds, isHybrid);
5684:     }
5685:     PetscDSDestroy(&ds);
5686:   }
5687:   PetscFree(labelSet);
5688:   /* Set fields in DSes */
5689:   for (s = 0; s < dm->Nds; ++s) {
5690:     PetscDS         ds     = dm->probs[s].ds;
5691:     IS              fields = dm->probs[s].fields;
5692:     const PetscInt *fld;
5693:     PetscInt        nf;

5695:     ISGetLocalSize(fields, &nf);
5696:     ISGetIndices(fields, &fld);
5697:     for (f = 0; f < nf; ++f) {
5698:       PetscObject  disc  = dm->fields[fld[f]].disc;
5699:       PetscBool    isHybrid;
5700:       PetscClassId id;

5702:       PetscDSGetHybrid(ds, &isHybrid);
5703:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5704:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5705:       PetscDSSetDiscretization(ds, f, disc);
5706:       /* We allow people to have placeholder fields and construct the Section by hand */
5707:       PetscObjectGetClassId(disc, &id);
5708:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5709:     }
5710:     ISRestoreIndices(fields, &fld);
5711:   }
5712:   /* Allow k-jet tabulation */
5713:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5714:   if (flg) {
5715:     for (s = 0; s < dm->Nds; ++s) {
5716:       PetscDS  ds = dm->probs[s].ds;
5717:       PetscInt Nf, f;

5719:       PetscDSGetNumFields(ds, &Nf);
5720:       for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5721:     }
5722:   }
5723:   /* Setup DSes */
5724:   if (doSetup) {
5725:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5726:   }
5727:   return(0);
5728: }

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

5733:   Collective on DM

5735:   Input Parameters:
5736: + dm   - The DM
5737: - time - The time

5739:   Output Parameters:
5740: + u    - The vector will be filled with exact solution values, or NULL
5741: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5743:   Note: The user must call PetscDSSetExactSolution() beforehand

5745:   Level: developer

5747: .seealso: PetscDSSetExactSolution()
5748: @*/
5749: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5750: {
5751:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5752:   void            **ectxs;
5753:   PetscInt          Nf, Nds, s;
5754:   PetscErrorCode    ierr;

5760:   DMGetNumFields(dm, &Nf);
5761:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5762:   DMGetNumDS(dm, &Nds);
5763:   for (s = 0; s < Nds; ++s) {
5764:     PetscDS         ds;
5765:     DMLabel         label;
5766:     IS              fieldIS;
5767:     const PetscInt *fields, id = 1;
5768:     PetscInt        dsNf, f;

5770:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5771:     PetscDSGetNumFields(ds, &dsNf);
5772:     ISGetIndices(fieldIS, &fields);
5773:     PetscArrayzero(exacts, Nf);
5774:     PetscArrayzero(ectxs, Nf);
5775:     if (u) {
5776:       for (f = 0; f < dsNf; ++f) {
5777:         const PetscInt field = fields[f];
5778:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5779:       }
5780:       ISRestoreIndices(fieldIS, &fields);
5781:       if (label) {
5782:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5783:       } else {
5784:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5785:       }
5786:     }
5787:     if (u_t) {
5788:       PetscArrayzero(exacts, Nf);
5789:       PetscArrayzero(ectxs, Nf);
5790:       for (f = 0; f < dsNf; ++f) {
5791:         const PetscInt field = fields[f];
5792:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5793:       }
5794:       ISRestoreIndices(fieldIS, &fields);
5795:       if (label) {
5796:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5797:       } else {
5798:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5799:       }
5800:     }
5801:   }
5802:   if (u) {
5803:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5804:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5805:   }
5806:   if (u_t) {
5807:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5808:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5809:   }
5810:   PetscFree2(exacts, ectxs);
5811:   return(0);
5812: }

5814: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5815: {
5816:   PetscDS        dsNew;
5817:   DSBoundary     b;
5818:   PetscInt       cdim, Nf, f;
5819:   PetscBool      isHybrid;
5820:   void          *ctx;

5824:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5825:   PetscDSCopyConstants(ds, dsNew);
5826:   PetscDSCopyExactSolutions(ds, dsNew);
5827:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5828:   PetscDSCopyEquations(ds, dsNew);
5829:   PetscDSGetNumFields(ds, &Nf);
5830:   for (f = 0; f < Nf; ++f) {
5831:     PetscDSGetContext(ds, f, &ctx);
5832:     PetscDSSetContext(dsNew, f, ctx);
5833:   }
5834:   if (Nf) {
5835:     PetscDSGetCoordinateDimension(ds, &cdim);
5836:     PetscDSSetCoordinateDimension(dsNew, cdim);
5837:   }
5838:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5839:   for (b = dsNew->boundary; b; b = b->next) {
5840:     DMGetLabel(dm, b->lname, &b->label);
5841:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5842:     //if (!b->label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
5843:   }
5844:   PetscDSGetHybrid(ds, &isHybrid);
5845:   PetscDSSetHybrid(dsNew, isHybrid);

5847:   DMSetRegionDS(dm, label, fields, dsNew);
5848:   PetscDSDestroy(&dsNew);
5849:   return(0);
5850: }

5852: /*@
5853:   DMCopyDS - Copy the discrete systems for the DM into another DM

5855:   Collective on dm

5857:   Input Parameter:
5858: . dm - The DM

5860:   Output Parameter:
5861: . newdm - The DM

5863:   Level: advanced

5865: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5866: @*/
5867: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5868: {
5869:   PetscInt       Nds, s;

5873:   if (dm == newdm) return(0);
5874:   DMGetNumDS(dm, &Nds);
5875:   DMClearDS(newdm);
5876:   for (s = 0; s < Nds; ++s) {
5877:     DMLabel  label;
5878:     IS       fields;
5879:     PetscDS  ds, newds;
5880:     PetscInt Nbd, bd;

5882:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5883:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5884:     DMTransferDS_Internal(newdm, label, fields, ds);
5885:     /* Commplete new labels in the new DS */
5886:     DMGetRegionDS(newdm, label, NULL, &newds);
5887:     PetscDSGetNumBoundary(newds, &Nbd);
5888:     for (bd = 0; bd < Nbd; ++bd) {
5889:       PetscWeakForm wf;
5890:       DMLabel       label;
5891:       PetscInt      field;

5893:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5894:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5895:       PetscWeakFormReplaceLabel(wf, label);
5896:     }
5897:   }
5898:   return(0);
5899: }

5901: /*@
5902:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

5904:   Collective on dm

5906:   Input Parameter:
5907: . dm - The DM

5909:   Output Parameter:
5910: . newdm - The DM

5912:   Level: advanced

5914: .seealso: DMCopyFields(), DMCopyDS()
5915: @*/
5916: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5917: {

5921:   DMCopyFields(dm, newdm);
5922:   DMCopyDS(dm, newdm);
5923:   return(0);
5924: }

5926: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5927: {
5928:   DM dm_coord,dmc_coord;
5930:   Vec coords,ccoords;
5931:   Mat inject;
5933:   DMGetCoordinateDM(dm,&dm_coord);
5934:   DMGetCoordinateDM(dmc,&dmc_coord);
5935:   DMGetCoordinates(dm,&coords);
5936:   DMGetCoordinates(dmc,&ccoords);
5937:   if (coords && !ccoords) {
5938:     DMCreateGlobalVector(dmc_coord,&ccoords);
5939:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5940:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5941:     MatRestrict(inject,coords,ccoords);
5942:     MatDestroy(&inject);
5943:     DMSetCoordinates(dmc,ccoords);
5944:     VecDestroy(&ccoords);
5945:   }
5946:   return(0);
5947: }

5949: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5950: {
5951:   DM dm_coord,subdm_coord;
5953:   Vec coords,ccoords,clcoords;
5954:   VecScatter *scat_i,*scat_g;
5956:   DMGetCoordinateDM(dm,&dm_coord);
5957:   DMGetCoordinateDM(subdm,&subdm_coord);
5958:   DMGetCoordinates(dm,&coords);
5959:   DMGetCoordinates(subdm,&ccoords);
5960:   if (coords && !ccoords) {
5961:     DMCreateGlobalVector(subdm_coord,&ccoords);
5962:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5963:     DMCreateLocalVector(subdm_coord,&clcoords);
5964:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5965:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5966:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5967:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5968:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5969:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5970:     DMSetCoordinates(subdm,ccoords);
5971:     DMSetCoordinatesLocal(subdm,clcoords);
5972:     VecScatterDestroy(&scat_i[0]);
5973:     VecScatterDestroy(&scat_g[0]);
5974:     VecDestroy(&ccoords);
5975:     VecDestroy(&clcoords);
5976:     PetscFree(scat_i);
5977:     PetscFree(scat_g);
5978:   }
5979:   return(0);
5980: }

5982: /*@
5983:   DMGetDimension - Return the topological dimension of the DM

5985:   Not collective

5987:   Input Parameter:
5988: . dm - The DM

5990:   Output Parameter:
5991: . dim - The topological dimension

5993:   Level: beginner

5995: .seealso: DMSetDimension(), DMCreate()
5996: @*/
5997: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5998: {
6002:   *dim = dm->dim;
6003:   return(0);
6004: }

6006: /*@
6007:   DMSetDimension - Set the topological dimension of the DM

6009:   Collective on dm

6011:   Input Parameters:
6012: + dm - The DM
6013: - dim - The topological dimension

6015:   Level: beginner

6017: .seealso: DMGetDimension(), DMCreate()
6018: @*/
6019: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6020: {
6021:   PetscDS        ds;
6022:   PetscInt       Nds, n;

6028:   dm->dim = dim;
6029:   if (dm->dim >= 0) {
6030:     DMGetNumDS(dm, &Nds);
6031:     for (n = 0; n < Nds; ++n) {
6032:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6033:       if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
6034:     }
6035:   }
6036:   return(0);
6037: }

6039: /*@
6040:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

6042:   Collective on dm

6044:   Input Parameters:
6045: + dm - the DM
6046: - dim - the dimension

6048:   Output Parameters:
6049: + pStart - The first point of the given dimension
6050: - pEnd - The first point following points of the given dimension

6052:   Note:
6053:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6054:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6055:   then the interval is empty.

6057:   Level: intermediate

6059: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
6060: @*/
6061: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6062: {
6063:   PetscInt       d;

6068:   DMGetDimension(dm, &d);
6069:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
6070:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
6071:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
6072:   return(0);
6073: }

6075: /*@
6076:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

6078:   Collective on dm

6080:   Input Parameters:
6081: + dm - the DM
6082: - c - coordinate vector

6084:   Notes:
6085:   The coordinates do include those for ghost points, which are in the local vector.

6087:   The vector c should be destroyed by the caller.

6089:   Level: intermediate

6091: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6092: @*/
6093: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6094: {

6100:   PetscObjectReference((PetscObject) c);
6101:   VecDestroy(&dm->coordinates);
6102:   dm->coordinates = c;
6103:   VecDestroy(&dm->coordinatesLocal);
6104:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6105:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6106:   return(0);
6107: }

6109: /*@
6110:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

6112:   Not collective

6114:    Input Parameters:
6115: +  dm - the DM
6116: -  c - coordinate vector

6118:   Notes:
6119:   The coordinates of ghost points can be set using DMSetCoordinates()
6120:   followed by DMGetCoordinatesLocal(). This is intended to enable the
6121:   setting of ghost coordinates outside of the domain.

6123:   The vector c should be destroyed by the caller.

6125:   Level: intermediate

6127: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6128: @*/
6129: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6130: {

6136:   PetscObjectReference((PetscObject) c);
6137:   VecDestroy(&dm->coordinatesLocal);

6139:   dm->coordinatesLocal = c;

6141:   VecDestroy(&dm->coordinates);
6142:   return(0);
6143: }

6145: /*@
6146:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

6148:   Collective on dm

6150:   Input Parameter:
6151: . dm - the DM

6153:   Output Parameter:
6154: . c - global coordinate vector

6156:   Note:
6157:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6158:   destroyed the array will no longer be valid.

6160:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

6162:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6163:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6165:   Level: intermediate

6167: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6168: @*/
6169: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6170: {

6176:   if (!dm->coordinates && dm->coordinatesLocal) {
6177:     DM        cdm = NULL;
6178:     PetscBool localized;

6180:     DMGetCoordinateDM(dm, &cdm);
6181:     DMCreateGlobalVector(cdm, &dm->coordinates);
6182:     DMGetCoordinatesLocalized(dm, &localized);
6183:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6184:     if (localized) {
6185:       PetscInt cdim;

6187:       DMGetCoordinateDim(dm, &cdim);
6188:       VecSetBlockSize(dm->coordinates, cdim);
6189:     }
6190:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6191:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6192:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6193:   }
6194:   *c = dm->coordinates;
6195:   return(0);
6196: }

6198: /*@
6199:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

6201:   Collective on dm

6203:   Input Parameter:
6204: . dm - the DM

6206:   Level: advanced

6208: .seealso: DMGetCoordinatesLocalNoncollective()
6209: @*/
6210: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6211: {

6216:   if (!dm->coordinatesLocal && dm->coordinates) {
6217:     DM        cdm = NULL;
6218:     PetscBool localized;

6220:     DMGetCoordinateDM(dm, &cdm);
6221:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6222:     DMGetCoordinatesLocalized(dm, &localized);
6223:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6224:     if (localized) {
6225:       PetscInt cdim;

6227:       DMGetCoordinateDim(dm, &cdim);
6228:       VecSetBlockSize(dm->coordinates, cdim);
6229:     }
6230:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6231:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6232:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6233:   }
6234:   return(0);
6235: }

6237: /*@
6238:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

6240:   Collective on dm

6242:   Input Parameter:
6243: . dm - the DM

6245:   Output Parameter:
6246: . c - coordinate vector

6248:   Note:
6249:   This is a borrowed reference, so the user should NOT destroy this vector

6251:   Each process has the local and ghost coordinates

6253:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6254:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6256:   Level: intermediate

6258: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6259: @*/
6260: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6261: {

6267:   DMGetCoordinatesLocalSetUp(dm);
6268:   *c = dm->coordinatesLocal;
6269:   return(0);
6270: }

6272: /*@
6273:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6275:   Not collective

6277:   Input Parameter:
6278: . dm - the DM

6280:   Output Parameter:
6281: . c - coordinate vector

6283:   Level: advanced

6285: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6286: @*/
6287: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6288: {
6292:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6293:   *c = dm->coordinatesLocal;
6294:   return(0);
6295: }

6297: /*@
6298:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6300:   Not collective

6302:   Input Parameters:
6303: + dm - the DM
6304: - p - the IS of points whose coordinates will be returned

6306:   Output Parameters:
6307: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6308: - pCoord - the Vec with coordinates of points in p

6310:   Note:
6311:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6313:   This creates a new vector, so the user SHOULD destroy this vector

6315:   Each process has the local and ghost coordinates

6317:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6318:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6320:   Level: advanced

6322: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6323: @*/
6324: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6325: {
6326:   PetscSection        cs, newcs;
6327:   Vec                 coords;
6328:   const PetscScalar   *arr;
6329:   PetscScalar         *newarr=NULL;
6330:   PetscInt            n;
6331:   PetscErrorCode      ierr;

6338:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6339:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6340:   cs = dm->coordinateDM->localSection;
6341:   coords = dm->coordinatesLocal;
6342:   VecGetArrayRead(coords, &arr);
6343:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6344:   VecRestoreArrayRead(coords, &arr);
6345:   if (pCoord) {
6346:     PetscSectionGetStorageSize(newcs, &n);
6347:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6348:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6349:     VecReplaceArray(*pCoord, newarr);
6350:   } else {
6351:     PetscFree(newarr);
6352:   }
6353:   if (pCoordSection) {*pCoordSection = newcs;}
6354:   else               {PetscSectionDestroy(&newcs);}
6355:   return(0);
6356: }

6358: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6359: {

6365:   if (!dm->coordinateField) {
6366:     if (dm->ops->createcoordinatefield) {
6367:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6368:     }
6369:   }
6370:   *field = dm->coordinateField;
6371:   return(0);
6372: }

6374: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6375: {

6381:   PetscObjectReference((PetscObject)field);
6382:   DMFieldDestroy(&dm->coordinateField);
6383:   dm->coordinateField = field;
6384:   return(0);
6385: }

6387: /*@
6388:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

6390:   Collective on dm

6392:   Input Parameter:
6393: . dm - the DM

6395:   Output Parameter:
6396: . cdm - coordinate DM

6398:   Level: intermediate

6400: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6401: @*/
6402: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6403: {

6409:   if (!dm->coordinateDM) {
6410:     DM cdm;

6412:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6413:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6414:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6415:      * until the call to CreateCoordinateDM) */
6416:     DMDestroy(&dm->coordinateDM);
6417:     dm->coordinateDM = cdm;
6418:   }
6419:   *cdm = dm->coordinateDM;
6420:   return(0);
6421: }

6423: /*@
6424:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

6426:   Logically Collective on dm

6428:   Input Parameters:
6429: + dm - the DM
6430: - cdm - coordinate DM

6432:   Level: intermediate

6434: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6435: @*/
6436: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6437: {

6443:   PetscObjectReference((PetscObject)cdm);
6444:   DMDestroy(&dm->coordinateDM);
6445:   dm->coordinateDM = cdm;
6446:   return(0);
6447: }

6449: /*@
6450:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

6452:   Not Collective

6454:   Input Parameter:
6455: . dm - The DM object

6457:   Output Parameter:
6458: . dim - The embedding dimension

6460:   Level: intermediate

6462: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6463: @*/
6464: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6465: {
6469:   if (dm->dimEmbed == PETSC_DEFAULT) {
6470:     dm->dimEmbed = dm->dim;
6471:   }
6472:   *dim = dm->dimEmbed;
6473:   return(0);
6474: }

6476: /*@
6477:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

6479:   Not Collective

6481:   Input Parameters:
6482: + dm  - The DM object
6483: - dim - The embedding dimension

6485:   Level: intermediate

6487: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6488: @*/
6489: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6490: {
6491:   PetscDS        ds;
6492:   PetscInt       Nds, n;

6497:   dm->dimEmbed = dim;
6498:   if (dm->dim >= 0) {
6499:     DMGetNumDS(dm, &Nds);
6500:     for (n = 0; n < Nds; ++n) {
6501:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6502:       PetscDSSetCoordinateDimension(ds, dim);
6503:     }
6504:   }
6505:   return(0);
6506: }

6508: /*@
6509:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6511:   Collective on dm

6513:   Input Parameter:
6514: . dm - The DM object

6516:   Output Parameter:
6517: . section - The PetscSection object

6519:   Level: intermediate

6521: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6522: @*/
6523: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6524: {
6525:   DM             cdm;

6531:   DMGetCoordinateDM(dm, &cdm);
6532:   DMGetLocalSection(cdm, section);
6533:   return(0);
6534: }

6536: /*@
6537:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6539:   Not Collective

6541:   Input Parameters:
6542: + dm      - The DM object
6543: . dim     - The embedding dimension, or PETSC_DETERMINE
6544: - section - The PetscSection object

6546:   Level: intermediate

6548: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6549: @*/
6550: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6551: {
6552:   DM             cdm;

6558:   DMGetCoordinateDM(dm, &cdm);
6559:   DMSetLocalSection(cdm, section);
6560:   if (dim == PETSC_DETERMINE) {
6561:     PetscInt d = PETSC_DEFAULT;
6562:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6564:     PetscSectionGetChart(section, &pStart, &pEnd);
6565:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6566:     pStart = PetscMax(vStart, pStart);
6567:     pEnd   = PetscMin(vEnd, pEnd);
6568:     for (v = pStart; v < pEnd; ++v) {
6569:       PetscSectionGetDof(section, v, &dd);
6570:       if (dd) {d = dd; break;}
6571:     }
6572:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6573:   }
6574:   return(0);
6575: }

6577: /*@
6578:   DMProjectCoordinates - Project coordinates to a different space

6580:   Input Parameters:
6581: + dm      - The DM object
6582: - disc    - The new coordinate discretization

6584:   Level: intermediate

6586: .seealso: DMGetCoordinateField()
6587: @*/
6588: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6589: {
6590:   PetscObject    discOld;
6591:   PetscClassId   classid;
6592:   DM             cdmOld,cdmNew;
6593:   Vec            coordsOld,coordsNew;
6594:   Mat            matInterp;


6601:   DMGetCoordinateDM(dm, &cdmOld);
6602:   /* Check current discretization is compatible */
6603:   DMGetField(cdmOld, 0, NULL, &discOld);
6604:   PetscObjectGetClassId(discOld, &classid);
6605:   if (classid != PETSCFE_CLASSID) {
6606:     if (classid == PETSC_CONTAINER_CLASSID) {
6607:       PetscFE        feLinear;
6608:       DMPolytopeType ct;
6609:       PetscInt       dim, dE, cStart;
6610:       PetscBool      simplex;

6612:       /* Assume linear vertex coordinates */
6613:       DMGetDimension(dm, &dim);
6614:       DMGetCoordinateDim(dm, &dE);
6615:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6616:       DMPlexGetCellType(dm, cStart, &ct);
6617:       switch (ct) {
6618:         case DM_POLYTOPE_TRI_PRISM:
6619:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6620:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6621:         default: break;
6622:       }
6623:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6624:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6625:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6626:       PetscFEDestroy(&feLinear);
6627:       DMCreateDS(cdmOld);
6628:     } else {
6629:       const char *discname;

6631:       PetscObjectGetType(discOld, &discname);
6632:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6633:     }
6634:   }
6635:   /* Make a fresh clone of the coordinate DM */
6636:   DMClone(cdmOld, &cdmNew);
6637:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6638:   DMCreateDS(cdmNew);
6639:   /* Project the coordinate vector from old to new space  */
6640:   DMGetCoordinates(dm, &coordsOld);
6641:   DMCreateGlobalVector(cdmNew, &coordsNew);
6642:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6643:   MatInterpolate(matInterp, coordsOld, coordsNew);
6644:   MatDestroy(&matInterp);
6645:   /* Set new coordinate structures */
6646:   DMSetCoordinateField(dm, NULL);
6647:   DMSetCoordinateDM(dm, cdmNew);
6648:   DMSetCoordinates(dm, coordsNew);
6649:   VecDestroy(&coordsNew);
6650:   DMDestroy(&cdmNew);
6651:   return(0);
6652: }

6654: /*@C
6655:   DMGetPeriodicity - Get the description of mesh periodicity

6657:   Input Parameter:
6658: . dm      - The DM object

6660:   Output Parameters:
6661: + per     - Whether the DM is periodic or not
6662: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6663: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6664: - bd      - This describes the type of periodicity in each topological dimension

6666:   Level: developer

6668: .seealso: DMGetPeriodicity()
6669: @*/
6670: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6671: {
6674:   if (per)     *per     = dm->periodic;
6675:   if (L)       *L       = dm->L;
6676:   if (maxCell) *maxCell = dm->maxCell;
6677:   if (bd)      *bd      = dm->bdtype;
6678:   return(0);
6679: }

6681: /*@C
6682:   DMSetPeriodicity - Set the description of mesh periodicity

6684:   Input Parameters:
6685: + dm      - The DM object
6686: . per     - Whether the DM is periodic or not.
6687: . 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.
6688: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6689: - bd      - This describes the type of periodicity in each topological dimension

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

6693:   Level: developer

6695: .seealso: DMGetPeriodicity()
6696: @*/
6697: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6698: {
6699:   PetscInt       dim, d;

6708:   DMGetDimension(dm, &dim);
6709:   if (maxCell) {
6710:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6711:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6712:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6713:     PetscFree(dm->maxCell);
6714:   }

6716:   if (L) {
6717:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6718:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6719:   }
6720:   if (bd) {
6721:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6722:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6723:   }
6724:   dm->periodic = per;
6725:   return(0);
6726: }

6728: /*@
6729:   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.

6731:   Input Parameters:
6732: + dm     - The DM
6733: . in     - The input coordinate point (dim numbers)
6734: - endpoint - Include the endpoint L_i

6736:   Output Parameter:
6737: . out - The localized coordinate point

6739:   Level: developer

6741: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6742: @*/
6743: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6744: {
6745:   PetscInt       dim, d;

6749:   DMGetCoordinateDim(dm, &dim);
6750:   if (!dm->maxCell) {
6751:     for (d = 0; d < dim; ++d) out[d] = in[d];
6752:   } else {
6753:     if (endpoint) {
6754:       for (d = 0; d < dim; ++d) {
6755:         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)) {
6756:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6757:         } else {
6758:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6759:         }
6760:       }
6761:     } else {
6762:       for (d = 0; d < dim; ++d) {
6763:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6764:       }
6765:     }
6766:   }
6767:   return(0);
6768: }

6770: /*
6771:   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.

6773:   Input Parameters:
6774: + dm     - The DM
6775: . dim    - The spatial dimension
6776: . anchor - The anchor point, the input point can be no more than maxCell away from it
6777: - in     - The input coordinate point (dim numbers)

6779:   Output Parameter:
6780: . out - The localized coordinate point

6782:   Level: developer

6784:   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

6786: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6787: */
6788: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6789: {
6790:   PetscInt d;

6793:   if (!dm->maxCell) {
6794:     for (d = 0; d < dim; ++d) out[d] = in[d];
6795:   } else {
6796:     for (d = 0; d < dim; ++d) {
6797:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6798:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6799:       } else {
6800:         out[d] = in[d];
6801:       }
6802:     }
6803:   }
6804:   return(0);
6805: }

6807: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6808: {
6809:   PetscInt d;

6812:   if (!dm->maxCell) {
6813:     for (d = 0; d < dim; ++d) out[d] = in[d];
6814:   } else {
6815:     for (d = 0; d < dim; ++d) {
6816:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6817:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6818:       } else {
6819:         out[d] = in[d];
6820:       }
6821:     }
6822:   }
6823:   return(0);
6824: }

6826: /*
6827:   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.

6829:   Input Parameters:
6830: + dm     - The DM
6831: . dim    - The spatial dimension
6832: . anchor - The anchor point, the input point can be no more than maxCell away from it
6833: . in     - The input coordinate delta (dim numbers)
6834: - out    - The input coordinate point (dim numbers)

6836:   Output Parameter:
6837: . out    - The localized coordinate in + out

6839:   Level: developer

6841:   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

6843: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6844: */
6845: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6846: {
6847:   PetscInt d;

6850:   if (!dm->maxCell) {
6851:     for (d = 0; d < dim; ++d) out[d] += in[d];
6852:   } else {
6853:     for (d = 0; d < dim; ++d) {
6854:       const PetscReal maxC = dm->maxCell[d];

6856:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6857:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6859:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6860:           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]));
6861:         out[d] += newCoord;
6862:       } else {
6863:         out[d] += in[d];
6864:       }
6865:     }
6866:   }
6867:   return(0);
6868: }

6870: /*@
6871:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6873:   Not collective

6875:   Input Parameter:
6876: . dm - The DM

6878:   Output Parameter:
6879:   areLocalized - True if localized

6881:   Level: developer

6883: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6884: @*/
6885: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6886: {
6887:   DM             cdm;
6888:   PetscSection   coordSection;
6889:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
6890:   PetscBool      isPlex, alreadyLocalized;

6896:   *areLocalized = PETSC_FALSE;

6898:   /* We need some generic way of refering to cells/vertices */
6899:   DMGetCoordinateDM(dm, &cdm);
6900:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6901:   if (!isPlex) return(0);
6902:   DMPlexGetDepth(cdm, &depth);
6903:   if (!depth) return(0);

6905:   DMGetCoordinateSection(dm, &coordSection);
6906:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6907:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6908:   alreadyLocalized = PETSC_FALSE;
6909:   for (c = cStart; c < cEnd; ++c) {
6910:     if (c < sStart || c >= sEnd) continue;
6911:     PetscSectionGetDof(coordSection, c, &dof);
6912:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6913:   }
6914:   *areLocalized = alreadyLocalized;
6915:   return(0);
6916: }

6918: /*@
6919:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6921:   Collective on dm

6923:   Input Parameter:
6924: . dm - The DM

6926:   Output Parameter:
6927:   areLocalized - True if localized

6929:   Level: developer

6931: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6932: @*/
6933: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6934: {
6935:   PetscBool      localized;

6941:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6942:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6943:   return(0);
6944: }

6946: /*@
6947:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6949:   Collective on dm

6951:   Input Parameter:
6952: . dm - The DM

6954:   Level: developer

6956: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6957: @*/
6958: PetscErrorCode DMLocalizeCoordinates(DM dm)
6959: {
6960:   DM             cdm;
6961:   PetscSection   coordSection, cSection;
6962:   Vec            coordinates,  cVec;
6963:   PetscScalar   *coords, *coords2, *anchor, *localized;
6964:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6965:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6966:   PetscInt       maxHeight = 0, h;
6967:   PetscInt       *pStart = NULL, *pEnd = NULL;

6972:   if (!dm->periodic) return(0);
6973:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6974:   if (alreadyLocalized) return(0);

6976:   /* We need some generic way of refering to cells/vertices */
6977:   DMGetCoordinateDM(dm, &cdm);
6978:   {
6979:     PetscBool isplex;

6981:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6982:     if (isplex) {
6983:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6984:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6985:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6986:       pEnd = &pStart[maxHeight + 1];
6987:       newStart = vStart;
6988:       newEnd   = vEnd;
6989:       for (h = 0; h <= maxHeight; h++) {
6990:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6991:         newStart = PetscMin(newStart,pStart[h]);
6992:         newEnd   = PetscMax(newEnd,pEnd[h]);
6993:       }
6994:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6995:   }
6996:   DMGetCoordinatesLocal(dm, &coordinates);
6997:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6998:   DMGetCoordinateSection(dm, &coordSection);
6999:   VecGetBlockSize(coordinates, &bs);
7000:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

7002:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
7003:   PetscSectionSetNumFields(cSection, 1);
7004:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
7005:   PetscSectionSetFieldComponents(cSection, 0, Nc);
7006:   PetscSectionSetChart(cSection, newStart, newEnd);

7008:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7009:   localized = &anchor[bs];
7010:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7011:   for (h = 0; h <= maxHeight; h++) {
7012:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7014:     for (c = cStart; c < cEnd; ++c) {
7015:       PetscScalar *cellCoords = NULL;
7016:       PetscInt     b;

7018:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7019:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7020:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7021:       for (d = 0; d < dof/bs; ++d) {
7022:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
7023:         for (b = 0; b < bs; b++) {
7024:           if (cellCoords[d*bs + b] != localized[b]) break;
7025:         }
7026:         if (b < bs) break;
7027:       }
7028:       if (d < dof/bs) {
7029:         if (c >= sStart && c < sEnd) {
7030:           PetscInt cdof;

7032:           PetscSectionGetDof(coordSection, c, &cdof);
7033:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7034:         }
7035:         PetscSectionSetDof(cSection, c, dof);
7036:         PetscSectionSetFieldDof(cSection, c, 0, dof);
7037:       }
7038:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7039:     }
7040:   }
7041:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
7042:   if (alreadyLocalizedGlobal) {
7043:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7044:     PetscSectionDestroy(&cSection);
7045:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7046:     return(0);
7047:   }
7048:   for (v = vStart; v < vEnd; ++v) {
7049:     PetscSectionGetDof(coordSection, v, &dof);
7050:     PetscSectionSetDof(cSection, v, dof);
7051:     PetscSectionSetFieldDof(cSection, v, 0, dof);
7052:   }
7053:   PetscSectionSetUp(cSection);
7054:   PetscSectionGetStorageSize(cSection, &coordSize);
7055:   VecCreate(PETSC_COMM_SELF, &cVec);
7056:   PetscObjectSetName((PetscObject)cVec,"coordinates");
7057:   VecSetBlockSize(cVec, bs);
7058:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
7059:   VecSetType(cVec, VECSTANDARD);
7060:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
7061:   VecGetArray(cVec, &coords2);
7062:   for (v = vStart; v < vEnd; ++v) {
7063:     PetscSectionGetDof(coordSection, v, &dof);
7064:     PetscSectionGetOffset(coordSection, v, &off);
7065:     PetscSectionGetOffset(cSection,     v, &off2);
7066:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7067:   }
7068:   for (h = 0; h <= maxHeight; h++) {
7069:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7071:     for (c = cStart; c < cEnd; ++c) {
7072:       PetscScalar *cellCoords = NULL;
7073:       PetscInt     b, cdof;

7075:       PetscSectionGetDof(cSection,c,&cdof);
7076:       if (!cdof) continue;
7077:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7078:       PetscSectionGetOffset(cSection, c, &off2);
7079:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7080:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
7081:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7082:     }
7083:   }
7084:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7085:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7086:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
7087:   VecRestoreArray(cVec, &coords2);
7088:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
7089:   DMSetCoordinatesLocal(dm, cVec);
7090:   VecDestroy(&cVec);
7091:   PetscSectionDestroy(&cSection);
7092:   return(0);
7093: }

7095: /*@
7096:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

7098:   Collective on v (see explanation below)

7100:   Input Parameters:
7101: + dm - The DM
7102: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

7104:   Input/Output Parameters:
7105: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7106: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7107:            on output, the PetscSF containing the ranks and local indices of the containing points

7109:   Level: developer

7111:   Notes:
7112:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7113:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

7115:   If *cellSF is NULL on input, a PetscSF will be created.
7116:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

7118:   An array that maps each point to its containing cell can be obtained with

7120: $    const PetscSFNode *cells;
7121: $    PetscInt           nFound;
7122: $    const PetscInt    *found;
7123: $
7124: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

7126:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7127:   the index of the cell in its rank's local numbering.

7129: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7130: @*/
7131: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7132: {

7139:   if (*cellSF) {
7140:     PetscMPIInt result;

7143:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7144:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7145:   } else {
7146:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7147:   }
7148:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7149:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7150:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7151:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7152:   return(0);
7153: }

7155: /*@
7156:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7158:   Collective on dm

7160:   Input Parameter:
7161: . dm - The original DM

7163:   Output Parameter:
7164: . odm - The DM which provides the layout for output

7166:   Level: intermediate

7168: .seealso: VecView(), DMGetGlobalSection()
7169: @*/
7170: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7171: {
7172:   PetscSection   section;
7173:   PetscBool      hasConstraints, ghasConstraints;

7179:   DMGetLocalSection(dm, &section);
7180:   PetscSectionHasConstraints(section, &hasConstraints);
7181:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7182:   if (!ghasConstraints) {
7183:     *odm = dm;
7184:     return(0);
7185:   }
7186:   if (!dm->dmBC) {
7187:     PetscSection newSection, gsection;
7188:     PetscSF      sf;

7190:     DMClone(dm, &dm->dmBC);
7191:     DMCopyDisc(dm, dm->dmBC);
7192:     PetscSectionClone(section, &newSection);
7193:     DMSetLocalSection(dm->dmBC, newSection);
7194:     PetscSectionDestroy(&newSection);
7195:     DMGetPointSF(dm->dmBC, &sf);
7196:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7197:     DMSetGlobalSection(dm->dmBC, gsection);
7198:     PetscSectionDestroy(&gsection);
7199:   }
7200:   *odm = dm->dmBC;
7201:   return(0);
7202: }

7204: /*@
7205:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7207:   Input Parameter:
7208: . dm - The original DM

7210:   Output Parameters:
7211: + num - The output sequence number
7212: - val - The output sequence value

7214:   Level: intermediate

7216:   Note: This is intended for output that should appear in sequence, for instance
7217:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7219: .seealso: VecView()
7220: @*/
7221: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7222: {
7227:   return(0);
7228: }

7230: /*@
7231:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7233:   Input Parameters:
7234: + dm - The original DM
7235: . num - The output sequence number
7236: - val - The output sequence value

7238:   Level: intermediate

7240:   Note: This is intended for output that should appear in sequence, for instance
7241:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7243: .seealso: VecView()
7244: @*/
7245: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7246: {
7249:   dm->outputSequenceNum = num;
7250:   dm->outputSequenceVal = val;
7251:   return(0);
7252: }

7254: /*@C
7255:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7257:   Input Parameters:
7258: + dm   - The original DM
7259: . name - The sequence name
7260: - num  - The output sequence number

7262:   Output Parameter:
7263: . val  - The output sequence value

7265:   Level: intermediate

7267:   Note: This is intended for output that should appear in sequence, for instance
7268:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7270: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7271: @*/
7272: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7273: {
7274:   PetscBool      ishdf5;

7281:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7282:   if (ishdf5) {
7283: #if defined(PETSC_HAVE_HDF5)
7284:     PetscScalar value;

7286:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7287:     *val = PetscRealPart(value);
7288: #endif
7289:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7290:   return(0);
7291: }

7293: /*@
7294:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

7296:   Not collective

7298:   Input Parameter:
7299: . dm - The DM

7301:   Output Parameter:
7302: . useNatural - The flag to build the mapping to a natural order during distribution

7304:   Level: beginner

7306: .seealso: DMSetUseNatural(), DMCreate()
7307: @*/
7308: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7309: {
7313:   *useNatural = dm->useNatural;
7314:   return(0);
7315: }

7317: /*@
7318:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7320:   Collective on dm

7322:   Input Parameters:
7323: + dm - The DM
7324: - useNatural - The flag to build the mapping to a natural order during distribution

7326:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7328:   Level: beginner

7330: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7331: @*/
7332: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7333: {
7337:   dm->useNatural = useNatural;
7338:   return(0);
7339: }

7341: /*@C
7342:   DMCreateLabel - Create a label of the given name if it does not already exist

7344:   Not Collective

7346:   Input Parameters:
7347: + dm   - The DM object
7348: - name - The label name

7350:   Level: intermediate

7352: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7353: @*/
7354: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7355: {
7356:   PetscBool      flg;
7357:   DMLabel        label;

7363:   DMHasLabel(dm, name, &flg);
7364:   if (!flg) {
7365:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7366:     DMAddLabel(dm, label);
7367:     DMLabelDestroy(&label);
7368:   }
7369:   return(0);
7370: }

7372: /*@C
7373:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

7375:   Not Collective

7377:   Input Parameters:
7378: + dm   - The DM object
7379: . l    - The index for the label
7380: - name - The label name

7382:   Level: intermediate

7384: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7385: @*/
7386: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7387: {
7388:   DMLabelLink    orig, prev = NULL;
7389:   DMLabel        label;
7390:   PetscInt       Nl, m;
7391:   PetscBool      flg, match;
7392:   const char    *lname;

7398:   DMHasLabel(dm, name, &flg);
7399:   if (!flg) {
7400:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7401:     DMAddLabel(dm, label);
7402:     DMLabelDestroy(&label);
7403:   }
7404:   DMGetNumLabels(dm, &Nl);
7405:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7406:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7407:     PetscObjectGetName((PetscObject) orig->label, &lname);
7408:     PetscStrcmp(name, lname, &match);
7409:     if (match) break;
7410:   }
7411:   if (m == l) return(0);
7412:   if (!m) dm->labels = orig->next;
7413:   else    prev->next = orig->next;
7414:   if (!l) {
7415:     orig->next = dm->labels;
7416:     dm->labels = orig;
7417:   } else {
7418:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7419:     orig->next = prev->next;
7420:     prev->next = orig;
7421:   }
7422:   return(0);
7423: }

7425: /*@C
7426:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

7428:   Not Collective

7430:   Input Parameters:
7431: + dm   - The DM object
7432: . name - The label name
7433: - point - The mesh point

7435:   Output Parameter:
7436: . value - The label value for this point, or -1 if the point is not in the label

7438:   Level: beginner

7440: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7441: @*/
7442: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7443: {
7444:   DMLabel        label;

7450:   DMGetLabel(dm, name, &label);
7451:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7452:   DMLabelGetValue(label, point, value);
7453:   return(0);
7454: }

7456: /*@C
7457:   DMSetLabelValue - Add a point to a Sieve Label with given value

7459:   Not Collective

7461:   Input Parameters:
7462: + dm   - The DM object
7463: . name - The label name
7464: . point - The mesh point
7465: - value - The label value for this point

7467:   Output Parameter:

7469:   Level: beginner

7471: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7472: @*/
7473: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7474: {
7475:   DMLabel        label;

7481:   DMGetLabel(dm, name, &label);
7482:   if (!label) {
7483:     DMCreateLabel(dm, name);
7484:     DMGetLabel(dm, name, &label);
7485:   }
7486:   DMLabelSetValue(label, point, value);
7487:   return(0);
7488: }

7490: /*@C
7491:   DMClearLabelValue - Remove a point from a Sieve Label with given value

7493:   Not Collective

7495:   Input Parameters:
7496: + dm   - The DM object
7497: . name - The label name
7498: . point - The mesh point
7499: - value - The label value for this point

7501:   Output Parameter:

7503:   Level: beginner

7505: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7506: @*/
7507: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7508: {
7509:   DMLabel        label;

7515:   DMGetLabel(dm, name, &label);
7516:   if (!label) return(0);
7517:   DMLabelClearValue(label, point, value);
7518:   return(0);
7519: }

7521: /*@C
7522:   DMGetLabelSize - Get the number of different integer ids in a Label

7524:   Not Collective

7526:   Input Parameters:
7527: + dm   - The DM object
7528: - name - The label name

7530:   Output Parameter:
7531: . size - The number of different integer ids, or 0 if the label does not exist

7533:   Level: beginner

7535: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7536: @*/
7537: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7538: {
7539:   DMLabel        label;

7546:   DMGetLabel(dm, name, &label);
7547:   *size = 0;
7548:   if (!label) return(0);
7549:   DMLabelGetNumValues(label, size);
7550:   return(0);
7551: }

7553: /*@C
7554:   DMGetLabelIdIS - Get the integer ids in a label

7556:   Not Collective

7558:   Input Parameters:
7559: + mesh - The DM object
7560: - name - The label name

7562:   Output Parameter:
7563: . ids - The integer ids, or NULL if the label does not exist

7565:   Level: beginner

7567: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7568: @*/
7569: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7570: {
7571:   DMLabel        label;

7578:   DMGetLabel(dm, name, &label);
7579:   *ids = NULL;
7580:  if (label) {
7581:     DMLabelGetValueIS(label, ids);
7582:   } else {
7583:     /* returning an empty IS */
7584:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7585:   }
7586:   return(0);
7587: }

7589: /*@C
7590:   DMGetStratumSize - Get the number of points in a label stratum

7592:   Not Collective

7594:   Input Parameters:
7595: + dm - The DM object
7596: . name - The label name
7597: - value - The stratum value

7599:   Output Parameter:
7600: . size - The stratum size

7602:   Level: beginner

7604: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7605: @*/
7606: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7607: {
7608:   DMLabel        label;

7615:   DMGetLabel(dm, name, &label);
7616:   *size = 0;
7617:   if (!label) return(0);
7618:   DMLabelGetStratumSize(label, value, size);
7619:   return(0);
7620: }

7622: /*@C
7623:   DMGetStratumIS - Get the points in a label stratum

7625:   Not Collective

7627:   Input Parameters:
7628: + dm - The DM object
7629: . name - The label name
7630: - value - The stratum value

7632:   Output Parameter:
7633: . points - The stratum points, or NULL if the label does not exist or does not have that value

7635:   Level: beginner

7637: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7638: @*/
7639: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7640: {
7641:   DMLabel        label;

7648:   DMGetLabel(dm, name, &label);
7649:   *points = NULL;
7650:   if (!label) return(0);
7651:   DMLabelGetStratumIS(label, value, points);
7652:   return(0);
7653: }

7655: /*@C
7656:   DMSetStratumIS - Set the points in a label stratum

7658:   Not Collective

7660:   Input Parameters:
7661: + dm - The DM object
7662: . name - The label name
7663: . value - The stratum value
7664: - points - The stratum points

7666:   Level: beginner

7668: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7669: @*/
7670: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7671: {
7672:   DMLabel        label;

7679:   DMGetLabel(dm, name, &label);
7680:   if (!label) return(0);
7681:   DMLabelSetStratumIS(label, value, points);
7682:   return(0);
7683: }

7685: /*@C
7686:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7688:   Not Collective

7690:   Input Parameters:
7691: + dm   - The DM object
7692: . name - The label name
7693: - value - The label value for this point

7695:   Output Parameter:

7697:   Level: beginner

7699: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7700: @*/
7701: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7702: {
7703:   DMLabel        label;

7709:   DMGetLabel(dm, name, &label);
7710:   if (!label) return(0);
7711:   DMLabelClearStratum(label, value);
7712:   return(0);
7713: }

7715: /*@
7716:   DMGetNumLabels - Return the number of labels defined by the mesh

7718:   Not Collective

7720:   Input Parameter:
7721: . dm   - The DM object

7723:   Output Parameter:
7724: . numLabels - the number of Labels

7726:   Level: intermediate

7728: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7729: @*/
7730: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7731: {
7732:   DMLabelLink next = dm->labels;
7733:   PetscInt  n    = 0;

7738:   while (next) {++n; next = next->next;}
7739:   *numLabels = n;
7740:   return(0);
7741: }

7743: /*@C
7744:   DMGetLabelName - Return the name of nth label

7746:   Not Collective

7748:   Input Parameters:
7749: + dm - The DM object
7750: - n  - the label number

7752:   Output Parameter:
7753: . name - the label name

7755:   Level: intermediate

7757: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7758: @*/
7759: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7760: {
7761:   DMLabelLink    next = dm->labels;
7762:   PetscInt       l    = 0;

7768:   while (next) {
7769:     if (l == n) {
7770:       PetscObjectGetName((PetscObject) next->label, name);
7771:       return(0);
7772:     }
7773:     ++l;
7774:     next = next->next;
7775:   }
7776:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7777: }

7779: /*@C
7780:   DMHasLabel - Determine whether the mesh has a label of a given name

7782:   Not Collective

7784:   Input Parameters:
7785: + dm   - The DM object
7786: - name - The label name

7788:   Output Parameter:
7789: . hasLabel - PETSC_TRUE if the label is present

7791:   Level: intermediate

7793: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7794: @*/
7795: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7796: {
7797:   DMLabelLink    next = dm->labels;
7798:   const char    *lname;

7805:   *hasLabel = PETSC_FALSE;
7806:   while (next) {
7807:     PetscObjectGetName((PetscObject) next->label, &lname);
7808:     PetscStrcmp(name, lname, hasLabel);
7809:     if (*hasLabel) break;
7810:     next = next->next;
7811:   }
7812:   return(0);
7813: }

7815: /*@C
7816:   DMGetLabel - Return the label of a given name, or NULL

7818:   Not Collective

7820:   Input Parameters:
7821: + dm   - The DM object
7822: - name - The label name

7824:   Output Parameter:
7825: . label - The DMLabel, or NULL if the label is absent

7827:   Note: Some of the default labels in a DMPlex will be
7828: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7829: $ "celltype"    - Holds the topological type of each cell
7830: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7831: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7832: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7833: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7835:   Level: intermediate

7837: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7838: @*/
7839: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7840: {
7841:   DMLabelLink    next = dm->labels;
7842:   PetscBool      hasLabel;
7843:   const char    *lname;

7850:   *label = NULL;
7851:   while (next) {
7852:     PetscObjectGetName((PetscObject) next->label, &lname);
7853:     PetscStrcmp(name, lname, &hasLabel);
7854:     if (hasLabel) {
7855:       *label = next->label;
7856:       break;
7857:     }
7858:     next = next->next;
7859:   }
7860:   return(0);
7861: }

7863: /*@C
7864:   DMGetLabelByNum - Return the nth label

7866:   Not Collective

7868:   Input Parameters:
7869: + dm - The DM object
7870: - n  - the label number

7872:   Output Parameter:
7873: . label - the label

7875:   Level: intermediate

7877: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7878: @*/
7879: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7880: {
7881:   DMLabelLink next = dm->labels;
7882:   PetscInt    l    = 0;

7887:   while (next) {
7888:     if (l == n) {
7889:       *label = next->label;
7890:       return(0);
7891:     }
7892:     ++l;
7893:     next = next->next;
7894:   }
7895:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7896: }

7898: /*@C
7899:   DMAddLabel - Add the label to this mesh

7901:   Not Collective

7903:   Input Parameters:
7904: + dm   - The DM object
7905: - label - The DMLabel

7907:   Level: developer

7909: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7910: @*/
7911: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7912: {
7913:   DMLabelLink    l, *p, tmpLabel;
7914:   PetscBool      hasLabel;
7915:   const char    *lname;
7916:   PetscBool      flg;

7921:   PetscObjectGetName((PetscObject) label, &lname);
7922:   DMHasLabel(dm, lname, &hasLabel);
7923:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7924:   PetscCalloc1(1, &tmpLabel);
7925:   tmpLabel->label  = label;
7926:   tmpLabel->output = PETSC_TRUE;
7927:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7928:   *p = tmpLabel;
7929:   PetscObjectReference((PetscObject)label);
7930:   PetscStrcmp(lname, "depth", &flg);
7931:   if (flg) dm->depthLabel = label;
7932:   PetscStrcmp(lname, "celltype", &flg);
7933:   if (flg) dm->celltypeLabel = label;
7934:   return(0);
7935: }

7937: /*@C
7938:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

7940:   Not Collective

7942:   Input Parameters:
7943: + dm    - The DM object
7944: - label - The DMLabel, having the same name, to substitute

7946:   Note: Some of the default labels in a DMPlex will be
7947: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7948: $ "celltype"    - Holds the topological type of each cell
7949: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7950: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7951: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7952: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7954:   Level: intermediate

7956: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7957: @*/
7958: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7959: {
7960:   DMLabelLink    next = dm->labels;
7961:   PetscBool      hasLabel, flg;
7962:   const char    *name, *lname;

7968:   PetscObjectGetName((PetscObject) label, &name);
7969:   while (next) {
7970:     PetscObjectGetName((PetscObject) next->label, &lname);
7971:     PetscStrcmp(name, lname, &hasLabel);
7972:     if (hasLabel) {
7973:       PetscObjectReference((PetscObject) label);
7974:       PetscStrcmp(lname, "depth", &flg);
7975:       if (flg) dm->depthLabel = label;
7976:       PetscStrcmp(lname, "celltype", &flg);
7977:       if (flg) dm->celltypeLabel = label;
7978:       DMLabelDestroy(&next->label);
7979:       next->label = label;
7980:       break;
7981:     }
7982:     next = next->next;
7983:   }
7984:   return(0);
7985: }

7987: /*@C
7988:   DMRemoveLabel - Remove the label given by name from this mesh

7990:   Not Collective

7992:   Input Parameters:
7993: + dm   - The DM object
7994: - name - The label name

7996:   Output Parameter:
7997: . label - The DMLabel, or NULL if the label is absent

7999:   Level: developer

8001:   Notes:
8002:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
8003:   DMLabelDestroy() on the label.

8005:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
8006:   call DMLabelDestroy(). Instead, the label is returned and the user is
8007:   responsible of calling DMLabelDestroy() at some point.

8009: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
8010: @*/
8011: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8012: {
8013:   DMLabelLink    link, *pnext;
8014:   PetscBool      hasLabel;
8015:   const char    *lname;

8021:   if (label) {
8023:     *label = NULL;
8024:   }
8025:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8026:     PetscObjectGetName((PetscObject) link->label, &lname);
8027:     PetscStrcmp(name, lname, &hasLabel);
8028:     if (hasLabel) {
8029:       *pnext = link->next; /* Remove from list */
8030:       PetscStrcmp(name, "depth", &hasLabel);
8031:       if (hasLabel) dm->depthLabel = NULL;
8032:       PetscStrcmp(name, "celltype", &hasLabel);
8033:       if (hasLabel) dm->celltypeLabel = NULL;
8034:       if (label) *label = link->label;
8035:       else       {DMLabelDestroy(&link->label);}
8036:       PetscFree(link);
8037:       break;
8038:     }
8039:   }
8040:   return(0);
8041: }

8043: /*@
8044:   DMRemoveLabelBySelf - Remove the label from this mesh

8046:   Not Collective

8048:   Input Parameters:
8049: + dm   - The DM object
8050: . label - The DMLabel to be removed from the DM
8051: - failNotFound - Should it fail if the label is not found in the DM?

8053:   Level: developer

8055:   Notes:
8056:   Only exactly the same instance is removed if found, name match is ignored.
8057:   If the DM has an exclusive reference to the label, it gets destroyed and
8058:   *label nullified.

8060: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
8061: @*/
8062: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8063: {
8064:   DMLabelLink    link, *pnext;
8065:   PetscBool      hasLabel = PETSC_FALSE;

8071:   if (!*label && !failNotFound) return(0);
8074:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8075:     if (*label == link->label) {
8076:       hasLabel = PETSC_TRUE;
8077:       *pnext = link->next; /* Remove from list */
8078:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
8079:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8080:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8081:       DMLabelDestroy(&link->label);
8082:       PetscFree(link);
8083:       break;
8084:     }
8085:   }
8086:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8087:   return(0);
8088: }

8090: /*@C
8091:   DMGetLabelOutput - Get the output flag for a given label

8093:   Not Collective

8095:   Input Parameters:
8096: + dm   - The DM object
8097: - name - The label name

8099:   Output Parameter:
8100: . output - The flag for output

8102:   Level: developer

8104: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8105: @*/
8106: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8107: {
8108:   DMLabelLink    next = dm->labels;
8109:   const char    *lname;

8116:   while (next) {
8117:     PetscBool flg;

8119:     PetscObjectGetName((PetscObject) next->label, &lname);
8120:     PetscStrcmp(name, lname, &flg);
8121:     if (flg) {*output = next->output; return(0);}
8122:     next = next->next;
8123:   }
8124:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8125: }

8127: /*@C
8128:   DMSetLabelOutput - Set the output flag for a given label

8130:   Not Collective

8132:   Input Parameters:
8133: + dm     - The DM object
8134: . name   - The label name
8135: - output - The flag for output

8137:   Level: developer

8139: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8140: @*/
8141: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8142: {
8143:   DMLabelLink    next = dm->labels;
8144:   const char    *lname;

8150:   while (next) {
8151:     PetscBool flg;

8153:     PetscObjectGetName((PetscObject) next->label, &lname);
8154:     PetscStrcmp(name, lname, &flg);
8155:     if (flg) {next->output = output; return(0);}
8156:     next = next->next;
8157:   }
8158:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8159: }

8161: /*@
8162:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

8164:   Collective on dmA

8166:   Input Parameters:
8167: + dmA - The DM object with initial labels
8168: . dmB - The DM object with copied labels
8169: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8170: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

8172:   Level: intermediate

8174:   Note: This is typically used when interpolating or otherwise adding to a mesh

8176: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8177: @*/
8178: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8179: {
8180:   DMLabel        label, labelNew;
8181:   const char    *name;
8182:   PetscBool      flg;
8183:   DMLabelLink    link;

8191:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8192:   if (dmA == dmB) return(0);
8193:   for (link=dmA->labels; link; link=link->next) {
8194:     label=link->label;
8195:     PetscObjectGetName((PetscObject)label, &name);
8196:     if (!all) {
8197:       PetscStrcmp(name, "depth", &flg);
8198:       if (flg) continue;
8199:       PetscStrcmp(name, "dim", &flg);
8200:       if (flg) continue;
8201:       PetscStrcmp(name, "celltype", &flg);
8202:       if (flg) continue;
8203:     }
8204:     if (mode==PETSC_COPY_VALUES) {
8205:       DMLabelDuplicate(label, &labelNew);
8206:     } else {
8207:       labelNew = label;
8208:     }
8209:     DMAddLabel(dmB, labelNew);
8210:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8211:   }
8212:   return(0);
8213: }

8215: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8216: {
8220:   if (!*label) {
8221:     DMCreateLabel(dm, name);
8222:     DMGetLabel(dm, name, label);
8223:   }
8224:   DMLabelSetValue(*label, point, value);
8225:   return(0);
8226: }

8228: /*
8229:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8230:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8231:   (label, id) pair in the DM.

8233:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8234:   each label.
8235: */
8236: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8237: {
8238:   DMUniversalLabel ul;
8239:   PetscBool       *active;
8240:   PetscInt         pStart, pEnd, p, Nl, l, m;
8241:   PetscErrorCode   ierr;

8244:   PetscMalloc1(1, &ul);
8245:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8246:   DMGetNumLabels(dm, &Nl);
8247:   PetscCalloc1(Nl, &active);
8248:   ul->Nl = 0;
8249:   for (l = 0; l < Nl; ++l) {
8250:     PetscBool   isdepth, iscelltype;
8251:     const char *name;

8253:     DMGetLabelName(dm, l, &name);
8254:     PetscStrncmp(name, "depth", 6, &isdepth);
8255:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8256:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8257:     if (active[l]) ++ul->Nl;
8258:   }
8259:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8260:   ul->Nv = 0;
8261:   for (l = 0, m = 0; l < Nl; ++l) {
8262:     DMLabel     label;
8263:     PetscInt    nv;
8264:     const char *name;

8266:     if (!active[l]) continue;
8267:     DMGetLabelName(dm, l, &name);
8268:     DMGetLabelByNum(dm, l, &label);
8269:     DMLabelGetNumValues(label, &nv);
8270:     PetscStrallocpy(name, &ul->names[m]);
8271:     ul->indices[m]   = l;
8272:     ul->Nv          += nv;
8273:     ul->offsets[m+1] = nv;
8274:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8275:     ++m;
8276:   }
8277:   for (l = 1; l <= ul->Nl; ++l) {
8278:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8279:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8280:   }
8281:   for (l = 0; l < ul->Nl; ++l) {
8282:     PetscInt b;

8284:     ul->masks[l] = 0;
8285:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8286:   }
8287:   PetscMalloc1(ul->Nv, &ul->values);
8288:   for (l = 0, m = 0; l < Nl; ++l) {
8289:     DMLabel         label;
8290:     IS              valueIS;
8291:     const PetscInt *varr;
8292:     PetscInt        nv, v;

8294:     if (!active[l]) continue;
8295:     DMGetLabelByNum(dm, l, &label);
8296:     DMLabelGetNumValues(label, &nv);
8297:     DMLabelGetValueIS(label, &valueIS);
8298:     ISGetIndices(valueIS, &varr);
8299:     for (v = 0; v < nv; ++v) {
8300:       ul->values[ul->offsets[m]+v] = varr[v];
8301:     }
8302:     ISRestoreIndices(valueIS, &varr);
8303:     ISDestroy(&valueIS);
8304:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8305:     ++m;
8306:   }
8307:   DMPlexGetChart(dm, &pStart, &pEnd);
8308:   for (p = pStart; p < pEnd; ++p) {
8309:     PetscInt  uval = 0;
8310:     PetscBool marked = PETSC_FALSE;

8312:     for (l = 0, m = 0; l < Nl; ++l) {
8313:       DMLabel  label;
8314:       PetscInt val, defval, loc, nv;

8316:       if (!active[l]) continue;
8317:       DMGetLabelByNum(dm, l, &label);
8318:       DMLabelGetValue(label, p, &val);
8319:       DMLabelGetDefaultValue(label, &defval);
8320:       if (val == defval) {++m; continue;}
8321:       nv = ul->offsets[m+1]-ul->offsets[m];
8322:       marked = PETSC_TRUE;
8323:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8324:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8325:       uval += (loc+1) << ul->bits[m];
8326:       ++m;
8327:     }
8328:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8329:   }
8330:   PetscFree(active);
8331:   *universal = ul;
8332:   return(0);
8333: }

8335: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8336: {
8337:   PetscInt       l;

8341:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8342:   DMLabelDestroy(&(*universal)->label);
8343:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8344:   PetscFree((*universal)->values);
8345:   PetscFree(*universal);
8346:   *universal = NULL;
8347:   return(0);
8348: }

8350: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8351: {
8354:   *ulabel = ul->label;
8355:   return(0);
8356: }

8358: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8359: {
8360:   PetscInt       Nl = ul->Nl, l;

8365:   for (l = 0; l < Nl; ++l) {
8366:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8367:     else               {DMCreateLabel(dm, ul->names[l]);}
8368:   }
8369:   if (preserveOrder) {
8370:     for (l = 0; l < ul->Nl; ++l) {
8371:       const char *name;
8372:       PetscBool   match;

8374:       DMGetLabelName(dm, ul->indices[l], &name);
8375:       PetscStrcmp(name, ul->names[l], &match);
8376:       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]);
8377:     }
8378:   }
8379:   return(0);
8380: }

8382: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8383: {
8384:   PetscInt       l;

8388:   for (l = 0; l < ul->Nl; ++l) {
8389:     DMLabel  label;
8390:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

8392:     if (lval) {
8393:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8394:       else          {DMGetLabel(dm, ul->names[l], &label);}
8395:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8396:     }
8397:   }
8398:   return(0);
8399: }

8401: /*@
8402:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

8404:   Input Parameter:
8405: . dm - The DM object

8407:   Output Parameter:
8408: . cdm - The coarse DM

8410:   Level: intermediate

8412: .seealso: DMSetCoarseDM()
8413: @*/
8414: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8415: {
8419:   *cdm = dm->coarseMesh;
8420:   return(0);
8421: }

8423: /*@
8424:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

8426:   Input Parameters:
8427: + dm - The DM object
8428: - cdm - The coarse DM

8430:   Level: intermediate

8432: .seealso: DMGetCoarseDM()
8433: @*/
8434: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8435: {

8441:   PetscObjectReference((PetscObject)cdm);
8442:   DMDestroy(&dm->coarseMesh);
8443:   dm->coarseMesh = cdm;
8444:   return(0);
8445: }

8447: /*@
8448:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

8450:   Input Parameter:
8451: . dm - The DM object

8453:   Output Parameter:
8454: . fdm - The fine DM

8456:   Level: intermediate

8458: .seealso: DMSetFineDM()
8459: @*/
8460: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8461: {
8465:   *fdm = dm->fineMesh;
8466:   return(0);
8467: }

8469: /*@
8470:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

8472:   Input Parameters:
8473: + dm - The DM object
8474: - fdm - The fine DM

8476:   Level: intermediate

8478: .seealso: DMGetFineDM()
8479: @*/
8480: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8481: {

8487:   PetscObjectReference((PetscObject)fdm);
8488:   DMDestroy(&dm->fineMesh);
8489:   dm->fineMesh = fdm;
8490:   return(0);
8491: }

8493: /*=== DMBoundary code ===*/

8495: /*@C
8496:   DMAddBoundary - Add a boundary condition to the model

8498:   Collective on dm

8500:   Input Parameters:
8501: + dm       - The DM, with a PetscDS that matches the problem being constrained
8502: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8503: . name     - The BC name
8504: . label    - The label defining constrained points
8505: . Nv       - The number of DMLabel values for constrained points
8506: . values   - An array of values for constrained points
8507: . field    - The field to constrain
8508: . Nc       - The number of constrained field components (0 will constrain all fields)
8509: . comps    - An array of constrained component numbers
8510: . bcFunc   - A pointwise function giving boundary values
8511: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8512: - ctx      - An optional user context for bcFunc

8514:   Output Parameter:
8515: . bd          - (Optional) Boundary number

8517:   Options Database Keys:
8518: + -bc_<boundary name> <num> - Overrides the boundary ids
8519: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8521:   Note:
8522:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8524: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8526:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8528: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8529: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8530: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8531: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8533: + dim - the spatial dimension
8534: . Nf - the number of fields
8535: . uOff - the offset into u[] and u_t[] for each field
8536: . uOff_x - the offset into u_x[] for each field
8537: . u - each field evaluated at the current point
8538: . u_t - the time derivative of each field evaluated at the current point
8539: . u_x - the gradient of each field evaluated at the current point
8540: . aOff - the offset into a[] and a_t[] for each auxiliary field
8541: . aOff_x - the offset into a_x[] for each auxiliary field
8542: . a - each auxiliary field evaluated at the current point
8543: . a_t - the time derivative of each auxiliary field evaluated at the current point
8544: . a_x - the gradient of auxiliary each field evaluated at the current point
8545: . t - current time
8546: . x - coordinates of the current point
8547: . numConstants - number of constant parameters
8548: . constants - constant parameters
8549: - bcval - output values at the current point

8551:   Level: developer

8553: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8554: @*/
8555: 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)
8556: {
8557:   PetscDS        ds;

8567:   DMGetDS(dm, &ds);
8568:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8569:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8570:   return(0);
8571: }

8573: /* TODO Remove this since now the structures are the same */
8574: static PetscErrorCode DMPopulateBoundary(DM dm)
8575: {
8576:   PetscDS        ds;
8577:   DMBoundary    *lastnext;
8578:   DSBoundary     dsbound;

8582:   DMGetDS(dm, &ds);
8583:   dsbound = ds->boundary;
8584:   if (dm->boundary) {
8585:     DMBoundary next = dm->boundary;

8587:     /* quick check to see if the PetscDS has changed */
8588:     if (next->dsboundary == dsbound) return(0);
8589:     /* the PetscDS has changed: tear down and rebuild */
8590:     while (next) {
8591:       DMBoundary b = next;

8593:       next = b->next;
8594:       PetscFree(b);
8595:     }
8596:     dm->boundary = NULL;
8597:   }

8599:   lastnext = &(dm->boundary);
8600:   while (dsbound) {
8601:     DMBoundary dmbound;

8603:     PetscNew(&dmbound);
8604:     dmbound->dsboundary = dsbound;
8605:     dmbound->label      = dsbound->label;
8606:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8607:     *lastnext = dmbound;
8608:     lastnext = &(dmbound->next);
8609:     dsbound = dsbound->next;
8610:   }
8611:   return(0);
8612: }

8614: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8615: {
8616:   DMBoundary     b;

8622:   *isBd = PETSC_FALSE;
8623:   DMPopulateBoundary(dm);
8624:   b = dm->boundary;
8625:   while (b && !(*isBd)) {
8626:     DMLabel    label = b->label;
8627:     DSBoundary dsb   = b->dsboundary;
8628:     PetscInt   i;

8630:     if (label) {
8631:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
8632:     }
8633:     b = b->next;
8634:   }
8635:   return(0);
8636: }

8638: /*@C
8639:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8641:   Collective on DM

8643:   Input Parameters:
8644: + dm      - The DM
8645: . time    - The time
8646: . funcs   - The coordinate functions to evaluate, one per field
8647: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8648: - mode    - The insertion mode for values

8650:   Output Parameter:
8651: . X - vector

8653:    Calling sequence of func:
8654: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8656: +  dim - The spatial dimension
8657: .  time - The time at which to sample
8658: .  x   - The coordinates
8659: .  Nc  - The number of components
8660: .  u   - The output field values
8661: -  ctx - optional user-defined function context

8663:   Level: developer

8665: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8666: @*/
8667: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8668: {
8669:   Vec            localX;

8674:   DMGetLocalVector(dm, &localX);
8675:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8676:   DMLocalToGlobalBegin(dm, localX, mode, X);
8677:   DMLocalToGlobalEnd(dm, localX, mode, X);
8678:   DMRestoreLocalVector(dm, &localX);
8679:   return(0);
8680: }

8682: /*@C
8683:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8685:   Not collective

8687:   Input Parameters:
8688: + dm      - The DM
8689: . time    - The time
8690: . funcs   - The coordinate functions to evaluate, one per field
8691: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8692: - mode    - The insertion mode for values

8694:   Output Parameter:
8695: . localX - vector

8697:    Calling sequence of func:
8698: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8700: +  dim - The spatial dimension
8701: .  x   - The coordinates
8702: .  Nc  - The number of components
8703: .  u   - The output field values
8704: -  ctx - optional user-defined function context

8706:   Level: developer

8708: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8709: @*/
8710: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8711: {

8717:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8718:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8719:   return(0);
8720: }

8722: /*@C
8723:   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.

8725:   Collective on DM

8727:   Input Parameters:
8728: + dm      - The DM
8729: . time    - The time
8730: . label   - The DMLabel selecting the portion of the mesh for projection
8731: . funcs   - The coordinate functions to evaluate, one per field
8732: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8733: - mode    - The insertion mode for values

8735:   Output Parameter:
8736: . X - vector

8738:    Calling sequence of func:
8739: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8741: +  dim - The spatial dimension
8742: .  x   - The coordinates
8743: .  Nc  - The number of components
8744: .  u   - The output field values
8745: -  ctx - optional user-defined function context

8747:   Level: developer

8749: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8750: @*/
8751: 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)
8752: {
8753:   Vec            localX;

8758:   DMGetLocalVector(dm, &localX);
8759:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8760:   DMLocalToGlobalBegin(dm, localX, mode, X);
8761:   DMLocalToGlobalEnd(dm, localX, mode, X);
8762:   DMRestoreLocalVector(dm, &localX);
8763:   return(0);
8764: }

8766: /*@C
8767:   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.

8769:   Not collective

8771:   Input Parameters:
8772: + dm      - The DM
8773: . time    - The time
8774: . label   - The DMLabel selecting the portion of the mesh for projection
8775: . funcs   - The coordinate functions to evaluate, one per field
8776: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8777: - mode    - The insertion mode for values

8779:   Output Parameter:
8780: . localX - vector

8782:    Calling sequence of func:
8783: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8785: +  dim - The spatial dimension
8786: .  x   - The coordinates
8787: .  Nc  - The number of components
8788: .  u   - The output field values
8789: -  ctx - optional user-defined function context

8791:   Level: developer

8793: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8794: @*/
8795: 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)
8796: {

8802:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8803:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8804:   return(0);
8805: }

8807: /*@C
8808:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8810:   Not collective

8812:   Input Parameters:
8813: + dm      - The DM
8814: . time    - The time
8815: . localU  - The input field vector
8816: . funcs   - The functions to evaluate, one per field
8817: - mode    - The insertion mode for values

8819:   Output Parameter:
8820: . localX  - The output vector

8822:    Calling sequence of func:
8823: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8824: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8825: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8826: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8828: +  dim          - The spatial dimension
8829: .  Nf           - The number of input fields
8830: .  NfAux        - The number of input auxiliary fields
8831: .  uOff         - The offset of each field in u[]
8832: .  uOff_x       - The offset of each field in u_x[]
8833: .  u            - The field values at this point in space
8834: .  u_t          - The field time derivative at this point in space (or NULL)
8835: .  u_x          - The field derivatives at this point in space
8836: .  aOff         - The offset of each auxiliary field in u[]
8837: .  aOff_x       - The offset of each auxiliary field in u_x[]
8838: .  a            - The auxiliary field values at this point in space
8839: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8840: .  a_x          - The auxiliary field derivatives at this point in space
8841: .  t            - The current time
8842: .  x            - The coordinates of this point
8843: .  numConstants - The number of constants
8844: .  constants    - The value of each constant
8845: -  f            - The value of the function at this point in space

8847:   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.
8848:   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
8849:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8850:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8852:   Level: intermediate

8854: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8855: @*/
8856: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8857:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8858:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8859:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8860:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8861:                                    InsertMode mode, Vec localX)
8862: {

8869:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8870:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8871:   return(0);
8872: }

8874: /*@C
8875:   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.

8877:   Not collective

8879:   Input Parameters:
8880: + dm      - The DM
8881: . time    - The time
8882: . label   - The DMLabel marking the portion of the domain to output
8883: . numIds  - The number of label ids to use
8884: . ids     - The label ids to use for marking
8885: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8886: . comps   - The components to set in the output, or NULL for all components
8887: . localU  - The input field vector
8888: . funcs   - The functions to evaluate, one per field
8889: - mode    - The insertion mode for values

8891:   Output Parameter:
8892: . localX  - The output vector

8894:    Calling sequence of func:
8895: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8896: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8897: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8898: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8900: +  dim          - The spatial dimension
8901: .  Nf           - The number of input fields
8902: .  NfAux        - The number of input auxiliary fields
8903: .  uOff         - The offset of each field in u[]
8904: .  uOff_x       - The offset of each field in u_x[]
8905: .  u            - The field values at this point in space
8906: .  u_t          - The field time derivative at this point in space (or NULL)
8907: .  u_x          - The field derivatives at this point in space
8908: .  aOff         - The offset of each auxiliary field in u[]
8909: .  aOff_x       - The offset of each auxiliary field in u_x[]
8910: .  a            - The auxiliary field values at this point in space
8911: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8912: .  a_x          - The auxiliary field derivatives at this point in space
8913: .  t            - The current time
8914: .  x            - The coordinates of this point
8915: .  numConstants - The number of constants
8916: .  constants    - The value of each constant
8917: -  f            - The value of the function at this point in space

8919:   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.
8920:   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
8921:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8922:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8924:   Level: intermediate

8926: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8927: @*/
8928: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8929:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8930:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8931:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8932:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8933:                                         InsertMode mode, Vec localX)
8934: {

8941:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8942:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8943:   return(0);
8944: }

8946: /*@C
8947:   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.

8949:   Not collective

8951:   Input Parameters:
8952: + dm      - The DM
8953: . time    - The time
8954: . label   - The DMLabel marking the portion of the domain boundary to output
8955: . numIds  - The number of label ids to use
8956: . ids     - The label ids to use for marking
8957: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8958: . comps   - The components to set in the output, or NULL for all components
8959: . localU  - The input field vector
8960: . funcs   - The functions to evaluate, one per field
8961: - mode    - The insertion mode for values

8963:   Output Parameter:
8964: . localX  - The output vector

8966:    Calling sequence of func:
8967: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8968: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8969: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8970: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8972: +  dim          - The spatial dimension
8973: .  Nf           - The number of input fields
8974: .  NfAux        - The number of input auxiliary fields
8975: .  uOff         - The offset of each field in u[]
8976: .  uOff_x       - The offset of each field in u_x[]
8977: .  u            - The field values at this point in space
8978: .  u_t          - The field time derivative at this point in space (or NULL)
8979: .  u_x          - The field derivatives at this point in space
8980: .  aOff         - The offset of each auxiliary field in u[]
8981: .  aOff_x       - The offset of each auxiliary field in u_x[]
8982: .  a            - The auxiliary field values at this point in space
8983: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8984: .  a_x          - The auxiliary field derivatives at this point in space
8985: .  t            - The current time
8986: .  x            - The coordinates of this point
8987: .  n            - The face normal
8988: .  numConstants - The number of constants
8989: .  constants    - The value of each constant
8990: -  f            - The value of the function at this point in space

8992:   Note:
8993:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8994:   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
8995:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8996:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8998:   Level: intermediate

9000: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
9001: @*/
9002: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9003:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
9004:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9005:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9006:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9007:                                           InsertMode mode, Vec localX)
9008: {

9015:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9016:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
9017:   return(0);
9018: }

9020: /*@C
9021:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

9023:   Input Parameters:
9024: + dm    - The DM
9025: . time  - The time
9026: . funcs - The functions to evaluate for each field component
9027: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9028: - X     - The coefficient vector u_h, a global vector

9030:   Output Parameter:
9031: . diff - The diff ||u - u_h||_2

9033:   Level: developer

9035: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9036: @*/
9037: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
9038: {

9044:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9045:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
9046:   return(0);
9047: }

9049: /*@C
9050:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

9052:   Collective on dm

9054:   Input Parameters:
9055: + dm    - The DM
9056: , time  - The time
9057: . funcs - The gradient functions to evaluate for each field component
9058: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9059: . X     - The coefficient vector u_h, a global vector
9060: - n     - The vector to project along

9062:   Output Parameter:
9063: . diff - The diff ||(grad u - grad u_h) . n||_2

9065:   Level: developer

9067: .seealso: DMProjectFunction(), DMComputeL2Diff()
9068: @*/
9069: 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)
9070: {

9076:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9077:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
9078:   return(0);
9079: }

9081: /*@C
9082:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

9084:   Collective on dm

9086:   Input Parameters:
9087: + dm    - The DM
9088: . time  - The time
9089: . funcs - The functions to evaluate for each field component
9090: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9091: - X     - The coefficient vector u_h, a global vector

9093:   Output Parameter:
9094: . diff - The array of differences, ||u^f - u^f_h||_2

9096:   Level: developer

9098: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9099: @*/
9100: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9101: {

9107:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9108:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9109:   return(0);
9110: }

9112: /*@C
9113:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
9114:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

9116:   Collective on dm

9118:   Input parameters:
9119: + dm - the pre-adaptation DM object
9120: - label - label with the flags

9122:   Output parameters:
9123: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

9125:   Level: intermediate

9127: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9128: @*/
9129: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9130: {

9137:   *dmAdapt = NULL;
9138:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9139:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
9140:   if (*dmAdapt) {
9141:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
9142:     PetscFree((*dmAdapt)->vectype);
9143:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9144:     PetscFree((*dmAdapt)->mattype);
9145:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9146:   }
9147:   return(0);
9148: }

9150: /*@C
9151:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

9153:   Input Parameters:
9154: + dm - The DM object
9155: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9156: - 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_".

9158:   Output Parameter:
9159: . dmAdapt  - Pointer to the DM object containing the adapted mesh

9161:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

9163:   Level: advanced

9165: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9166: @*/
9167: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9168: {

9176:   *dmAdapt = NULL;
9177:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9178:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9179:   return(0);
9180: }

9182: /*@C
9183:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

9185:  Not Collective

9187:  Input Parameter:
9188: .  dm    - The DM

9190:  Output Parameters:
9191: +  nranks - the number of neighbours
9192: -  ranks - the neighbors ranks

9194:  Notes:
9195:  Do not free the array, it is freed when the DM is destroyed.

9197:  Level: beginner

9199:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9200: @*/
9201: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9202: {

9207:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9208:   (dm->ops->getneighbors)(dm,nranks,ranks);
9209:   return(0);
9210: }

9212: #include <petsc/private/matimpl.h>

9214: /*
9215:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9216:     This has be a different function because it requires DM which is not defined in the Mat library
9217: */
9218: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9219: {

9223:   if (coloring->ctype == IS_COLORING_LOCAL) {
9224:     Vec x1local;
9225:     DM  dm;
9226:     MatGetDM(J,&dm);
9227:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9228:     DMGetLocalVector(dm,&x1local);
9229:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9230:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9231:     x1   = x1local;
9232:   }
9233:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9234:   if (coloring->ctype == IS_COLORING_LOCAL) {
9235:     DM  dm;
9236:     MatGetDM(J,&dm);
9237:     DMRestoreLocalVector(dm,&x1);
9238:   }
9239:   return(0);
9240: }

9242: /*@
9243:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

9245:     Input Parameter:
9246: .    coloring - the MatFDColoring object

9248:     Developer Notes:
9249:     this routine exists because the PETSc Mat library does not know about the DM objects

9251:     Level: advanced

9253: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9254: @*/
9255: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9256: {
9258:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9259:   return(0);
9260: }

9262: /*@
9263:     DMGetCompatibility - determine if two DMs are compatible

9265:     Collective

9267:     Input Parameters:
9268: +    dm1 - the first DM
9269: -    dm2 - the second DM

9271:     Output Parameters:
9272: +    compatible - whether or not the two DMs are compatible
9273: -    set - whether or not the compatible value was set

9275:     Notes:
9276:     Two DMs are deemed compatible if they represent the same parallel decomposition
9277:     of the same topology. This implies that the section (field data) on one
9278:     "makes sense" with respect to the topology and parallel decomposition of the other.
9279:     Loosely speaking, compatible DMs represent the same domain and parallel
9280:     decomposition, but hold different data.

9282:     Typically, one would confirm compatibility if intending to simultaneously iterate
9283:     over a pair of vectors obtained from different DMs.

9285:     For example, two DMDA objects are compatible if they have the same local
9286:     and global sizes and the same stencil width. They can have different numbers
9287:     of degrees of freedom per node. Thus, one could use the node numbering from
9288:     either DM in bounds for a loop over vectors derived from either DM.

9290:     Consider the operation of summing data living on a 2-dof DMDA to data living
9291:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9292: .vb
9293:   ...
9294:   DMGetCompatibility(da1,da2,&compatible,&set);
9295:   if (set && compatible)  {
9296:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9297:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9298:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9299:     for (j=y; j<y+n; ++j) {
9300:       for (i=x; i<x+m, ++i) {
9301:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9302:       }
9303:     }
9304:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9305:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9306:   } else {
9307:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9308:   }
9309:   ...
9310: .ve

9312:     Checking compatibility might be expensive for a given implementation of DM,
9313:     or might be impossible to unambiguously confirm or deny. For this reason,
9314:     this function may decline to determine compatibility, and hence users should
9315:     always check the "set" output parameter.

9317:     A DM is always compatible with itself.

9319:     In the current implementation, DMs which live on "unequal" communicators
9320:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9321:     incompatible.

9323:     This function is labeled "Collective," as information about all subdomains
9324:     is required on each rank. However, in DM implementations which store all this
9325:     information locally, this function may be merely "Logically Collective".

9327:     Developer Notes:
9328:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9329:     iff B is compatible with A. Thus, this function checks the implementations
9330:     of both dm and dmc (if they are of different types), attempting to determine
9331:     compatibility. It is left to DM implementers to ensure that symmetry is
9332:     preserved. The simplest way to do this is, when implementing type-specific
9333:     logic for this function, is to check for existing logic in the implementation
9334:     of other DM types and let *set = PETSC_FALSE if found.

9336:     Level: advanced

9338: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9339: @*/

9341: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9342: {
9344:   PetscMPIInt    compareResult;
9345:   DMType         type,type2;
9346:   PetscBool      sameType;


9352:   /* Declare a DM compatible with itself */
9353:   if (dm1 == dm2) {
9354:     *set = PETSC_TRUE;
9355:     *compatible = PETSC_TRUE;
9356:     return(0);
9357:   }

9359:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9360:      communicator. Note that this does not preclude compatibility with
9361:      DMs living on "congruent" or "similar" communicators, but this must be
9362:      determined by the implementation-specific logic */
9363:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9364:   if (compareResult == MPI_UNEQUAL) {
9365:     *set = PETSC_TRUE;
9366:     *compatible = PETSC_FALSE;
9367:     return(0);
9368:   }

9370:   /* Pass to the implementation-specific routine, if one exists. */
9371:   if (dm1->ops->getcompatibility) {
9372:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9373:     if (*set) return(0);
9374:   }

9376:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9377:      with an implementation of this function from dm2 */
9378:   DMGetType(dm1,&type);
9379:   DMGetType(dm2,&type2);
9380:   PetscStrcmp(type,type2,&sameType);
9381:   if (!sameType && dm2->ops->getcompatibility) {
9382:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9383:   } else {
9384:     *set = PETSC_FALSE;
9385:   }
9386:   return(0);
9387: }

9389: /*@C
9390:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

9392:   Logically Collective on DM

9394:   Input Parameters:
9395: + DM - the DM
9396: . f - the monitor function
9397: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9398: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

9400:   Options Database Keys:
9401: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9402:                             does not cancel those set via the options database.

9404:   Notes:
9405:   Several different monitoring routines may be set by calling
9406:   DMMonitorSet() multiple times; all will be called in the
9407:   order in which they were set.

9409:   Fortran Notes:
9410:   Only a single monitor function can be set for each DM object

9412:   Level: intermediate

9414: .seealso: DMMonitorCancel()
9415: @*/
9416: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9417: {
9418:   PetscInt       m;

9423:   for (m = 0; m < dm->numbermonitors; ++m) {
9424:     PetscBool identical;

9426:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9427:     if (identical) return(0);
9428:   }
9429:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9430:   dm->monitor[dm->numbermonitors]          = f;
9431:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9432:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9433:   return(0);
9434: }

9436: /*@
9437:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9439:   Logically Collective on DM

9441:   Input Parameter:
9442: . dm - the DM

9444:   Options Database Key:
9445: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9446:   into a code by calls to DMonitorSet(), but does not cancel those
9447:   set via the options database

9449:   Notes:
9450:   There is no way to clear one specific monitor from a DM object.

9452:   Level: intermediate

9454: .seealso: DMMonitorSet()
9455: @*/
9456: PetscErrorCode DMMonitorCancel(DM dm)
9457: {
9459:   PetscInt       m;

9463:   for (m = 0; m < dm->numbermonitors; ++m) {
9464:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9465:   }
9466:   dm->numbermonitors = 0;
9467:   return(0);
9468: }

9470: /*@C
9471:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9473:   Collective on DM

9475:   Input Parameters:
9476: + dm   - DM object you wish to monitor
9477: . name - the monitor type one is seeking
9478: . help - message indicating what monitoring is done
9479: . manual - manual page for the monitor
9480: . monitor - the monitor function
9481: - 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

9483:   Output Parameter:
9484: . flg - Flag set if the monitor was created

9486:   Level: developer

9488: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9489:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9490:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9491:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9492:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9493:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9494:           PetscOptionsFList(), PetscOptionsEList()
9495: @*/
9496: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9497: {
9498:   PetscViewer       viewer;
9499:   PetscViewerFormat format;
9500:   PetscErrorCode    ierr;

9504:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9505:   if (*flg) {
9506:     PetscViewerAndFormat *vf;

9508:     PetscViewerAndFormatCreate(viewer, format, &vf);
9509:     PetscObjectDereference((PetscObject) viewer);
9510:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9511:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9512:   }
9513:   return(0);
9514: }

9516: /*@
9517:    DMMonitor - runs the user provided monitor routines, if they exist

9519:    Collective on DM

9521:    Input Parameters:
9522: .  dm - The DM

9524:    Level: developer

9526: .seealso: DMMonitorSet()
9527: @*/
9528: PetscErrorCode DMMonitor(DM dm)
9529: {
9530:   PetscInt       m;

9534:   if (!dm) return(0);
9536:   for (m = 0; m < dm->numbermonitors; ++m) {
9537:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9538:   }
9539:   return(0);
9540: }

9542: /*@
9543:   DMComputeError - Computes the error assuming the user has given exact solution functions

9545:   Collective on DM

9547:   Input Parameters:
9548: + dm     - The DM
9549: - sol    - The solution vector

9551:   Input/Output Parameter:
9552: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9553:            contains the error in each field

9555:   Output Parameter:
9556: . errorVec - A vector to hold the cellwise error (may be NULL)

9558:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

9560:   Level: developer

9562: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9563: @*/
9564: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9565: {
9566:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9567:   void            **ctxs;
9568:   PetscReal         time;
9569:   PetscInt          Nf, f, Nds, s;
9570:   PetscErrorCode    ierr;

9573:   DMGetNumFields(dm, &Nf);
9574:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9575:   DMGetNumDS(dm, &Nds);
9576:   for (s = 0; s < Nds; ++s) {
9577:     PetscDS         ds;
9578:     DMLabel         label;
9579:     IS              fieldIS;
9580:     const PetscInt *fields;
9581:     PetscInt        dsNf;

9583:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9584:     PetscDSGetNumFields(ds, &dsNf);
9585:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9586:     for (f = 0; f < dsNf; ++f) {
9587:       const PetscInt field = fields[f];
9588:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9589:     }
9590:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9591:   }
9592:   for (f = 0; f < Nf; ++f) {
9593:     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);
9594:   }
9595:   DMGetOutputSequenceNumber(dm, NULL, &time);
9596:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9597:   if (errorVec) {
9598:     DM             edm;
9599:     DMPolytopeType ct;
9600:     PetscBool      simplex;
9601:     PetscInt       dim, cStart, Nf;

9603:     DMClone(dm, &edm);
9604:     DMGetDimension(edm, &dim);
9605:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9606:     DMPlexGetCellType(dm, cStart, &ct);
9607:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9608:     DMGetNumFields(dm, &Nf);
9609:     for (f = 0; f < Nf; ++f) {
9610:       PetscFE         fe, efe;
9611:       PetscQuadrature q;
9612:       const char     *name;

9614:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
9615:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9616:       PetscObjectGetName((PetscObject) fe, &name);
9617:       PetscObjectSetName((PetscObject) efe, name);
9618:       PetscFEGetQuadrature(fe, &q);
9619:       PetscFESetQuadrature(efe, q);
9620:       DMSetField(edm, f, NULL, (PetscObject) efe);
9621:       PetscFEDestroy(&efe);
9622:     }
9623:     DMCreateDS(edm);

9625:     DMCreateGlobalVector(edm, errorVec);
9626:     PetscObjectSetName((PetscObject) *errorVec, "Error");
9627:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9628:     DMDestroy(&edm);
9629:   }
9630:   PetscFree2(exactSol, ctxs);
9631:   return(0);
9632: }

9634: /*@
9635:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

9637:   Not collective

9639:   Input Parameter:
9640: . dm     - The DM

9642:   Output Parameter:
9643: . numAux - The number of auxiliary data vectors

9645:   Level: advanced

9647: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9648: @*/
9649: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9650: {

9655:   PetscHMapAuxGetSize(dm->auxData, numAux);
9656:   return(0);
9657: }

9659: /*@
9660:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value

9662:   Not collective

9664:   Input Parameters:
9665: + dm     - The DM
9666: . label  - The DMLabel
9667: - value  - The label value indicating the region

9669:   Output Parameter:
9670: . aux    - The Vec holding auxiliary field data

9672:   Note: If no auxiliary vector is found for this (label, value), (NULL, 0) is checked as well.

9674:   Level: advanced

9676: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9677: @*/
9678: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec *aux)
9679: {
9680:   PetscHashAuxKey key, wild = {NULL, 0};
9681:   PetscBool       has;
9682:   PetscErrorCode  ierr;

9687:   key.label = label;
9688:   key.value = value;
9689:   PetscHMapAuxHas(dm->auxData, key, &has);
9690:   if (has) {PetscHMapAuxGet(dm->auxData, key,  aux);}
9691:   else     {PetscHMapAuxGet(dm->auxData, wild, aux);}
9692:   return(0);
9693: }

9695: /*@
9696:   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value

9698:   Not collective

9700:   Input Parameters:
9701: + dm     - The DM
9702: . label  - The DMLabel
9703: . value  - The label value indicating the region
9704: - aux    - The Vec holding auxiliary field data

9706:   Level: advanced

9708: .seealso: DMGetAuxiliaryVec()
9709: @*/
9710: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec aux)
9711: {
9712:   Vec             old;
9713:   PetscHashAuxKey key;
9714:   PetscErrorCode  ierr;

9719:   key.label = label;
9720:   key.value = value;
9721:   PetscHMapAuxGet(dm->auxData, key, &old);
9722:   PetscObjectReference((PetscObject) aux);
9723:   PetscObjectDereference((PetscObject) old);
9724:   if (!aux) {PetscHMapAuxDel(dm->auxData, key);}
9725:   else      {PetscHMapAuxSet(dm->auxData, key, aux);}
9726:   return(0);
9727: }

9729: /*@C
9730:   DMGetAuxiliaryLabels - Get the labels and values for all auxiliary vectors in this DM

9732:   Not collective

9734:   Input Parameter:
9735: . dm      - The DM

9737:   Output Parameters:
9738: + labels  - The DMLabels for each Vec
9739: - values  - The label values for each Vec

9741:   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().

9743:   Level: advanced

9745: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9746: @*/
9747: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[])
9748: {
9749:   PetscHashAuxKey *keys;
9750:   PetscInt         n, i, off = 0;
9751:   PetscErrorCode   ierr;

9757:   DMGetNumAuxiliaryVec(dm, &n);
9758:   PetscMalloc1(n, &keys);
9759:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
9760:   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value;}
9761:   PetscFree(keys);
9762:   return(0);
9763: }

9765: /*@
9766:   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM

9768:   Not collective

9770:   Input Parameter:
9771: . dm    - The DM

9773:   Output Parameter:
9774: . dmNew - The new DM, now with the same auxiliary data

9776:   Level: advanced

9778: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9779: @*/
9780: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9781: {

9786:   PetscHMapAuxDestroy(&dmNew->auxData);
9787:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
9788:   return(0);
9789: }

9791: /*@C
9792:   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

9794:   Not collective

9796:   Input Parameters:
9797: + ct         - The DMPolytopeType
9798: . sourceCone - The source arrangement of faces
9799: - targetCone - The target arrangement of faces

9801:   Output Parameters:
9802: + ornt  - The orientation which will take the source arrangement to the target arrangement
9803: - found - Flag indicating that a suitable orientation was found

9805:   Level: advanced

9807: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
9808: @*/
9809: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9810: {
9811:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9812:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9813:   PetscInt       o, c;

9816:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9817:   for (o = -nO; o < nO; ++o) {
9818:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

9820:     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9821:     if (c == cS) {*ornt = o; break;}
9822:   }
9823:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9824:   return(0);
9825: }

9827: /*@C
9828:   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

9830:   Not collective

9832:   Input Parameters:
9833: + ct         - The DMPolytopeType
9834: . sourceCone - The source arrangement of faces
9835: - targetCone - The target arrangement of faces

9837:   Output Parameters:
9838: . ornt  - The orientation which will take the source arrangement to the target arrangement

9840:   Note: This function will fail if no suitable orientation can be found.

9842:   Level: advanced

9844: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
9845: @*/
9846: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9847: {
9848:   PetscBool      found;

9852:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
9853:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9854:   return(0);
9855: }

9857: /*@C
9858:   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

9860:   Not collective

9862:   Input Parameters:
9863: + ct         - The DMPolytopeType
9864: . sourceVert - The source arrangement of vertices
9865: - targetVert - The target arrangement of vertices

9867:   Output Parameters:
9868: + ornt  - The orientation which will take the source arrangement to the target arrangement
9869: - found - Flag indicating that a suitable orientation was found

9871:   Level: advanced

9873: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
9874: @*/
9875: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9876: {
9877:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9878:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9879:   PetscInt       o, c;

9882:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9883:   for (o = -nO; o < nO; ++o) {
9884:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

9886:     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9887:     if (c == cS) {*ornt = o; break;}
9888:   }
9889:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9890:   return(0);
9891: }

9893: /*@C
9894:   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

9896:   Not collective

9898:   Input Parameters:
9899: + ct         - The DMPolytopeType
9900: . sourceCone - The source arrangement of vertices
9901: - targetCone - The target arrangement of vertices

9903:   Output Parameters:
9904: . ornt  - The orientation which will take the source arrangement to the target arrangement

9906:   Note: This function will fail if no suitable orientation can be found.

9908:   Level: advanced

9910: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
9911: @*/
9912: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9913: {
9914:   PetscBool      found;

9918:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
9919:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9920:   return(0);
9921: }

9923: /*@C
9924:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

9926:   Not collective

9928:   Input Parameters:
9929: + ct    - The DMPolytopeType
9930: - point - Coordinates of the point

9932:   Output Parameters:
9933: . inside  - Flag indicating whether the point is inside the reference cell of given type

9935:   Level: advanced

9937: .seealso: DMLocatePoints()
9938: @*/
9939: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9940: {
9941:   PetscReal sum = 0.0;
9942:   PetscInt  d;

9945:   *inside = PETSC_TRUE;
9946:   switch (ct) {
9947:   case DM_POLYTOPE_TRIANGLE:
9948:   case DM_POLYTOPE_TETRAHEDRON:
9949:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9950:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
9951:       sum += point[d];
9952:     }
9953:     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9954:     break;
9955:   case DM_POLYTOPE_QUADRILATERAL:
9956:   case DM_POLYTOPE_HEXAHEDRON:
9957:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9958:       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9959:     break;
9960:   default:
9961:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9962:   }
9963:   return(0);
9964: }