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) ltog[k] = ltog[l]/bs;
1125:         n /= bs;
1126:       }
1127:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1128:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1129:     } else {
1130:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
1131:       (*dm->ops->getlocaltoglobalmapping)(dm);
1132:     }
1133:   }
1134:   *ltog = dm->ltogmap;
1135:   return(0);
1136: }

1138: /*@
1139:    DMGetBlockSize - Gets the inherent block size associated with a DM

1141:    Not Collective

1143:    Input Parameter:
1144: .  dm - the DM with block structure

1146:    Output Parameter:
1147: .  bs - the block size, 1 implies no exploitable block structure

1149:    Level: intermediate

1151: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1152: @*/
1153: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1154: {
1158:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1159:   *bs = dm->bs;
1160:   return(0);
1161: }

1163: /*@C
1164:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1166:     Collective on dmc

1168:     Input Parameters:
1169: +   dmc - the DM object
1170: -   dmf - the second, finer DM object

1172:     Output Parameters:
1173: +  mat - the interpolation
1174: -  vec - the scaling (optional)

1176:     Level: developer

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

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

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

1187: @*/
1188: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1189: {

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

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

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

1211:   Output Parameter:
1212: .    scale - the scaled vector

1214:   Level: developer

1216: .seealso: DMCreateInterpolation()

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

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

1235: /*@
1236:     DMCreateRestriction - Gets restriction matrix between two DM objects

1238:     Collective on dmc

1240:     Input Parameters:
1241: +   dmc - the DM object
1242: -   dmf - the second, finer DM object

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

1247:     Level: developer

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

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

1255: @*/
1256: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1257: {

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

1271: /*@
1272:     DMCreateInjection - Gets injection matrix between two DM objects

1274:     Collective on dac

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

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

1283:     Level: developer

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

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

1291: @*/
1292: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1293: {

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

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

1310:   Collective on dac

1312:   Input Parameters:
1313: + dac - the DM object
1314: - daf - the second, finer DM object

1316:   Output Parameter:
1317: . mat - the interpolation

1319:   Level: developer

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

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

1336: /*@
1337:     DMCreateColoring - Gets coloring for a DM

1339:     Collective on dm

1341:     Input Parameters:
1342: +   dm - the DM object
1343: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1345:     Output Parameter:
1346: .   coloring - the coloring

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

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

1354:     Level: developer

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

1358: @*/
1359: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1360: {

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

1371: /*@
1372:     DMCreateMatrix - Gets empty Jacobian for a DM

1374:     Collective on dm

1376:     Input Parameter:
1377: .   dm - the DM object

1379:     Output Parameter:
1380: .   mat - the empty Jacobian

1382:     Level: beginner

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

1387:     Notes:
1388:     This properly preallocates the number of nonzeros in the sparse matrix so you
1389:        do not need to do it yourself.

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

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

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

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

1402: @*/
1403: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1404: {

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

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

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

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

1450:   Logically Collective on dm

1452:   Input Parameters:
1453: + dm - the DM
1454: - only - PETSC_TRUE if only want preallocation

1456:   Level: developer

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

1461: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1462: @*/
1463: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1464: {
1467:   dm->prealloc_only = only;
1468:   return(0);
1469: }

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

1475:   Logically Collective on dm

1477:   Input Parameters:
1478: + dm - the DM
1479: - only - PETSC_TRUE if only want matrix stucture

1481:   Level: developer
1482: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1483: @*/
1484: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1485: {
1488:   dm->structure_only = only;
1489:   return(0);
1490: }

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

1495:   Not Collective

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

1502:   Output Parameter:
1503: . array - the work array

1505:   Level: developer

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

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

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

1543:   Not Collective

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

1550:   Output Parameter:
1551: . array - the work array

1553:   Level: developer

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

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

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

1581:   Logically collective on DM

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

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

1596:   This function is currently not available from Fortran.

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

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

1612:   Not collective

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

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

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

1629:   This function is currently not available from Fortran.

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

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

1646:   Logically collective on DM

1648:   Input Parameters:
1649: + dm     - The DM
1650: . field  - The field number for the nullspace
1651: - nullsp - A callback to create the near-nullspace

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

1661:   This function is currently not available from Fortran.

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

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

1677:   Not collective

1679:   Input Parameters:
1680: + dm     - The DM
1681: - field  - The field number for the nullspace

1683:   Output Parameter:
1684: . nullsp - A callback to create the near-nullspace

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

1694:   This function is currently not available from Fortran.

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

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

1711:   Not collective

1713:   Input Parameter:
1714: . dm - the DM object

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

1721:   Level: intermediate

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

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

1737:   if (numFields) {
1739:     *numFields = 0;
1740:   }
1741:   if (fieldNames) {
1743:     *fieldNames = NULL;
1744:   }
1745:   if (fields) {
1747:     *fields = NULL;
1748:   }
1749:   DMGetLocalSection(dm, &section);
1750:   if (section) {
1751:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1752:     PetscInt nF, f, pStart, pEnd, p;

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

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

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

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

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

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

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

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

1838:   Not collective

1840:   Input Parameter:
1841: . dm - the DM object

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

1849:   Level: intermediate

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

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

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

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

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

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

1921:   Not collective

1923:   Input Parameters:
1924: + dm        - The DM object
1925: . numFields - The number of fields in this subproblem
1926: - fields    - The field numbers of the selected fields

1928:   Output Parameters:
1929: + is - The global indices for the subproblem
1930: - subdm - The DM for the subproblem

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

1934:   Level: intermediate

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

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

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

1955:   Not collective

1957:   Input Parameters:
1958: + dms - The DM objects
1959: - len - The number of DMs

1961:   Output Parameters:
1962: + is - The global indices for the subproblem, or NULL
1963: - superdm - The DM for the superproblem

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

1967:   Level: intermediate

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

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

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

1997:   Not collective

1999:   Input Parameter:
2000: . dm - the DM object

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

2009:   Level: intermediate

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

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

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

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

2056:   Not collective

2058:   Input Parameters:
2059: + dm - the DM object
2060: . n  - the number of subdomain scatters
2061: - subdms - the local subdomains

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

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

2074:   Level: developer

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

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

2090: /*@
2091:   DMRefine - Refines a DM object

2093:   Collective on dm

2095:   Input Parameters:
2096: + dm   - the DM object
2097: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2099:   Output Parameter:
2100: . dmf - the refined DM, or NULL

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

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

2107:   Level: developer

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

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

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

2126:     (*dmf)->ctx       = dm->ctx;
2127:     (*dmf)->leveldown = dm->leveldown;
2128:     (*dmf)->levelup   = dm->levelup + 1;

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

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

2144:    Logically Collective

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

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

2155: +  coarse - coarse level DM
2156: .  fine - fine level DM to interpolate problem to
2157: -  ctx - optional user-defined function context

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

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

2167:    Level: advanced

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

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

2174:    This function is currently not available from Fortran.

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

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

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

2200:    Logically Collective

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

2208:    Level: advanced

2210:    Notes:
2211:    This function does nothing if the hook is not in the list.

2213:    This function is currently not available from Fortran.

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

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

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

2238:    Collective if any hooks are

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

2245:    Level: developer

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

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

2263: /*@
2264:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2266:    Collective on DM

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

2276:    Output Parameter:
2277: .  fineSol - the interpolation of coarseSol to the fine mesh

2279:    Level: developer

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

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


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

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

2311:     Not Collective

2313:     Input Parameter:
2314: .   dm - the DM object

2316:     Output Parameter:
2317: .   level - number of refinements

2319:     Level: developer

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

2323: @*/
2324: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2325: {
2328:   *level = dm->levelup;
2329:   return(0);
2330: }

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

2335:     Not Collective

2337:     Input Parameters:
2338: +   dm - the DM object
2339: -   level - number of refinements

2341:     Level: advanced

2343:     Notes:
2344:     This value is used by PCMG to determine how many multigrid levels to use

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

2348: @*/
2349: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2350: {
2353:   dm->levelup = level;
2354:   return(0);
2355: }

2357: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2358: {
2362:   *tdm = dm->transformDM;
2363:   return(0);
2364: }

2366: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2367: {
2371:   *tv = dm->transform;
2372:   return(0);
2373: }

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

2378:   Input Parameter:
2379: . dm - The DM

2381:   Output Parameter:
2382: . flg - PETSC_TRUE if a basis transformation should be done

2384:   Level: developer

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

2396:   DMGetBasisTransformVec_Internal(dm, &tv);
2397:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2398:   return(0);
2399: }

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

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

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

2450: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2451: {

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

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

2468:    Logically Collective

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

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

2479: +  dm - global DM
2480: .  g - global vector
2481: .  mode - mode
2482: .  l - local vector
2483: -  ctx - optional user-defined function context

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

2488: +  global - global DM
2489: -  ctx - optional user-defined function context

2491:    Level: advanced

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

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

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

2522:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2523:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2524:     PetscInt nRows;

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

2545: /*@
2546:     DMGlobalToLocal - update local vectors from global vector

2548:     Neighbor-wise Collective on dm

2550:     Input Parameters:
2551: +   dm - the DM object
2552: .   g - the global vector
2553: .   mode - INSERT_VALUES or ADD_VALUES
2554: -   l - the local vector

2556:     Notes:
2557:     The communication involved in this update can be overlapped with computation by using
2558:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2560:     Level: beginner

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

2564: @*/
2565: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2566: {

2570:   DMGlobalToLocalBegin(dm,g,mode,l);
2571:   DMGlobalToLocalEnd(dm,g,mode,l);
2572:   return(0);
2573: }

2575: /*@
2576:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2578:     Neighbor-wise Collective on dm

2580:     Input Parameters:
2581: +   dm - the DM object
2582: .   g - the global vector
2583: .   mode - INSERT_VALUES or ADD_VALUES
2584: -   l - the local vector

2586:     Level: intermediate

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

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

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

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

2623: /*@
2624:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2626:     Neighbor-wise Collective on dm

2628:     Input Parameters:
2629: +   dm - the DM object
2630: .   g - the global vector
2631: .   mode - INSERT_VALUES or ADD_VALUES
2632: -   l - the local vector

2634:     Level: intermediate

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

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

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

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

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

2676:    Logically Collective

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

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

2687: +  dm - global DM
2688: .  l - local vector
2689: .  mode - mode
2690: .  g - global vector
2691: -  ctx - optional user-defined function context

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

2696: +  global - global DM
2697: .  l - local vector
2698: .  mode - mode
2699: .  g - global vector
2700: -  ctx - optional user-defined function context

2702:    Level: advanced

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

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

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

2733:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2734:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2735:     PetscInt nRows;

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

2764:     Neighbor-wise Collective on dm

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

2772:     Notes:
2773:     The communication involved in this update can be overlapped with computation by using
2774:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2779:     Level: beginner

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

2783: @*/
2784: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2785: {

2789:   DMLocalToGlobalBegin(dm,l,mode,g);
2790:   DMLocalToGlobalEnd(dm,l,mode,g);
2791:   return(0);
2792: }

2794: /*@
2795:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2797:     Neighbor-wise Collective on dm

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

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

2809:     Level: intermediate

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

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

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

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

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

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

2923: /*@
2924:     DMLocalToGlobalEnd - updates global vectors from local vectors

2926:     Neighbor-wise Collective on dm

2928:     Input Parameters:
2929: +   dm - the DM object
2930: .   l - the local vector
2931: .   mode - INSERT_VALUES or ADD_VALUES
2932: -   g - the global vector

2934:     Level: intermediate

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

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

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

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

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

2998:    Neighbor-wise Collective on dm

3000:    Input Parameters:
3001: +  dm - the DM object
3002: .  g - the original local vector
3003: -  mode - one of INSERT_VALUES or ADD_VALUES

3005:    Output Parameter:
3006: .  l  - the local vector with correct ghost values

3008:    Level: intermediate

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

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

3018: @*/
3019: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
3020: {
3021:   PetscErrorCode          ierr;

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

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

3035:    Neighbor-wise Collective on dm

3037:    Input Parameters:
3038: +  da - the DM object
3039: .  g - the original local vector
3040: -  mode - one of INSERT_VALUES or ADD_VALUES

3042:    Output Parameter:
3043: .  l  - the local vector with correct ghost values

3045:    Level: intermediate

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

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

3055: @*/
3056: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3057: {
3058:   PetscErrorCode          ierr;

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

3067: /*@
3068:     DMCoarsen - Coarsens a DM object

3070:     Collective on dm

3072:     Input Parameters:
3073: +   dm - the DM object
3074: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

3076:     Output Parameter:
3077: .   dmc - the coarsened DM

3079:     Level: developer

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

3083: @*/
3084: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3085: {
3086:   PetscErrorCode    ierr;
3087:   DMCoarsenHookLink link;

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

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

3114:    Logically Collective

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

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

3125: +  fine - fine level DM
3126: .  coarse - coarse level DM to restrict problem to
3127: -  ctx - optional user-defined function context

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

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

3139:    Level: advanced

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

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

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

3149:    This function is currently not available from Fortran.

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

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

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

3175:    Logically Collective

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

3183:    Level: advanced

3185:    Notes:
3186:    This function does nothing if the hook is not in the list.

3188:    This function is currently not available from Fortran.

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

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

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

3213:    Collective if any hooks are

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

3222:    Level: developer

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

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

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

3243:    Logically Collective on global

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

3251:    Calling sequence for ddhook:
3252: $    ddhook(DM global,DM block,void *ctx)

3254: +  global - global DM
3255: .  block  - block DM
3256: -  ctx - optional user-defined function context

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

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

3267:    Level: advanced

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

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

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

3277:    This function is currently not available from Fortran.

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

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

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

3303:    Logically Collective

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

3311:    Level: advanced

3313:    Notes:

3315:    This function is currently not available from Fortran.

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

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

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

3340:    Collective if any hooks are

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

3348:    Level: developer

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

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

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

3369:     Not Collective

3371:     Input Parameter:
3372: .   dm - the DM object

3374:     Output Parameter:
3375: .   level - number of coarsenings

3377:     Level: developer

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

3381: @*/
3382: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3383: {
3387:   *level = dm->leveldown;
3388:   return(0);
3389: }

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

3394:     Not Collective

3396:     Input Parameters:
3397: +   dm - the DM object
3398: -   level - number of coarsenings

3400:     Level: developer

3402: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3403: @*/
3404: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3405: {
3408:   dm->leveldown = level;
3409:   return(0);
3410: }

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

3415:     Collective on dm

3417:     Input Parameters:
3418: +   dm - the DM object
3419: -   nlevels - the number of levels of refinement

3421:     Output Parameter:
3422: .   dmf - the refined DM hierarchy

3424:     Level: developer

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

3428: @*/
3429: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3430: {

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

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

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

3454:     Collective on dm

3456:     Input Parameters:
3457: +   dm - the DM object
3458: -   nlevels - the number of levels of coarsening

3460:     Output Parameter:
3461: .   dmc - the coarsened DM hierarchy

3463:     Level: developer

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

3467: @*/
3468: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3469: {

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

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

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

3493:     Not Collective

3495:     Input Parameters:
3496: +   dm - the DM object
3497: -   destroy - the destroy function

3499:     Level: intermediate

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

3503: @*/
3504: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3505: {
3508:   dm->ctxdestroy = destroy;
3509:   return(0);
3510: }

3512: /*@
3513:     DMSetApplicationContext - Set a user context into a DM object

3515:     Not Collective

3517:     Input Parameters:
3518: +   dm - the DM object
3519: -   ctx - the user context

3521:     Level: intermediate

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

3525: @*/
3526: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3527: {
3530:   dm->ctx = ctx;
3531:   return(0);
3532: }

3534: /*@
3535:     DMGetApplicationContext - Gets a user context from a DM object

3537:     Not Collective

3539:     Input Parameter:
3540: .   dm - the DM object

3542:     Output Parameter:
3543: .   ctx - the user context

3545:     Level: intermediate

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

3549: @*/
3550: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3551: {
3554:   *(void**)ctx = dm->ctx;
3555:   return(0);
3556: }

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

3561:     Logically Collective on dm

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

3567:     Level: intermediate

3569: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3570:          DMSetJacobian()

3572: @*/
3573: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3574: {
3577:   dm->ops->computevariablebounds = f;
3578:   return(0);
3579: }

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

3584:     Not Collective

3586:     Input Parameter:
3587: .   dm - the DM object to destroy

3589:     Output Parameter:
3590: .   flg - PETSC_TRUE if the variable bounds function exists

3592:     Level: developer

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

3596: @*/
3597: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3598: {
3602:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3603:   return(0);
3604: }

3606: /*@C
3607:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3609:     Logically Collective on dm

3611:     Input Parameter:
3612: .   dm - the DM object

3614:     Output parameters:
3615: +   xl - lower bound
3616: -   xu - upper bound

3618:     Level: advanced

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

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

3625: @*/
3626: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3627: {

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

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

3642:     Not Collective

3644:     Input Parameter:
3645: .   dm - the DM object

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

3650:     Level: developer

3652: .seealso DMCreateColoring()

3654: @*/
3655: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3656: {
3660:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3661:   return(0);
3662: }

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

3667:     Not Collective

3669:     Input Parameter:
3670: .   dm - the DM object

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

3675:     Level: developer

3677: .seealso DMCreateRestriction()

3679: @*/
3680: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3681: {
3685:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3686:   return(0);
3687: }

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

3692:     Not Collective

3694:     Input Parameter:
3695: .   dm - the DM object

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

3700:     Level: developer

3702: .seealso DMCreateInjection()

3704: @*/
3705: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3706: {

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

3720: PetscFunctionList DMList              = NULL;
3721: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3723: /*@C
3724:   DMSetType - Builds a DM, for a particular DM implementation.

3726:   Collective on dm

3728:   Input Parameters:
3729: + dm     - The DM object
3730: - method - The name of the DM type

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

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

3738:   Level: intermediate

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

3750:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3751:   if (match) return(0);

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

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

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

3769:   Not Collective

3771:   Input Parameter:
3772: . dm  - The DM

3774:   Output Parameter:
3775: . type - The DM type name

3777:   Level: intermediate

3779: .seealso: DMSetType(), DMCreate()
3780: @*/
3781: PetscErrorCode  DMGetType(DM dm, DMType *type)
3782: {

3788:   DMRegisterAll();
3789:   *type = ((PetscObject)dm)->type_name;
3790:   return(0);
3791: }

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

3796:   Collective on dm

3798:   Input Parameters:
3799: + dm - the DM
3800: - newtype - new DM type (use "same" for the same type)

3802:   Output Parameter:
3803: . M - pointer to new DM

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

3810:   Level: intermediate

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

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

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

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

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

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

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

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

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

3904: /*--------------------------------------------------------------------------------------------------------------------*/

3906: /*@C
3907:   DMRegister -  Adds a new DM component implementation

3909:   Not Collective

3911:   Input Parameters:
3912: + name        - The name of a new user-defined creation routine
3913: - create_func - The creation routine itself

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

3918:   Sample usage:
3919: .vb
3920:     DMRegister("my_da", MyDMCreate);
3921: .ve

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

3933:   Level: advanced

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

3937: @*/
3938: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3939: {

3943:   DMInitializePackage();
3944:   PetscFunctionListAdd(&DMList,sname,function);
3945:   return(0);
3946: }

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

3951:   Collective on viewer

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

3959:    Level: intermediate

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

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

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

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

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

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

4006:   Not collective

4008:   Input Parameter:
4009: . dm - the DM

4011:   Output Parameters:
4012: + lmin - local minimum coordinates (length coord dim, optional)
4013: - lmax - local maximim coordinates (length coord dim, optional)

4015:   Level: beginner

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

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

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

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

4057: /*@
4058:   DMGetBoundingBox - Returns the global bounding box for the DM.

4060:   Collective

4062:   Input Parameter:
4063: . dm - the DM

4065:   Output Parameters:
4066: + gmin - global minimum coordinates (length coord dim, optional)
4067: - gmax - global maximim coordinates (length coord dim, optional)

4069:   Level: beginner

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

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

4090: /******************************** FEM Support **********************************/

4092: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4093: {
4094:   PetscInt       f;

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

4105: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4106: {
4107:   PetscInt       f, g;

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

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

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

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

4156:   Input Parameter:
4157: . dm - The DM

4159:   Output Parameter:
4160: . section - The PetscSection

4162:   Options Database Keys:
4163: . -dm_petscsection_view - View the Section created by the DM

4165:   Level: advanced

4167:   Notes:
4168:   Use DMGetLocalSection() in new code.

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

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

4179:   DMGetLocalSection(dm,section);
4180:   return(0);
4181: }

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

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

4189:   Output Parameter:
4190: . section - The PetscSection

4192:   Options Database Keys:
4193: . -dm_petscsection_view - View the Section created by the DM

4195:   Level: intermediate

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

4199: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4200: @*/
4201: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4202: {

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

4211:     if (dm->setfromoptionscalled) {
4212:       PetscObject       obj = (PetscObject) dm;
4213:       PetscViewer       viewer;
4214:       PetscViewerFormat format;
4215:       PetscBool         flg;

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

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

4239:   Input Parameters:
4240: + dm - The DM
4241: - section - The PetscSection

4243:   Level: advanced

4245:   Notes:
4246:   Use DMSetLocalSection() in new code.

4248:   Any existing Section will be destroyed

4250: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4251: @*/
4252: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4253: {

4257:   DMSetLocalSection(dm,section);
4258:   return(0);
4259: }

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

4264:   Input Parameters:
4265: + dm - The DM
4266: - section - The PetscSection

4268:   Level: intermediate

4270:   Note: Any existing Section will be destroyed

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

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

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

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

4306:   not collective

4308:   Input Parameter:
4309: . dm - The DM

4311:   Output Parameters:
4312: + 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.
4313: - 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.

4315:   Level: advanced

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

4319: .seealso: DMSetDefaultConstraints()
4320: @*/
4321: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4322: {

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

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

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

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

4340:   collective on dm

4342:   Input Parameters:
4343: + dm - The DM
4344: + 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).
4345: - 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).

4347:   Level: advanced

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

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

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

4379: #if defined(PETSC_USE_DEBUG)
4380: /*
4381:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4383:   Input Parameters:
4384: + dm - The DM
4385: . localSection - PetscSection describing the local data layout
4386: - globalSection - PetscSection describing the global data layout

4388:   Level: intermediate

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

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

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

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

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

4451:   Collective on dm

4453:   Input Parameter:
4454: . dm - The DM

4456:   Output Parameter:
4457: . section - The PetscSection

4459:   Level: intermediate

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

4463: .seealso: DMSetLocalSection(), DMGetLocalSection()
4464: @*/
4465: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4466: {

4472:   if (!dm->globalSection) {
4473:     PetscSection s;

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

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

4490:   Input Parameters:
4491: + dm - The DM
4492: - section - The PetscSection, or NULL

4494:   Level: intermediate

4496:   Note: Any existing Section will be destroyed

4498: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4499: @*/
4500: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4501: {

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

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

4520:   Input Parameter:
4521: . dm - The DM

4523:   Output Parameter:
4524: . sf - The PetscSF

4526:   Level: intermediate

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

4530: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4531: @*/
4532: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4533: {
4534:   PetscInt       nroots;

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

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

4560: /*@
4561:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4563:   Input Parameters:
4564: + dm - The DM
4565: - sf - The PetscSF

4567:   Level: intermediate

4569:   Note: Any previous SF is destroyed

4571: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4572: @*/
4573: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4574: {

4580:   PetscObjectReference((PetscObject) sf);
4581:   PetscSFDestroy(&dm->sectionSF);
4582:   dm->sectionSF = sf;
4583:   return(0);
4584: }

4586: /*@C
4587:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4588:   describing the data layout.

4590:   Input Parameters:
4591: + dm - The DM
4592: . localSection - PetscSection describing the local data layout
4593: - globalSection - PetscSection describing the global data layout

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

4597:   Level: developer

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

4603: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4604: @*/
4605: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4606: {

4611:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4612:   return(0);
4613: }

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

4618:   Input Parameter:
4619: . dm - The DM

4621:   Output Parameter:
4622: . sf - The PetscSF

4624:   Level: intermediate

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

4628: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4629: @*/
4630: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4631: {
4635:   *sf = dm->sf;
4636:   return(0);
4637: }

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

4642:   Input Parameters:
4643: + dm - The DM
4644: - sf - The PetscSF

4646:   Level: intermediate

4648: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4649: @*/
4650: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4651: {

4657:   PetscObjectReference((PetscObject) sf);
4658:   PetscSFDestroy(&dm->sf);
4659:   dm->sf = sf;
4660:   return(0);
4661: }

4663: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4664: {
4665:   PetscClassId   id;

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

4680: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4681: {
4682:   RegionField   *tmpr;
4683:   PetscInt       Nf = dm->Nf, f;

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

4697: /*@
4698:   DMClearFields - Remove all fields from the DM

4700:   Logically collective on dm

4702:   Input Parameter:
4703: . dm - The DM

4705:   Level: intermediate

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

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

4726: /*@
4727:   DMGetNumFields - Get the number of fields in the DM

4729:   Not collective

4731:   Input Parameter:
4732: . dm - The DM

4734:   Output Parameter:
4735: . Nf - The number of fields

4737:   Level: intermediate

4739: .seealso: DMSetNumFields(), DMSetField()
4740: @*/
4741: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4742: {
4746:   *numFields = dm->Nf;
4747:   return(0);
4748: }

4750: /*@
4751:   DMSetNumFields - Set the number of fields in the DM

4753:   Logically collective on dm

4755:   Input Parameters:
4756: + dm - The DM
4757: - Nf - The number of fields

4759:   Level: intermediate

4761: .seealso: DMGetNumFields(), DMSetField()
4762: @*/
4763: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4764: {
4765:   PetscInt       Nf, f;

4770:   DMGetNumFields(dm, &Nf);
4771:   for (f = Nf; f < numFields; ++f) {
4772:     PetscContainer obj;

4774:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4775:     DMAddField(dm, NULL, (PetscObject) obj);
4776:     PetscContainerDestroy(&obj);
4777:   }
4778:   return(0);
4779: }

4781: /*@
4782:   DMGetField - Return the discretization object for a given DM field

4784:   Not collective

4786:   Input Parameters:
4787: + dm - The DM
4788: - f  - The field number

4790:   Output Parameters:
4791: + label - The label indicating the support of the field, or NULL for the entire mesh
4792: - field - The discretization object

4794:   Level: intermediate

4796: .seealso: DMAddField(), DMSetField()
4797: @*/
4798: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4799: {
4803:   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);
4804:   if (label) *label = dm->fields[f].label;
4805:   if (field) *field = dm->fields[f].disc;
4806:   return(0);
4807: }

4809: /* Does not clear the DS */
4810: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4811: {

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

4825: /*@
4826:   DMSetField - Set the discretization object for a given DM field

4828:   Logically collective on dm

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

4836:   Level: intermediate

4838: .seealso: DMAddField(), DMGetField()
4839: @*/
4840: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4841: {

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

4855: /*@
4856:   DMAddField - Add the discretization object for the given DM field

4858:   Logically collective on dm

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

4865:   Level: intermediate

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

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

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

4891:   Logically collective on dm

4893:   Input Parameters:
4894: + dm          - The DM
4895: . f           - The field index
4896: - avoidTensor - The flag to avoid defining the field on tensor cells

4898:   Level: intermediate

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

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

4913:   Logically collective on dm

4915:   Input Parameters:
4916: + dm          - The DM
4917: - f           - The field index

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

4922:   Level: intermediate

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

4934: /*@
4935:   DMCopyFields - Copy the discretizations for the DM into another DM

4937:   Collective on dm

4939:   Input Parameter:
4940: . dm - The DM

4942:   Output Parameter:
4943: . newdm - The DM

4945:   Level: advanced

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

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

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

4971: /*@
4972:   DMGetAdjacency - Returns the flags for determining variable influence

4974:   Not collective

4976:   Input Parameters:
4977: + dm - The DM object
4978: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4980:   Output Parameters:
4981: + useCone    - Flag for variable influence starting with the cone operation
4982: - useClosure - Flag for variable influence using transitive closure

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

4990:   Level: developer

4992: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4993: @*/
4994: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4995: {
5000:   if (f < 0) {
5001:     if (useCone)    *useCone    = dm->adjacency[0];
5002:     if (useClosure) *useClosure = dm->adjacency[1];
5003:   } else {
5004:     PetscInt       Nf;

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

5015: /*@
5016:   DMSetAdjacency - Set the flags for determining variable influence

5018:   Not collective

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

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

5032:   Level: developer

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

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

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

5058:   Not collective

5060:   Input Parameter:
5061: . dm - The DM object

5063:   Output Parameters:
5064: + useCone    - Flag for variable influence starting with the cone operation
5065: - useClosure - Flag for variable influence using transitive closure

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

5072:   Level: developer

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

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

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

5097:   Not collective

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

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

5109:   Level: developer

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

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

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

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

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

5156:       DMConvert(dm, DMPLEX, &plex);
5157:       if (plex) {DMPlexLabelComplete(plex, label);}
5158:       DMDestroy(&plex);
5159:     }
5160:   }
5161:   return(0);
5162: }

5164: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5165: {
5166:   DMSpace       *tmpd;
5167:   PetscInt       Nds = dm->Nds, s;

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

5181: /*@
5182:   DMGetNumDS - Get the number of discrete systems in the DM

5184:   Not collective

5186:   Input Parameter:
5187: . dm - The DM

5189:   Output Parameter:
5190: . Nds - The number of PetscDS objects

5192:   Level: intermediate

5194: .seealso: DMGetDS(), DMGetCellDS()
5195: @*/
5196: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5197: {
5201:   *Nds = dm->Nds;
5202:   return(0);
5203: }

5205: /*@
5206:   DMClearDS - Remove all discrete systems from the DM

5208:   Logically collective on dm

5210:   Input Parameter:
5211: . dm - The DM

5213:   Level: intermediate

5215: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5216: @*/
5217: PetscErrorCode DMClearDS(DM dm)
5218: {
5219:   PetscInt       s;

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

5235: /*@
5236:   DMGetDS - Get the default PetscDS

5238:   Not collective

5240:   Input Parameter:
5241: . dm    - The DM

5243:   Output Parameter:
5244: . prob - The default PetscDS

5246:   Level: intermediate

5248: .seealso: DMGetCellDS(), DMGetRegionDS()
5249: @*/
5250: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5251: {

5257:   if (dm->Nds <= 0) {
5258:     PetscDS ds;

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

5268: /*@
5269:   DMGetCellDS - Get the PetscDS defined on a given cell

5271:   Not collective

5273:   Input Parameters:
5274: + dm    - The DM
5275: - point - Cell for the DS

5277:   Output Parameter:
5278: . prob - The PetscDS defined on the given cell

5280:   Level: developer

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

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

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

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

5311:   Not collective

5313:   Input Parameters:
5314: + dm    - The DM
5315: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5323:   Level: advanced

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

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

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

5349:   Collective on dm

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

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

5360:   Level: advanced

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

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

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

5398:   Not collective

5400:   Input Parameters:
5401: + dm  - The DM
5402: - num - The region number, in [0, Nds)

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

5409:   Level: advanced

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

5420:   DMGetNumDS(dm, &Nds);
5421:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5422:   if (label) {
5424:     *label = dm->probs[num].label;
5425:   }
5426:   if (fields) {
5428:     *fields = dm->probs[num].fields;
5429:   }
5430:   if (ds) {
5432:     *ds = dm->probs[num].ds;
5433:   }
5434:   return(0);
5435: }

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

5440:   Not collective

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

5449:   Level: advanced

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

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

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

5484:   Not collective

5486:   Input Parameters:
5487: + dm  - The DM
5488: - ds  - The PetscDS defined on the given region

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

5493:   Level: advanced

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

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

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

5516:   Collective on dm

5518:   Input Parameter:
5519: . dm - The DM

5521:   Options Database Keys:
5522: . -dm_petscds_view - View all the PetscDS objects in this DM

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

5526:   Level: intermediate

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

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

5552: #ifdef PETSC_HAVE_LIBCEED
5553:     /* Move CEED context to discretizations */
5554:     {
5555:       PetscClassId id;

5557:       PetscObjectGetClassId(dm->fields[f].disc, &id);
5558:       if (id == PETSCFE_CLASSID) {
5559:         Ceed ceed;

5561:         DMGetCeed(dm, &ceed);
5562:         PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
5563:       }
5564:     }
5565: #endif
5566:     if (!label) {++Ndef; continue;}
5567:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5568:     if (l < Nl) continue;
5569:     labelSet[Nl++] = label;
5570:   }
5571:   /* Create default DS if there are no labels to intersect with */
5572:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5573:   if (!dsDef && Ndef && !Nl) {
5574:     IS        fields;
5575:     PetscInt *fld, nf;

5577:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5578:     if (nf) {
5579:       PetscMalloc1(nf, &fld);
5580:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5581:       ISCreate(PETSC_COMM_SELF, &fields);
5582:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5583:       ISSetType(fields, ISGENERAL);
5584:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5586:       PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5587:       DMSetRegionDS(dm, NULL, fields, dsDef);
5588:       PetscDSDestroy(&dsDef);
5589:       ISDestroy(&fields);
5590:     }
5591:   }
5592:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5593:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5594:   /* Intersect labels with default fields */
5595:   if (Ndef && Nl) {
5596:     DM              plex;
5597:     DMLabel         cellLabel;
5598:     IS              fieldIS, allcellIS, defcellIS = NULL;
5599:     PetscInt       *fields;
5600:     const PetscInt *cells;
5601:     PetscInt        depth, nf = 0, n, c;

5603:     DMConvert(dm, DMPLEX, &plex);
5604:     DMPlexGetDepth(plex, &depth);
5605:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5606:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5607:     for (l = 0; l < Nl; ++l) {
5608:       DMLabel label = labelSet[l];
5609:       IS      pointIS;

5611:       ISDestroy(&defcellIS);
5612:       DMLabelGetStratumIS(label, 1, &pointIS);
5613:       ISDifference(allcellIS, pointIS, &defcellIS);
5614:       ISDestroy(&pointIS);
5615:     }
5616:     ISDestroy(&allcellIS);

5618:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5619:     ISGetLocalSize(defcellIS, &n);
5620:     ISGetIndices(defcellIS, &cells);
5621:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5622:     ISRestoreIndices(defcellIS, &cells);
5623:     ISDestroy(&defcellIS);
5624:     DMPlexLabelComplete(plex, cellLabel);

5626:     PetscMalloc1(Ndef, &fields);
5627:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5628:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5629:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5630:     ISSetType(fieldIS, ISGENERAL);
5631:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5633:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5634:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5635:     DMLabelDestroy(&cellLabel);
5636:     PetscDSSetCoordinateDimension(dsDef, dE);
5637:     PetscDSDestroy(&dsDef);
5638:     ISDestroy(&fieldIS);
5639:     DMDestroy(&plex);
5640:   }
5641:   /* Create label DSes
5642:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5643:   */
5644:   /* TODO Should check that labels are disjoint */
5645:   for (l = 0; l < Nl; ++l) {
5646:     DMLabel   label = labelSet[l];
5647:     PetscDS   ds;
5648:     IS        fields;
5649:     PetscInt *fld, nf;

5651:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5652:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5653:     PetscMalloc1(nf, &fld);
5654:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5655:     ISCreate(PETSC_COMM_SELF, &fields);
5656:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5657:     ISSetType(fields, ISGENERAL);
5658:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5659:     DMSetRegionDS(dm, label, fields, ds);
5660:     ISDestroy(&fields);
5661:     PetscDSSetCoordinateDimension(ds, dE);
5662:     {
5663:       DMPolytopeType ct;
5664:       PetscInt       lStart, lEnd;
5665:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5667:       DMLabelGetBounds(label, &lStart, &lEnd);
5668:       if (lStart >= 0) {
5669:         DMPlexGetCellType(dm, lStart, &ct);
5670:         switch (ct) {
5671:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5672:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5673:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5674:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5675:             isHybridLocal = PETSC_TRUE;break;
5676:           default: break;
5677:         }
5678:       }
5679:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5680:       PetscDSSetHybrid(ds, isHybrid);
5681:     }
5682:     PetscDSDestroy(&ds);
5683:   }
5684:   PetscFree(labelSet);
5685:   /* Set fields in DSes */
5686:   for (s = 0; s < dm->Nds; ++s) {
5687:     PetscDS         ds     = dm->probs[s].ds;
5688:     IS              fields = dm->probs[s].fields;
5689:     const PetscInt *fld;
5690:     PetscInt        nf;

5692:     ISGetLocalSize(fields, &nf);
5693:     ISGetIndices(fields, &fld);
5694:     for (f = 0; f < nf; ++f) {
5695:       PetscObject  disc  = dm->fields[fld[f]].disc;
5696:       PetscBool    isHybrid;
5697:       PetscClassId id;

5699:       PetscDSGetHybrid(ds, &isHybrid);
5700:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5701:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5702:       PetscDSSetDiscretization(ds, f, disc);
5703:       /* We allow people to have placeholder fields and construct the Section by hand */
5704:       PetscObjectGetClassId(disc, &id);
5705:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5706:     }
5707:     ISRestoreIndices(fields, &fld);
5708:   }
5709:   /* Allow k-jet tabulation */
5710:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5711:   if (flg) {
5712:     for (s = 0; s < dm->Nds; ++s) {
5713:       PetscDS  ds = dm->probs[s].ds;
5714:       PetscInt Nf, f;

5716:       PetscDSGetNumFields(ds, &Nf);
5717:       for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5718:     }
5719:   }
5720:   /* Setup DSes */
5721:   if (doSetup) {
5722:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5723:   }
5724:   return(0);
5725: }

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

5730:   Collective on DM

5732:   Input Parameters:
5733: + dm   - The DM
5734: - time - The time

5736:   Output Parameters:
5737: + u    - The vector will be filled with exact solution values, or NULL
5738: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5740:   Note: The user must call PetscDSSetExactSolution() beforehand

5742:   Level: developer

5744: .seealso: PetscDSSetExactSolution()
5745: @*/
5746: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5747: {
5748:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5749:   void            **ectxs;
5750:   PetscInt          Nf, Nds, s;
5751:   PetscErrorCode    ierr;

5757:   DMGetNumFields(dm, &Nf);
5758:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5759:   DMGetNumDS(dm, &Nds);
5760:   for (s = 0; s < Nds; ++s) {
5761:     PetscDS         ds;
5762:     DMLabel         label;
5763:     IS              fieldIS;
5764:     const PetscInt *fields, id = 1;
5765:     PetscInt        dsNf, f;

5767:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5768:     PetscDSGetNumFields(ds, &dsNf);
5769:     ISGetIndices(fieldIS, &fields);
5770:     PetscArrayzero(exacts, Nf);
5771:     PetscArrayzero(ectxs, Nf);
5772:     if (u) {
5773:       for (f = 0; f < dsNf; ++f) {
5774:         const PetscInt field = fields[f];
5775:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5776:       }
5777:       ISRestoreIndices(fieldIS, &fields);
5778:       if (label) {
5779:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5780:       } else {
5781:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5782:       }
5783:     }
5784:     if (u_t) {
5785:       PetscArrayzero(exacts, Nf);
5786:       PetscArrayzero(ectxs, Nf);
5787:       for (f = 0; f < dsNf; ++f) {
5788:         const PetscInt field = fields[f];
5789:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5790:       }
5791:       ISRestoreIndices(fieldIS, &fields);
5792:       if (label) {
5793:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5794:       } else {
5795:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5796:       }
5797:     }
5798:   }
5799:   if (u) {
5800:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5801:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5802:   }
5803:   if (u_t) {
5804:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5805:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5806:   }
5807:   PetscFree2(exacts, ectxs);
5808:   return(0);
5809: }

5811: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5812: {
5813:   PetscDS        dsNew;
5814:   DSBoundary     b;
5815:   PetscInt       cdim, Nf, f;
5816:   PetscBool      isHybrid;
5817:   void          *ctx;

5821:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5822:   PetscDSCopyConstants(ds, dsNew);
5823:   PetscDSCopyExactSolutions(ds, dsNew);
5824:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5825:   PetscDSCopyEquations(ds, dsNew);
5826:   PetscDSGetNumFields(ds, &Nf);
5827:   for (f = 0; f < Nf; ++f) {
5828:     PetscDSGetContext(ds, f, &ctx);
5829:     PetscDSSetContext(dsNew, f, ctx);
5830:   }
5831:   if (Nf) {
5832:     PetscDSGetCoordinateDimension(ds, &cdim);
5833:     PetscDSSetCoordinateDimension(dsNew, cdim);
5834:   }
5835:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5836:   for (b = dsNew->boundary; b; b = b->next) {
5837:     DMGetLabel(dm, b->lname, &b->label);
5838:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5839:     //if (!b->label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
5840:   }
5841:   PetscDSGetHybrid(ds, &isHybrid);
5842:   PetscDSSetHybrid(dsNew, isHybrid);

5844:   DMSetRegionDS(dm, label, fields, dsNew);
5845:   PetscDSDestroy(&dsNew);
5846:   return(0);
5847: }

5849: /*@
5850:   DMCopyDS - Copy the discrete systems for the DM into another DM

5852:   Collective on dm

5854:   Input Parameter:
5855: . dm - The DM

5857:   Output Parameter:
5858: . newdm - The DM

5860:   Level: advanced

5862: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5863: @*/
5864: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5865: {
5866:   PetscInt       Nds, s;

5870:   if (dm == newdm) return(0);
5871:   DMGetNumDS(dm, &Nds);
5872:   DMClearDS(newdm);
5873:   for (s = 0; s < Nds; ++s) {
5874:     DMLabel  label;
5875:     IS       fields;
5876:     PetscDS  ds, newds;
5877:     PetscInt Nbd, bd;

5879:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5880:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5881:     DMTransferDS_Internal(newdm, label, fields, ds);
5882:     /* Commplete new labels in the new DS */
5883:     DMGetRegionDS(newdm, label, NULL, &newds);
5884:     PetscDSGetNumBoundary(newds, &Nbd);
5885:     for (bd = 0; bd < Nbd; ++bd) {
5886:       PetscWeakForm wf;
5887:       DMLabel       label;
5888:       PetscInt      field;

5890:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5891:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5892:       PetscWeakFormReplaceLabel(wf, label);
5893:     }
5894:   }
5895:   return(0);
5896: }

5898: /*@
5899:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

5901:   Collective on dm

5903:   Input Parameter:
5904: . dm - The DM

5906:   Output Parameter:
5907: . newdm - The DM

5909:   Level: advanced

5911: .seealso: DMCopyFields(), DMCopyDS()
5912: @*/
5913: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5914: {

5918:   DMCopyFields(dm, newdm);
5919:   DMCopyDS(dm, newdm);
5920:   return(0);
5921: }

5923: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5924: {
5925:   DM dm_coord,dmc_coord;
5927:   Vec coords,ccoords;
5928:   Mat inject;
5930:   DMGetCoordinateDM(dm,&dm_coord);
5931:   DMGetCoordinateDM(dmc,&dmc_coord);
5932:   DMGetCoordinates(dm,&coords);
5933:   DMGetCoordinates(dmc,&ccoords);
5934:   if (coords && !ccoords) {
5935:     DMCreateGlobalVector(dmc_coord,&ccoords);
5936:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5937:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5938:     MatRestrict(inject,coords,ccoords);
5939:     MatDestroy(&inject);
5940:     DMSetCoordinates(dmc,ccoords);
5941:     VecDestroy(&ccoords);
5942:   }
5943:   return(0);
5944: }

5946: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5947: {
5948:   DM dm_coord,subdm_coord;
5950:   Vec coords,ccoords,clcoords;
5951:   VecScatter *scat_i,*scat_g;
5953:   DMGetCoordinateDM(dm,&dm_coord);
5954:   DMGetCoordinateDM(subdm,&subdm_coord);
5955:   DMGetCoordinates(dm,&coords);
5956:   DMGetCoordinates(subdm,&ccoords);
5957:   if (coords && !ccoords) {
5958:     DMCreateGlobalVector(subdm_coord,&ccoords);
5959:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5960:     DMCreateLocalVector(subdm_coord,&clcoords);
5961:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5962:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5963:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5964:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5965:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5966:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5967:     DMSetCoordinates(subdm,ccoords);
5968:     DMSetCoordinatesLocal(subdm,clcoords);
5969:     VecScatterDestroy(&scat_i[0]);
5970:     VecScatterDestroy(&scat_g[0]);
5971:     VecDestroy(&ccoords);
5972:     VecDestroy(&clcoords);
5973:     PetscFree(scat_i);
5974:     PetscFree(scat_g);
5975:   }
5976:   return(0);
5977: }

5979: /*@
5980:   DMGetDimension - Return the topological dimension of the DM

5982:   Not collective

5984:   Input Parameter:
5985: . dm - The DM

5987:   Output Parameter:
5988: . dim - The topological dimension

5990:   Level: beginner

5992: .seealso: DMSetDimension(), DMCreate()
5993: @*/
5994: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5995: {
5999:   *dim = dm->dim;
6000:   return(0);
6001: }

6003: /*@
6004:   DMSetDimension - Set the topological dimension of the DM

6006:   Collective on dm

6008:   Input Parameters:
6009: + dm - The DM
6010: - dim - The topological dimension

6012:   Level: beginner

6014: .seealso: DMGetDimension(), DMCreate()
6015: @*/
6016: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6017: {
6018:   PetscDS        ds;
6019:   PetscInt       Nds, n;

6025:   dm->dim = dim;
6026:   DMGetNumDS(dm, &Nds);
6027:   for (n = 0; n < Nds; ++n) {
6028:     DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6029:     if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
6030:   }
6031:   return(0);
6032: }

6034: /*@
6035:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

6037:   Collective on dm

6039:   Input Parameters:
6040: + dm - the DM
6041: - dim - the dimension

6043:   Output Parameters:
6044: + pStart - The first point of the given dimension
6045: - pEnd - The first point following points of the given dimension

6047:   Note:
6048:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6049:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6050:   then the interval is empty.

6052:   Level: intermediate

6054: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
6055: @*/
6056: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6057: {
6058:   PetscInt       d;

6063:   DMGetDimension(dm, &d);
6064:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
6065:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
6066:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
6067:   return(0);
6068: }

6070: /*@
6071:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

6073:   Collective on dm

6075:   Input Parameters:
6076: + dm - the DM
6077: - c - coordinate vector

6079:   Notes:
6080:   The coordinates do include those for ghost points, which are in the local vector.

6082:   The vector c should be destroyed by the caller.

6084:   Level: intermediate

6086: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6087: @*/
6088: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6089: {

6095:   PetscObjectReference((PetscObject) c);
6096:   VecDestroy(&dm->coordinates);
6097:   dm->coordinates = c;
6098:   VecDestroy(&dm->coordinatesLocal);
6099:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6100:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6101:   return(0);
6102: }

6104: /*@
6105:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

6107:   Not collective

6109:    Input Parameters:
6110: +  dm - the DM
6111: -  c - coordinate vector

6113:   Notes:
6114:   The coordinates of ghost points can be set using DMSetCoordinates()
6115:   followed by DMGetCoordinatesLocal(). This is intended to enable the
6116:   setting of ghost coordinates outside of the domain.

6118:   The vector c should be destroyed by the caller.

6120:   Level: intermediate

6122: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6123: @*/
6124: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6125: {

6131:   PetscObjectReference((PetscObject) c);
6132:   VecDestroy(&dm->coordinatesLocal);

6134:   dm->coordinatesLocal = c;

6136:   VecDestroy(&dm->coordinates);
6137:   return(0);
6138: }

6140: /*@
6141:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

6143:   Collective on dm

6145:   Input Parameter:
6146: . dm - the DM

6148:   Output Parameter:
6149: . c - global coordinate vector

6151:   Note:
6152:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6153:   destroyed the array will no longer be valid.

6155:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

6157:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6158:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6160:   Level: intermediate

6162: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6163: @*/
6164: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6165: {

6171:   if (!dm->coordinates && dm->coordinatesLocal) {
6172:     DM        cdm = NULL;
6173:     PetscBool localized;

6175:     DMGetCoordinateDM(dm, &cdm);
6176:     DMCreateGlobalVector(cdm, &dm->coordinates);
6177:     DMGetCoordinatesLocalized(dm, &localized);
6178:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6179:     if (localized) {
6180:       PetscInt cdim;

6182:       DMGetCoordinateDim(dm, &cdim);
6183:       VecSetBlockSize(dm->coordinates, cdim);
6184:     }
6185:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6186:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6187:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6188:   }
6189:   *c = dm->coordinates;
6190:   return(0);
6191: }

6193: /*@
6194:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

6196:   Collective on dm

6198:   Input Parameter:
6199: . dm - the DM

6201:   Level: advanced

6203: .seealso: DMGetCoordinatesLocalNoncollective()
6204: @*/
6205: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6206: {

6211:   if (!dm->coordinatesLocal && dm->coordinates) {
6212:     DM        cdm = NULL;
6213:     PetscBool localized;

6215:     DMGetCoordinateDM(dm, &cdm);
6216:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6217:     DMGetCoordinatesLocalized(dm, &localized);
6218:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6219:     if (localized) {
6220:       PetscInt cdim;

6222:       DMGetCoordinateDim(dm, &cdim);
6223:       VecSetBlockSize(dm->coordinates, cdim);
6224:     }
6225:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6226:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6227:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6228:   }
6229:   return(0);
6230: }

6232: /*@
6233:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

6235:   Collective on dm

6237:   Input Parameter:
6238: . dm - the DM

6240:   Output Parameter:
6241: . c - coordinate vector

6243:   Note:
6244:   This is a borrowed reference, so the user should NOT destroy this vector

6246:   Each process has the local and ghost coordinates

6248:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6249:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6251:   Level: intermediate

6253: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6254: @*/
6255: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6256: {

6262:   DMGetCoordinatesLocalSetUp(dm);
6263:   *c = dm->coordinatesLocal;
6264:   return(0);
6265: }

6267: /*@
6268:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6270:   Not collective

6272:   Input Parameter:
6273: . dm - the DM

6275:   Output Parameter:
6276: . c - coordinate vector

6278:   Level: advanced

6280: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6281: @*/
6282: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6283: {
6287:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6288:   *c = dm->coordinatesLocal;
6289:   return(0);
6290: }

6292: /*@
6293:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6295:   Not collective

6297:   Input Parameters:
6298: + dm - the DM
6299: - p - the IS of points whose coordinates will be returned

6301:   Output Parameters:
6302: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6303: - pCoord - the Vec with coordinates of points in p

6305:   Note:
6306:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6308:   This creates a new vector, so the user SHOULD destroy this vector

6310:   Each process has the local and ghost coordinates

6312:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6313:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

6315:   Level: advanced

6317: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6318: @*/
6319: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6320: {
6321:   PetscSection        cs, newcs;
6322:   Vec                 coords;
6323:   const PetscScalar   *arr;
6324:   PetscScalar         *newarr=NULL;
6325:   PetscInt            n;
6326:   PetscErrorCode      ierr;

6333:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6334:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6335:   cs = dm->coordinateDM->localSection;
6336:   coords = dm->coordinatesLocal;
6337:   VecGetArrayRead(coords, &arr);
6338:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6339:   VecRestoreArrayRead(coords, &arr);
6340:   if (pCoord) {
6341:     PetscSectionGetStorageSize(newcs, &n);
6342:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6343:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6344:     VecReplaceArray(*pCoord, newarr);
6345:   } else {
6346:     PetscFree(newarr);
6347:   }
6348:   if (pCoordSection) {*pCoordSection = newcs;}
6349:   else               {PetscSectionDestroy(&newcs);}
6350:   return(0);
6351: }

6353: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6354: {

6360:   if (!dm->coordinateField) {
6361:     if (dm->ops->createcoordinatefield) {
6362:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6363:     }
6364:   }
6365:   *field = dm->coordinateField;
6366:   return(0);
6367: }

6369: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6370: {

6376:   PetscObjectReference((PetscObject)field);
6377:   DMFieldDestroy(&dm->coordinateField);
6378:   dm->coordinateField = field;
6379:   return(0);
6380: }

6382: /*@
6383:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

6385:   Collective on dm

6387:   Input Parameter:
6388: . dm - the DM

6390:   Output Parameter:
6391: . cdm - coordinate DM

6393:   Level: intermediate

6395: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6396: @*/
6397: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6398: {

6404:   if (!dm->coordinateDM) {
6405:     DM cdm;

6407:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6408:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6409:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6410:      * until the call to CreateCoordinateDM) */
6411:     DMDestroy(&dm->coordinateDM);
6412:     dm->coordinateDM = cdm;
6413:   }
6414:   *cdm = dm->coordinateDM;
6415:   return(0);
6416: }

6418: /*@
6419:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

6421:   Logically Collective on dm

6423:   Input Parameters:
6424: + dm - the DM
6425: - cdm - coordinate DM

6427:   Level: intermediate

6429: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6430: @*/
6431: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6432: {

6438:   PetscObjectReference((PetscObject)cdm);
6439:   DMDestroy(&dm->coordinateDM);
6440:   dm->coordinateDM = cdm;
6441:   return(0);
6442: }

6444: /*@
6445:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

6447:   Not Collective

6449:   Input Parameter:
6450: . dm - The DM object

6452:   Output Parameter:
6453: . dim - The embedding dimension

6455:   Level: intermediate

6457: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6458: @*/
6459: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6460: {
6464:   if (dm->dimEmbed == PETSC_DEFAULT) {
6465:     dm->dimEmbed = dm->dim;
6466:   }
6467:   *dim = dm->dimEmbed;
6468:   return(0);
6469: }

6471: /*@
6472:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

6474:   Not Collective

6476:   Input Parameters:
6477: + dm  - The DM object
6478: - dim - The embedding dimension

6480:   Level: intermediate

6482: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6483: @*/
6484: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6485: {
6486:   PetscDS        ds;
6487:   PetscInt       Nds, n;

6492:   dm->dimEmbed = dim;
6493:   DMGetNumDS(dm, &Nds);
6494:   for (n = 0; n < Nds; ++n) {
6495:     DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6496:     PetscDSSetCoordinateDimension(ds, dim);
6497:   }
6498:   return(0);
6499: }

6501: /*@
6502:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6504:   Collective on dm

6506:   Input Parameter:
6507: . dm - The DM object

6509:   Output Parameter:
6510: . section - The PetscSection object

6512:   Level: intermediate

6514: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6515: @*/
6516: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6517: {
6518:   DM             cdm;

6524:   DMGetCoordinateDM(dm, &cdm);
6525:   DMGetLocalSection(cdm, section);
6526:   return(0);
6527: }

6529: /*@
6530:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6532:   Not Collective

6534:   Input Parameters:
6535: + dm      - The DM object
6536: . dim     - The embedding dimension, or PETSC_DETERMINE
6537: - section - The PetscSection object

6539:   Level: intermediate

6541: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6542: @*/
6543: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6544: {
6545:   DM             cdm;

6551:   DMGetCoordinateDM(dm, &cdm);
6552:   DMSetLocalSection(cdm, section);
6553:   if (dim == PETSC_DETERMINE) {
6554:     PetscInt d = PETSC_DEFAULT;
6555:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6557:     PetscSectionGetChart(section, &pStart, &pEnd);
6558:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6559:     pStart = PetscMax(vStart, pStart);
6560:     pEnd   = PetscMin(vEnd, pEnd);
6561:     for (v = pStart; v < pEnd; ++v) {
6562:       PetscSectionGetDof(section, v, &dd);
6563:       if (dd) {d = dd; break;}
6564:     }
6565:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6566:   }
6567:   return(0);
6568: }

6570: /*@
6571:   DMProjectCoordinates - Project coordinates to a different space

6573:   Input Parameters:
6574: + dm      - The DM object
6575: - disc    - The new coordinate discretization

6577:   Level: intermediate

6579: .seealso: DMGetCoordinateField()
6580: @*/
6581: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6582: {
6583:   PetscObject    discOld;
6584:   PetscClassId   classid;
6585:   DM             cdmOld,cdmNew;
6586:   Vec            coordsOld,coordsNew;
6587:   Mat            matInterp;


6594:   DMGetCoordinateDM(dm, &cdmOld);
6595:   /* Check current discretization is compatible */
6596:   DMGetField(cdmOld, 0, NULL, &discOld);
6597:   PetscObjectGetClassId(discOld, &classid);
6598:   if (classid != PETSCFE_CLASSID) {
6599:     if (classid == PETSC_CONTAINER_CLASSID) {
6600:       PetscFE        feLinear;
6601:       DMPolytopeType ct;
6602:       PetscInt       dim, dE, cStart;
6603:       PetscBool      simplex;

6605:       /* Assume linear vertex coordinates */
6606:       DMGetDimension(dm, &dim);
6607:       DMGetCoordinateDim(dm, &dE);
6608:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6609:       DMPlexGetCellType(dm, cStart, &ct);
6610:       switch (ct) {
6611:         case DM_POLYTOPE_TRI_PRISM:
6612:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6613:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6614:         default: break;
6615:       }
6616:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6617:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6618:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6619:       PetscFEDestroy(&feLinear);
6620:       DMCreateDS(cdmOld);
6621:     } else {
6622:       const char *discname;

6624:       PetscObjectGetType(discOld, &discname);
6625:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6626:     }
6627:   }
6628:   /* Make a fresh clone of the coordinate DM */
6629:   DMClone(cdmOld, &cdmNew);
6630:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6631:   DMCreateDS(cdmNew);
6632:   /* Project the coordinate vector from old to new space  */
6633:   DMGetCoordinates(dm, &coordsOld);
6634:   DMCreateGlobalVector(cdmNew, &coordsNew);
6635:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6636:   MatInterpolate(matInterp, coordsOld, coordsNew);
6637:   MatDestroy(&matInterp);
6638:   /* Set new coordinate structures */
6639:   DMSetCoordinateField(dm, NULL);
6640:   DMSetCoordinateDM(dm, cdmNew);
6641:   DMSetCoordinates(dm, coordsNew);
6642:   VecDestroy(&coordsNew);
6643:   DMDestroy(&cdmNew);
6644:   return(0);
6645: }

6647: /*@C
6648:   DMGetPeriodicity - Get the description of mesh periodicity

6650:   Input Parameter:
6651: . dm      - The DM object

6653:   Output Parameters:
6654: + per     - Whether the DM is periodic or not
6655: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6656: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6657: - bd      - This describes the type of periodicity in each topological dimension

6659:   Level: developer

6661: .seealso: DMGetPeriodicity()
6662: @*/
6663: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6664: {
6667:   if (per)     *per     = dm->periodic;
6668:   if (L)       *L       = dm->L;
6669:   if (maxCell) *maxCell = dm->maxCell;
6670:   if (bd)      *bd      = dm->bdtype;
6671:   return(0);
6672: }

6674: /*@C
6675:   DMSetPeriodicity - Set the description of mesh periodicity

6677:   Input Parameters:
6678: + dm      - The DM object
6679: . per     - Whether the DM is periodic or not.
6680: . 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.
6681: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6682: - bd      - This describes the type of periodicity in each topological dimension

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

6686:   Level: developer

6688: .seealso: DMGetPeriodicity()
6689: @*/
6690: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6691: {
6692:   PetscInt       dim, d;

6701:   DMGetDimension(dm, &dim);
6702:   if (maxCell) {
6703:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6704:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6705:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6706:     PetscFree(dm->maxCell);
6707:   }

6709:   if (L) {
6710:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6711:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6712:   }
6713:   if (bd) {
6714:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6715:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6716:   }
6717:   dm->periodic = per;
6718:   return(0);
6719: }

6721: /*@
6722:   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.

6724:   Input Parameters:
6725: + dm     - The DM
6726: . in     - The input coordinate point (dim numbers)
6727: - endpoint - Include the endpoint L_i

6729:   Output Parameter:
6730: . out - The localized coordinate point

6732:   Level: developer

6734: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6735: @*/
6736: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6737: {
6738:   PetscInt       dim, d;

6742:   DMGetCoordinateDim(dm, &dim);
6743:   if (!dm->maxCell) {
6744:     for (d = 0; d < dim; ++d) out[d] = in[d];
6745:   } else {
6746:     if (endpoint) {
6747:       for (d = 0; d < dim; ++d) {
6748:         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)) {
6749:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6750:         } else {
6751:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6752:         }
6753:       }
6754:     } else {
6755:       for (d = 0; d < dim; ++d) {
6756:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6757:       }
6758:     }
6759:   }
6760:   return(0);
6761: }

6763: /*
6764:   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.

6766:   Input Parameters:
6767: + dm     - The DM
6768: . dim    - The spatial dimension
6769: . anchor - The anchor point, the input point can be no more than maxCell away from it
6770: - in     - The input coordinate point (dim numbers)

6772:   Output Parameter:
6773: . out - The localized coordinate point

6775:   Level: developer

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

6779: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6780: */
6781: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6782: {
6783:   PetscInt d;

6786:   if (!dm->maxCell) {
6787:     for (d = 0; d < dim; ++d) out[d] = in[d];
6788:   } else {
6789:     for (d = 0; d < dim; ++d) {
6790:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6791:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6792:       } else {
6793:         out[d] = in[d];
6794:       }
6795:     }
6796:   }
6797:   return(0);
6798: }

6800: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6801: {
6802:   PetscInt d;

6805:   if (!dm->maxCell) {
6806:     for (d = 0; d < dim; ++d) out[d] = in[d];
6807:   } else {
6808:     for (d = 0; d < dim; ++d) {
6809:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6810:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6811:       } else {
6812:         out[d] = in[d];
6813:       }
6814:     }
6815:   }
6816:   return(0);
6817: }

6819: /*
6820:   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.

6822:   Input Parameters:
6823: + dm     - The DM
6824: . dim    - The spatial dimension
6825: . anchor - The anchor point, the input point can be no more than maxCell away from it
6826: . in     - The input coordinate delta (dim numbers)
6827: - out    - The input coordinate point (dim numbers)

6829:   Output Parameter:
6830: . out    - The localized coordinate in + out

6832:   Level: developer

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

6836: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6837: */
6838: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6839: {
6840:   PetscInt d;

6843:   if (!dm->maxCell) {
6844:     for (d = 0; d < dim; ++d) out[d] += in[d];
6845:   } else {
6846:     for (d = 0; d < dim; ++d) {
6847:       const PetscReal maxC = dm->maxCell[d];

6849:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6850:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6852:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6853:           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]));
6854:         out[d] += newCoord;
6855:       } else {
6856:         out[d] += in[d];
6857:       }
6858:     }
6859:   }
6860:   return(0);
6861: }

6863: /*@
6864:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6866:   Not collective

6868:   Input Parameter:
6869: . dm - The DM

6871:   Output Parameter:
6872:   areLocalized - True if localized

6874:   Level: developer

6876: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6877: @*/
6878: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6879: {
6880:   DM             cdm;
6881:   PetscSection   coordSection;
6882:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
6883:   PetscBool      isPlex, alreadyLocalized;

6889:   *areLocalized = PETSC_FALSE;

6891:   /* We need some generic way of refering to cells/vertices */
6892:   DMGetCoordinateDM(dm, &cdm);
6893:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6894:   if (!isPlex) return(0);
6895:   DMPlexGetDepth(cdm, &depth);
6896:   if (!depth) return(0);

6898:   DMGetCoordinateSection(dm, &coordSection);
6899:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6900:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6901:   alreadyLocalized = PETSC_FALSE;
6902:   for (c = cStart; c < cEnd; ++c) {
6903:     if (c < sStart || c >= sEnd) continue;
6904:     PetscSectionGetDof(coordSection, c, &dof);
6905:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6906:   }
6907:   *areLocalized = alreadyLocalized;
6908:   return(0);
6909: }

6911: /*@
6912:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6914:   Collective on dm

6916:   Input Parameter:
6917: . dm - The DM

6919:   Output Parameter:
6920:   areLocalized - True if localized

6922:   Level: developer

6924: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6925: @*/
6926: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6927: {
6928:   PetscBool      localized;

6934:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6935:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6936:   return(0);
6937: }

6939: /*@
6940:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6942:   Collective on dm

6944:   Input Parameter:
6945: . dm - The DM

6947:   Level: developer

6949: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6950: @*/
6951: PetscErrorCode DMLocalizeCoordinates(DM dm)
6952: {
6953:   DM             cdm;
6954:   PetscSection   coordSection, cSection;
6955:   Vec            coordinates,  cVec;
6956:   PetscScalar   *coords, *coords2, *anchor, *localized;
6957:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6958:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6959:   PetscInt       maxHeight = 0, h;
6960:   PetscInt       *pStart = NULL, *pEnd = NULL;

6965:   if (!dm->periodic) return(0);
6966:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6967:   if (alreadyLocalized) return(0);

6969:   /* We need some generic way of refering to cells/vertices */
6970:   DMGetCoordinateDM(dm, &cdm);
6971:   {
6972:     PetscBool isplex;

6974:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6975:     if (isplex) {
6976:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6977:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6978:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6979:       pEnd = &pStart[maxHeight + 1];
6980:       newStart = vStart;
6981:       newEnd   = vEnd;
6982:       for (h = 0; h <= maxHeight; h++) {
6983:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6984:         newStart = PetscMin(newStart,pStart[h]);
6985:         newEnd   = PetscMax(newEnd,pEnd[h]);
6986:       }
6987:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6988:   }
6989:   DMGetCoordinatesLocal(dm, &coordinates);
6990:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6991:   DMGetCoordinateSection(dm, &coordSection);
6992:   VecGetBlockSize(coordinates, &bs);
6993:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6995:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6996:   PetscSectionSetNumFields(cSection, 1);
6997:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6998:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6999:   PetscSectionSetChart(cSection, newStart, newEnd);

7001:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7002:   localized = &anchor[bs];
7003:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7004:   for (h = 0; h <= maxHeight; h++) {
7005:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7007:     for (c = cStart; c < cEnd; ++c) {
7008:       PetscScalar *cellCoords = NULL;
7009:       PetscInt     b;

7011:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7012:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7013:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7014:       for (d = 0; d < dof/bs; ++d) {
7015:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
7016:         for (b = 0; b < bs; b++) {
7017:           if (cellCoords[d*bs + b] != localized[b]) break;
7018:         }
7019:         if (b < bs) break;
7020:       }
7021:       if (d < dof/bs) {
7022:         if (c >= sStart && c < sEnd) {
7023:           PetscInt cdof;

7025:           PetscSectionGetDof(coordSection, c, &cdof);
7026:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7027:         }
7028:         PetscSectionSetDof(cSection, c, dof);
7029:         PetscSectionSetFieldDof(cSection, c, 0, dof);
7030:       }
7031:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7032:     }
7033:   }
7034:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
7035:   if (alreadyLocalizedGlobal) {
7036:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7037:     PetscSectionDestroy(&cSection);
7038:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7039:     return(0);
7040:   }
7041:   for (v = vStart; v < vEnd; ++v) {
7042:     PetscSectionGetDof(coordSection, v, &dof);
7043:     PetscSectionSetDof(cSection, v, dof);
7044:     PetscSectionSetFieldDof(cSection, v, 0, dof);
7045:   }
7046:   PetscSectionSetUp(cSection);
7047:   PetscSectionGetStorageSize(cSection, &coordSize);
7048:   VecCreate(PETSC_COMM_SELF, &cVec);
7049:   PetscObjectSetName((PetscObject)cVec,"coordinates");
7050:   VecSetBlockSize(cVec, bs);
7051:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
7052:   VecSetType(cVec, VECSTANDARD);
7053:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
7054:   VecGetArray(cVec, &coords2);
7055:   for (v = vStart; v < vEnd; ++v) {
7056:     PetscSectionGetDof(coordSection, v, &dof);
7057:     PetscSectionGetOffset(coordSection, v, &off);
7058:     PetscSectionGetOffset(cSection,     v, &off2);
7059:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7060:   }
7061:   for (h = 0; h <= maxHeight; h++) {
7062:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7064:     for (c = cStart; c < cEnd; ++c) {
7065:       PetscScalar *cellCoords = NULL;
7066:       PetscInt     b, cdof;

7068:       PetscSectionGetDof(cSection,c,&cdof);
7069:       if (!cdof) continue;
7070:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7071:       PetscSectionGetOffset(cSection, c, &off2);
7072:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7073:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
7074:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7075:     }
7076:   }
7077:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7078:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7079:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
7080:   VecRestoreArray(cVec, &coords2);
7081:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
7082:   DMSetCoordinatesLocal(dm, cVec);
7083:   VecDestroy(&cVec);
7084:   PetscSectionDestroy(&cSection);
7085:   return(0);
7086: }

7088: /*@
7089:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

7091:   Collective on v (see explanation below)

7093:   Input Parameters:
7094: + dm - The DM
7095: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

7097:   Input/Output Parameters:
7098: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7099: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7100:            on output, the PetscSF containing the ranks and local indices of the containing points

7102:   Level: developer

7104:   Notes:
7105:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7106:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

7108:   If *cellSF is NULL on input, a PetscSF will be created.
7109:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

7111:   An array that maps each point to its containing cell can be obtained with

7113: $    const PetscSFNode *cells;
7114: $    PetscInt           nFound;
7115: $    const PetscInt    *found;
7116: $
7117: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

7119:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7120:   the index of the cell in its rank's local numbering.

7122: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7123: @*/
7124: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7125: {

7132:   if (*cellSF) {
7133:     PetscMPIInt result;

7136:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7137:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7138:   } else {
7139:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7140:   }
7141:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7142:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7143:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7144:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7145:   return(0);
7146: }

7148: /*@
7149:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7151:   Collective on dm

7153:   Input Parameter:
7154: . dm - The original DM

7156:   Output Parameter:
7157: . odm - The DM which provides the layout for output

7159:   Level: intermediate

7161: .seealso: VecView(), DMGetGlobalSection()
7162: @*/
7163: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7164: {
7165:   PetscSection   section;
7166:   PetscBool      hasConstraints, ghasConstraints;

7172:   DMGetLocalSection(dm, &section);
7173:   PetscSectionHasConstraints(section, &hasConstraints);
7174:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7175:   if (!ghasConstraints) {
7176:     *odm = dm;
7177:     return(0);
7178:   }
7179:   if (!dm->dmBC) {
7180:     PetscSection newSection, gsection;
7181:     PetscSF      sf;

7183:     DMClone(dm, &dm->dmBC);
7184:     DMCopyDisc(dm, dm->dmBC);
7185:     PetscSectionClone(section, &newSection);
7186:     DMSetLocalSection(dm->dmBC, newSection);
7187:     PetscSectionDestroy(&newSection);
7188:     DMGetPointSF(dm->dmBC, &sf);
7189:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7190:     DMSetGlobalSection(dm->dmBC, gsection);
7191:     PetscSectionDestroy(&gsection);
7192:   }
7193:   *odm = dm->dmBC;
7194:   return(0);
7195: }

7197: /*@
7198:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7200:   Input Parameter:
7201: . dm - The original DM

7203:   Output Parameters:
7204: + num - The output sequence number
7205: - val - The output sequence value

7207:   Level: intermediate

7209:   Note: This is intended for output that should appear in sequence, for instance
7210:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7212: .seealso: VecView()
7213: @*/
7214: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7215: {
7220:   return(0);
7221: }

7223: /*@
7224:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7226:   Input Parameters:
7227: + dm - The original DM
7228: . num - The output sequence number
7229: - val - The output sequence value

7231:   Level: intermediate

7233:   Note: This is intended for output that should appear in sequence, for instance
7234:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7236: .seealso: VecView()
7237: @*/
7238: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7239: {
7242:   dm->outputSequenceNum = num;
7243:   dm->outputSequenceVal = val;
7244:   return(0);
7245: }

7247: /*@C
7248:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7250:   Input Parameters:
7251: + dm   - The original DM
7252: . name - The sequence name
7253: - num  - The output sequence number

7255:   Output Parameter:
7256: . val  - The output sequence value

7258:   Level: intermediate

7260:   Note: This is intended for output that should appear in sequence, for instance
7261:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7263: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7264: @*/
7265: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7266: {
7267:   PetscBool      ishdf5;

7274:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7275:   if (ishdf5) {
7276: #if defined(PETSC_HAVE_HDF5)
7277:     PetscScalar value;

7279:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7280:     *val = PetscRealPart(value);
7281: #endif
7282:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7283:   return(0);
7284: }

7286: /*@
7287:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

7289:   Not collective

7291:   Input Parameter:
7292: . dm - The DM

7294:   Output Parameter:
7295: . useNatural - The flag to build the mapping to a natural order during distribution

7297:   Level: beginner

7299: .seealso: DMSetUseNatural(), DMCreate()
7300: @*/
7301: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7302: {
7306:   *useNatural = dm->useNatural;
7307:   return(0);
7308: }

7310: /*@
7311:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7313:   Collective on dm

7315:   Input Parameters:
7316: + dm - The DM
7317: - useNatural - The flag to build the mapping to a natural order during distribution

7319:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7321:   Level: beginner

7323: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7324: @*/
7325: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7326: {
7330:   dm->useNatural = useNatural;
7331:   return(0);
7332: }

7334: /*@C
7335:   DMCreateLabel - Create a label of the given name if it does not already exist

7337:   Not Collective

7339:   Input Parameters:
7340: + dm   - The DM object
7341: - name - The label name

7343:   Level: intermediate

7345: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7346: @*/
7347: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7348: {
7349:   PetscBool      flg;
7350:   DMLabel        label;

7356:   DMHasLabel(dm, name, &flg);
7357:   if (!flg) {
7358:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7359:     DMAddLabel(dm, label);
7360:     DMLabelDestroy(&label);
7361:   }
7362:   return(0);
7363: }

7365: /*@C
7366:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

7368:   Not Collective

7370:   Input Parameters:
7371: + dm   - The DM object
7372: . l    - The index for the label
7373: - name - The label name

7375:   Level: intermediate

7377: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7378: @*/
7379: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7380: {
7381:   DMLabelLink    orig, prev = NULL;
7382:   DMLabel        label;
7383:   PetscInt       Nl, m;
7384:   PetscBool      flg, match;
7385:   const char    *lname;

7391:   DMHasLabel(dm, name, &flg);
7392:   if (!flg) {
7393:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7394:     DMAddLabel(dm, label);
7395:     DMLabelDestroy(&label);
7396:   }
7397:   DMGetNumLabels(dm, &Nl);
7398:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7399:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7400:     PetscObjectGetName((PetscObject) orig->label, &lname);
7401:     PetscStrcmp(name, lname, &match);
7402:     if (match) break;
7403:   }
7404:   if (m == l) return(0);
7405:   if (!m) dm->labels = orig->next;
7406:   else    prev->next = orig->next;
7407:   if (!l) {
7408:     orig->next = dm->labels;
7409:     dm->labels = orig;
7410:   } else {
7411:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7412:     orig->next = prev->next;
7413:     prev->next = orig;
7414:   }
7415:   return(0);
7416: }

7418: /*@C
7419:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

7421:   Not Collective

7423:   Input Parameters:
7424: + dm   - The DM object
7425: . name - The label name
7426: - point - The mesh point

7428:   Output Parameter:
7429: . value - The label value for this point, or -1 if the point is not in the label

7431:   Level: beginner

7433: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7434: @*/
7435: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7436: {
7437:   DMLabel        label;

7443:   DMGetLabel(dm, name, &label);
7444:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7445:   DMLabelGetValue(label, point, value);
7446:   return(0);
7447: }

7449: /*@C
7450:   DMSetLabelValue - Add a point to a Sieve Label with given value

7452:   Not Collective

7454:   Input Parameters:
7455: + dm   - The DM object
7456: . name - The label name
7457: . point - The mesh point
7458: - value - The label value for this point

7460:   Output Parameter:

7462:   Level: beginner

7464: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7465: @*/
7466: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7467: {
7468:   DMLabel        label;

7474:   DMGetLabel(dm, name, &label);
7475:   if (!label) {
7476:     DMCreateLabel(dm, name);
7477:     DMGetLabel(dm, name, &label);
7478:   }
7479:   DMLabelSetValue(label, point, value);
7480:   return(0);
7481: }

7483: /*@C
7484:   DMClearLabelValue - Remove a point from a Sieve Label with given value

7486:   Not Collective

7488:   Input Parameters:
7489: + dm   - The DM object
7490: . name - The label name
7491: . point - The mesh point
7492: - value - The label value for this point

7494:   Output Parameter:

7496:   Level: beginner

7498: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7499: @*/
7500: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7501: {
7502:   DMLabel        label;

7508:   DMGetLabel(dm, name, &label);
7509:   if (!label) return(0);
7510:   DMLabelClearValue(label, point, value);
7511:   return(0);
7512: }

7514: /*@C
7515:   DMGetLabelSize - Get the number of different integer ids in a Label

7517:   Not Collective

7519:   Input Parameters:
7520: + dm   - The DM object
7521: - name - The label name

7523:   Output Parameter:
7524: . size - The number of different integer ids, or 0 if the label does not exist

7526:   Level: beginner

7528: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7529: @*/
7530: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7531: {
7532:   DMLabel        label;

7539:   DMGetLabel(dm, name, &label);
7540:   *size = 0;
7541:   if (!label) return(0);
7542:   DMLabelGetNumValues(label, size);
7543:   return(0);
7544: }

7546: /*@C
7547:   DMGetLabelIdIS - Get the integer ids in a label

7549:   Not Collective

7551:   Input Parameters:
7552: + mesh - The DM object
7553: - name - The label name

7555:   Output Parameter:
7556: . ids - The integer ids, or NULL if the label does not exist

7558:   Level: beginner

7560: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7561: @*/
7562: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7563: {
7564:   DMLabel        label;

7571:   DMGetLabel(dm, name, &label);
7572:   *ids = NULL;
7573:  if (label) {
7574:     DMLabelGetValueIS(label, ids);
7575:   } else {
7576:     /* returning an empty IS */
7577:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7578:   }
7579:   return(0);
7580: }

7582: /*@C
7583:   DMGetStratumSize - Get the number of points in a label stratum

7585:   Not Collective

7587:   Input Parameters:
7588: + dm - The DM object
7589: . name - The label name
7590: - value - The stratum value

7592:   Output Parameter:
7593: . size - The stratum size

7595:   Level: beginner

7597: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7598: @*/
7599: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7600: {
7601:   DMLabel        label;

7608:   DMGetLabel(dm, name, &label);
7609:   *size = 0;
7610:   if (!label) return(0);
7611:   DMLabelGetStratumSize(label, value, size);
7612:   return(0);
7613: }

7615: /*@C
7616:   DMGetStratumIS - Get the points in a label stratum

7618:   Not Collective

7620:   Input Parameters:
7621: + dm - The DM object
7622: . name - The label name
7623: - value - The stratum value

7625:   Output Parameter:
7626: . points - The stratum points, or NULL if the label does not exist or does not have that value

7628:   Level: beginner

7630: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7631: @*/
7632: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7633: {
7634:   DMLabel        label;

7641:   DMGetLabel(dm, name, &label);
7642:   *points = NULL;
7643:   if (!label) return(0);
7644:   DMLabelGetStratumIS(label, value, points);
7645:   return(0);
7646: }

7648: /*@C
7649:   DMSetStratumIS - Set the points in a label stratum

7651:   Not Collective

7653:   Input Parameters:
7654: + dm - The DM object
7655: . name - The label name
7656: . value - The stratum value
7657: - points - The stratum points

7659:   Level: beginner

7661: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7662: @*/
7663: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7664: {
7665:   DMLabel        label;

7672:   DMGetLabel(dm, name, &label);
7673:   if (!label) return(0);
7674:   DMLabelSetStratumIS(label, value, points);
7675:   return(0);
7676: }

7678: /*@C
7679:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7681:   Not Collective

7683:   Input Parameters:
7684: + dm   - The DM object
7685: . name - The label name
7686: - value - The label value for this point

7688:   Output Parameter:

7690:   Level: beginner

7692: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7693: @*/
7694: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7695: {
7696:   DMLabel        label;

7702:   DMGetLabel(dm, name, &label);
7703:   if (!label) return(0);
7704:   DMLabelClearStratum(label, value);
7705:   return(0);
7706: }

7708: /*@
7709:   DMGetNumLabels - Return the number of labels defined by the mesh

7711:   Not Collective

7713:   Input Parameter:
7714: . dm   - The DM object

7716:   Output Parameter:
7717: . numLabels - the number of Labels

7719:   Level: intermediate

7721: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7722: @*/
7723: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7724: {
7725:   DMLabelLink next = dm->labels;
7726:   PetscInt  n    = 0;

7731:   while (next) {++n; next = next->next;}
7732:   *numLabels = n;
7733:   return(0);
7734: }

7736: /*@C
7737:   DMGetLabelName - Return the name of nth label

7739:   Not Collective

7741:   Input Parameters:
7742: + dm - The DM object
7743: - n  - the label number

7745:   Output Parameter:
7746: . name - the label name

7748:   Level: intermediate

7750: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7751: @*/
7752: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7753: {
7754:   DMLabelLink    next = dm->labels;
7755:   PetscInt       l    = 0;

7761:   while (next) {
7762:     if (l == n) {
7763:       PetscObjectGetName((PetscObject) next->label, name);
7764:       return(0);
7765:     }
7766:     ++l;
7767:     next = next->next;
7768:   }
7769:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7770: }

7772: /*@C
7773:   DMHasLabel - Determine whether the mesh has a label of a given name

7775:   Not Collective

7777:   Input Parameters:
7778: + dm   - The DM object
7779: - name - The label name

7781:   Output Parameter:
7782: . hasLabel - PETSC_TRUE if the label is present

7784:   Level: intermediate

7786: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7787: @*/
7788: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7789: {
7790:   DMLabelLink    next = dm->labels;
7791:   const char    *lname;

7798:   *hasLabel = PETSC_FALSE;
7799:   while (next) {
7800:     PetscObjectGetName((PetscObject) next->label, &lname);
7801:     PetscStrcmp(name, lname, hasLabel);
7802:     if (*hasLabel) break;
7803:     next = next->next;
7804:   }
7805:   return(0);
7806: }

7808: /*@C
7809:   DMGetLabel - Return the label of a given name, or NULL

7811:   Not Collective

7813:   Input Parameters:
7814: + dm   - The DM object
7815: - name - The label name

7817:   Output Parameter:
7818: . label - The DMLabel, or NULL if the label is absent

7820:   Note: Some of the default labels in a DMPlex will be
7821: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7822: $ "celltype"    - Holds the topological type of each cell
7823: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7824: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7825: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7826: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7828:   Level: intermediate

7830: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7831: @*/
7832: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7833: {
7834:   DMLabelLink    next = dm->labels;
7835:   PetscBool      hasLabel;
7836:   const char    *lname;

7843:   *label = NULL;
7844:   while (next) {
7845:     PetscObjectGetName((PetscObject) next->label, &lname);
7846:     PetscStrcmp(name, lname, &hasLabel);
7847:     if (hasLabel) {
7848:       *label = next->label;
7849:       break;
7850:     }
7851:     next = next->next;
7852:   }
7853:   return(0);
7854: }

7856: /*@C
7857:   DMGetLabelByNum - Return the nth label

7859:   Not Collective

7861:   Input Parameters:
7862: + dm - The DM object
7863: - n  - the label number

7865:   Output Parameter:
7866: . label - the label

7868:   Level: intermediate

7870: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7871: @*/
7872: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7873: {
7874:   DMLabelLink next = dm->labels;
7875:   PetscInt    l    = 0;

7880:   while (next) {
7881:     if (l == n) {
7882:       *label = next->label;
7883:       return(0);
7884:     }
7885:     ++l;
7886:     next = next->next;
7887:   }
7888:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7889: }

7891: /*@C
7892:   DMAddLabel - Add the label to this mesh

7894:   Not Collective

7896:   Input Parameters:
7897: + dm   - The DM object
7898: - label - The DMLabel

7900:   Level: developer

7902: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7903: @*/
7904: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7905: {
7906:   DMLabelLink    l, *p, tmpLabel;
7907:   PetscBool      hasLabel;
7908:   const char    *lname;
7909:   PetscBool      flg;

7914:   PetscObjectGetName((PetscObject) label, &lname);
7915:   DMHasLabel(dm, lname, &hasLabel);
7916:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7917:   PetscCalloc1(1, &tmpLabel);
7918:   tmpLabel->label  = label;
7919:   tmpLabel->output = PETSC_TRUE;
7920:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7921:   *p = tmpLabel;
7922:   PetscObjectReference((PetscObject)label);
7923:   PetscStrcmp(lname, "depth", &flg);
7924:   if (flg) dm->depthLabel = label;
7925:   PetscStrcmp(lname, "celltype", &flg);
7926:   if (flg) dm->celltypeLabel = label;
7927:   return(0);
7928: }

7930: /*@C
7931:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

7933:   Not Collective

7935:   Input Parameters:
7936: + dm    - The DM object
7937: - label - The DMLabel, having the same name, to substitute

7939:   Note: Some of the default labels in a DMPlex will be
7940: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7941: $ "celltype"    - Holds the topological type of each cell
7942: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7943: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7944: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7945: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7947:   Level: intermediate

7949: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7950: @*/
7951: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7952: {
7953:   DMLabelLink    next = dm->labels;
7954:   PetscBool      hasLabel, flg;
7955:   const char    *name, *lname;

7961:   PetscObjectGetName((PetscObject) label, &name);
7962:   while (next) {
7963:     PetscObjectGetName((PetscObject) next->label, &lname);
7964:     PetscStrcmp(name, lname, &hasLabel);
7965:     if (hasLabel) {
7966:       PetscObjectReference((PetscObject) label);
7967:       PetscStrcmp(lname, "depth", &flg);
7968:       if (flg) dm->depthLabel = label;
7969:       PetscStrcmp(lname, "celltype", &flg);
7970:       if (flg) dm->celltypeLabel = label;
7971:       DMLabelDestroy(&next->label);
7972:       next->label = label;
7973:       break;
7974:     }
7975:     next = next->next;
7976:   }
7977:   return(0);
7978: }

7980: /*@C
7981:   DMRemoveLabel - Remove the label given by name from this mesh

7983:   Not Collective

7985:   Input Parameters:
7986: + dm   - The DM object
7987: - name - The label name

7989:   Output Parameter:
7990: . label - The DMLabel, or NULL if the label is absent

7992:   Level: developer

7994:   Notes:
7995:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7996:   DMLabelDestroy() on the label.

7998:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7999:   call DMLabelDestroy(). Instead, the label is returned and the user is
8000:   responsible of calling DMLabelDestroy() at some point.

8002: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
8003: @*/
8004: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8005: {
8006:   DMLabelLink    link, *pnext;
8007:   PetscBool      hasLabel;
8008:   const char    *lname;

8014:   if (label) {
8016:     *label = NULL;
8017:   }
8018:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8019:     PetscObjectGetName((PetscObject) link->label, &lname);
8020:     PetscStrcmp(name, lname, &hasLabel);
8021:     if (hasLabel) {
8022:       *pnext = link->next; /* Remove from list */
8023:       PetscStrcmp(name, "depth", &hasLabel);
8024:       if (hasLabel) dm->depthLabel = NULL;
8025:       PetscStrcmp(name, "celltype", &hasLabel);
8026:       if (hasLabel) dm->celltypeLabel = NULL;
8027:       if (label) *label = link->label;
8028:       else       {DMLabelDestroy(&link->label);}
8029:       PetscFree(link);
8030:       break;
8031:     }
8032:   }
8033:   return(0);
8034: }

8036: /*@
8037:   DMRemoveLabelBySelf - Remove the label from this mesh

8039:   Not Collective

8041:   Input Parameters:
8042: + dm   - The DM object
8043: . label - (Optional) The DMLabel to be removed from the DM
8044: - failNotFound - Should it fail if the label is not found in the DM?

8046:   Level: developer

8048:   Notes:
8049:   Only exactly the same instance is removed if found, name match is ignored.
8050:   If the DM has an exclusive reference to the label, it gets destroyed and
8051:   *label nullified.

8053: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
8054: @*/
8055: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8056: {
8057:   DMLabelLink    link, *pnext;
8058:   PetscBool      hasLabel = PETSC_FALSE;

8064:   if (!*label && !failNotFound) return(0);
8067:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8068:     if (*label == link->label) {
8069:       hasLabel = PETSC_TRUE;
8070:       *pnext = link->next; /* Remove from list */
8071:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
8072:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8073:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8074:       DMLabelDestroy(&link->label);
8075:       PetscFree(link);
8076:       break;
8077:     }
8078:   }
8079:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8080:   return(0);
8081: }

8083: /*@C
8084:   DMGetLabelOutput - Get the output flag for a given label

8086:   Not Collective

8088:   Input Parameters:
8089: + dm   - The DM object
8090: - name - The label name

8092:   Output Parameter:
8093: . output - The flag for output

8095:   Level: developer

8097: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8098: @*/
8099: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8100: {
8101:   DMLabelLink    next = dm->labels;
8102:   const char    *lname;

8109:   while (next) {
8110:     PetscBool flg;

8112:     PetscObjectGetName((PetscObject) next->label, &lname);
8113:     PetscStrcmp(name, lname, &flg);
8114:     if (flg) {*output = next->output; return(0);}
8115:     next = next->next;
8116:   }
8117:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8118: }

8120: /*@C
8121:   DMSetLabelOutput - Set the output flag for a given label

8123:   Not Collective

8125:   Input Parameters:
8126: + dm     - The DM object
8127: . name   - The label name
8128: - output - The flag for output

8130:   Level: developer

8132: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8133: @*/
8134: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8135: {
8136:   DMLabelLink    next = dm->labels;
8137:   const char    *lname;

8143:   while (next) {
8144:     PetscBool flg;

8146:     PetscObjectGetName((PetscObject) next->label, &lname);
8147:     PetscStrcmp(name, lname, &flg);
8148:     if (flg) {next->output = output; return(0);}
8149:     next = next->next;
8150:   }
8151:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8152: }

8154: /*@
8155:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

8157:   Collective on dmA

8159:   Input Parameters:
8160: + dmA - The DM object with initial labels
8161: . dmB - The DM object with copied labels
8162: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8163: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

8165:   Level: intermediate

8167:   Note: This is typically used when interpolating or otherwise adding to a mesh

8169: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8170: @*/
8171: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8172: {
8173:   DMLabel        label, labelNew;
8174:   const char    *name;
8175:   PetscBool      flg;
8176:   DMLabelLink    link;

8184:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8185:   if (dmA == dmB) return(0);
8186:   for (link=dmA->labels; link; link=link->next) {
8187:     label=link->label;
8188:     PetscObjectGetName((PetscObject)label, &name);
8189:     if (!all) {
8190:       PetscStrcmp(name, "depth", &flg);
8191:       if (flg) continue;
8192:       PetscStrcmp(name, "dim", &flg);
8193:       if (flg) continue;
8194:       PetscStrcmp(name, "celltype", &flg);
8195:       if (flg) continue;
8196:     }
8197:     if (mode==PETSC_COPY_VALUES) {
8198:       DMLabelDuplicate(label, &labelNew);
8199:     } else {
8200:       labelNew = label;
8201:     }
8202:     DMAddLabel(dmB, labelNew);
8203:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8204:   }
8205:   return(0);
8206: }

8208: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8209: {
8213:   if (!*label) {
8214:     DMCreateLabel(dm, name);
8215:     DMGetLabel(dm, name, label);
8216:   }
8217:   DMLabelSetValue(*label, point, value);
8218:   return(0);
8219: }

8221: /*
8222:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8223:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8224:   (label, id) pair in the DM.

8226:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8227:   each label.
8228: */
8229: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8230: {
8231:   DMUniversalLabel ul;
8232:   PetscBool       *active;
8233:   PetscInt         pStart, pEnd, p, Nl, l, m;
8234:   PetscErrorCode   ierr;

8237:   PetscMalloc1(1, &ul);
8238:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8239:   DMGetNumLabels(dm, &Nl);
8240:   PetscCalloc1(Nl, &active);
8241:   ul->Nl = 0;
8242:   for (l = 0; l < Nl; ++l) {
8243:     PetscBool   isdepth, iscelltype;
8244:     const char *name;

8246:     DMGetLabelName(dm, l, &name);
8247:     PetscStrncmp(name, "depth", 6, &isdepth);
8248:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8249:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8250:     if (active[l]) ++ul->Nl;
8251:   }
8252:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8253:   ul->Nv = 0;
8254:   for (l = 0, m = 0; l < Nl; ++l) {
8255:     DMLabel     label;
8256:     PetscInt    nv;
8257:     const char *name;

8259:     if (!active[l]) continue;
8260:     DMGetLabelName(dm, l, &name);
8261:     DMGetLabelByNum(dm, l, &label);
8262:     DMLabelGetNumValues(label, &nv);
8263:     PetscStrallocpy(name, &ul->names[m]);
8264:     ul->indices[m]   = l;
8265:     ul->Nv          += nv;
8266:     ul->offsets[m+1] = nv;
8267:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8268:     ++m;
8269:   }
8270:   for (l = 1; l <= ul->Nl; ++l) {
8271:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8272:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8273:   }
8274:   for (l = 0; l < ul->Nl; ++l) {
8275:     PetscInt b;

8277:     ul->masks[l] = 0;
8278:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8279:   }
8280:   PetscMalloc1(ul->Nv, &ul->values);
8281:   for (l = 0, m = 0; l < Nl; ++l) {
8282:     DMLabel         label;
8283:     IS              valueIS;
8284:     const PetscInt *varr;
8285:     PetscInt        nv, v;

8287:     if (!active[l]) continue;
8288:     DMGetLabelByNum(dm, l, &label);
8289:     DMLabelGetNumValues(label, &nv);
8290:     DMLabelGetValueIS(label, &valueIS);
8291:     ISGetIndices(valueIS, &varr);
8292:     for (v = 0; v < nv; ++v) {
8293:       ul->values[ul->offsets[m]+v] = varr[v];
8294:     }
8295:     ISRestoreIndices(valueIS, &varr);
8296:     ISDestroy(&valueIS);
8297:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8298:     ++m;
8299:   }
8300:   DMPlexGetChart(dm, &pStart, &pEnd);
8301:   for (p = pStart; p < pEnd; ++p) {
8302:     PetscInt  uval = 0;
8303:     PetscBool marked = PETSC_FALSE;

8305:     for (l = 0, m = 0; l < Nl; ++l) {
8306:       DMLabel  label;
8307:       PetscInt val, defval, loc, nv;

8309:       if (!active[l]) continue;
8310:       DMGetLabelByNum(dm, l, &label);
8311:       DMLabelGetValue(label, p, &val);
8312:       DMLabelGetDefaultValue(label, &defval);
8313:       if (val == defval) {++m; continue;}
8314:       nv = ul->offsets[m+1]-ul->offsets[m];
8315:       marked = PETSC_TRUE;
8316:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8317:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8318:       uval += (loc+1) << ul->bits[m];
8319:       ++m;
8320:     }
8321:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8322:   }
8323:   PetscFree(active);
8324:   *universal = ul;
8325:   return(0);
8326: }

8328: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8329: {
8330:   PetscInt       l;

8334:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8335:   DMLabelDestroy(&(*universal)->label);
8336:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8337:   PetscFree((*universal)->values);
8338:   PetscFree(*universal);
8339:   *universal = NULL;
8340:   return(0);
8341: }

8343: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8344: {
8347:   *ulabel = ul->label;
8348:   return(0);
8349: }

8351: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8352: {
8353:   PetscInt       Nl = ul->Nl, l;

8358:   for (l = 0; l < Nl; ++l) {
8359:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8360:     else               {DMCreateLabel(dm, ul->names[l]);}
8361:   }
8362:   if (preserveOrder) {
8363:     for (l = 0; l < ul->Nl; ++l) {
8364:       const char *name;
8365:       PetscBool   match;

8367:       DMGetLabelName(dm, ul->indices[l], &name);
8368:       PetscStrcmp(name, ul->names[l], &match);
8369:       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]);
8370:     }
8371:   }
8372:   return(0);
8373: }

8375: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8376: {
8377:   PetscInt       l;

8381:   for (l = 0; l < ul->Nl; ++l) {
8382:     DMLabel  label;
8383:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

8385:     if (lval) {
8386:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8387:       else          {DMGetLabel(dm, ul->names[l], &label);}
8388:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8389:     }
8390:   }
8391:   return(0);
8392: }

8394: /*@
8395:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

8397:   Input Parameter:
8398: . dm - The DM object

8400:   Output Parameter:
8401: . cdm - The coarse DM

8403:   Level: intermediate

8405: .seealso: DMSetCoarseDM()
8406: @*/
8407: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8408: {
8412:   *cdm = dm->coarseMesh;
8413:   return(0);
8414: }

8416: /*@
8417:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

8419:   Input Parameters:
8420: + dm - The DM object
8421: - cdm - The coarse DM

8423:   Level: intermediate

8425: .seealso: DMGetCoarseDM()
8426: @*/
8427: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8428: {

8434:   PetscObjectReference((PetscObject)cdm);
8435:   DMDestroy(&dm->coarseMesh);
8436:   dm->coarseMesh = cdm;
8437:   return(0);
8438: }

8440: /*@
8441:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

8443:   Input Parameter:
8444: . dm - The DM object

8446:   Output Parameter:
8447: . fdm - The fine DM

8449:   Level: intermediate

8451: .seealso: DMSetFineDM()
8452: @*/
8453: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8454: {
8458:   *fdm = dm->fineMesh;
8459:   return(0);
8460: }

8462: /*@
8463:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

8465:   Input Parameters:
8466: + dm - The DM object
8467: - fdm - The fine DM

8469:   Level: intermediate

8471: .seealso: DMGetFineDM()
8472: @*/
8473: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8474: {

8480:   PetscObjectReference((PetscObject)fdm);
8481:   DMDestroy(&dm->fineMesh);
8482:   dm->fineMesh = fdm;
8483:   return(0);
8484: }

8486: /*=== DMBoundary code ===*/

8488: /*@C
8489:   DMAddBoundary - Add a boundary condition to the model

8491:   Collective on dm

8493:   Input Parameters:
8494: + dm       - The DM, with a PetscDS that matches the problem being constrained
8495: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8496: . name     - The BC name
8497: . label    - The label defining constrained points
8498: . Nv       - The number of DMLabel values for constrained points
8499: . values   - An array of values for constrained points
8500: . field    - The field to constrain
8501: . Nc       - The number of constrained field components (0 will constrain all fields)
8502: . comps    - An array of constrained component numbers
8503: . bcFunc   - A pointwise function giving boundary values
8504: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8505: - ctx      - An optional user context for bcFunc

8507:   Output Parameter:
8508: . bd          - (Optional) Boundary number

8510:   Options Database Keys:
8511: + -bc_<boundary name> <num> - Overrides the boundary ids
8512: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8514:   Note:
8515:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8517: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8519:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8521: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8522: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8523: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8524: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8526: + dim - the spatial dimension
8527: . Nf - the number of fields
8528: . uOff - the offset into u[] and u_t[] for each field
8529: . uOff_x - the offset into u_x[] for each field
8530: . u - each field evaluated at the current point
8531: . u_t - the time derivative of each field evaluated at the current point
8532: . u_x - the gradient of each field evaluated at the current point
8533: . aOff - the offset into a[] and a_t[] for each auxiliary field
8534: . aOff_x - the offset into a_x[] for each auxiliary field
8535: . a - each auxiliary field evaluated at the current point
8536: . a_t - the time derivative of each auxiliary field evaluated at the current point
8537: . a_x - the gradient of auxiliary each field evaluated at the current point
8538: . t - current time
8539: . x - coordinates of the current point
8540: . numConstants - number of constant parameters
8541: . constants - constant parameters
8542: - bcval - output values at the current point

8544:   Level: developer

8546: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8547: @*/
8548: 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)
8549: {
8550:   PetscDS        ds;

8560:   DMGetDS(dm, &ds);
8561:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8562:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8563:   return(0);
8564: }

8566: /* TODO Remove this since now the structures are the same */
8567: static PetscErrorCode DMPopulateBoundary(DM dm)
8568: {
8569:   PetscDS        ds;
8570:   DMBoundary    *lastnext;
8571:   DSBoundary     dsbound;

8575:   DMGetDS(dm, &ds);
8576:   dsbound = ds->boundary;
8577:   if (dm->boundary) {
8578:     DMBoundary next = dm->boundary;

8580:     /* quick check to see if the PetscDS has changed */
8581:     if (next->dsboundary == dsbound) return(0);
8582:     /* the PetscDS has changed: tear down and rebuild */
8583:     while (next) {
8584:       DMBoundary b = next;

8586:       next = b->next;
8587:       PetscFree(b);
8588:     }
8589:     dm->boundary = NULL;
8590:   }

8592:   lastnext = &(dm->boundary);
8593:   while (dsbound) {
8594:     DMBoundary dmbound;

8596:     PetscNew(&dmbound);
8597:     dmbound->dsboundary = dsbound;
8598:     dmbound->label      = dsbound->label;
8599:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8600:     *lastnext = dmbound;
8601:     lastnext = &(dmbound->next);
8602:     dsbound = dsbound->next;
8603:   }
8604:   return(0);
8605: }

8607: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8608: {
8609:   DMBoundary     b;

8615:   *isBd = PETSC_FALSE;
8616:   DMPopulateBoundary(dm);
8617:   b = dm->boundary;
8618:   while (b && !(*isBd)) {
8619:     DMLabel    label = b->label;
8620:     DSBoundary dsb   = b->dsboundary;
8621:     PetscInt   i;

8623:     if (label) {
8624:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
8625:     }
8626:     b = b->next;
8627:   }
8628:   return(0);
8629: }

8631: /*@C
8632:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8634:   Collective on DM

8636:   Input Parameters:
8637: + dm      - The DM
8638: . time    - The time
8639: . funcs   - The coordinate functions to evaluate, one per field
8640: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8641: - mode    - The insertion mode for values

8643:   Output Parameter:
8644: . X - vector

8646:    Calling sequence of func:
8647: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8649: +  dim - The spatial dimension
8650: .  time - The time at which to sample
8651: .  x   - The coordinates
8652: .  Nf  - The number of fields
8653: .  u   - The output field values
8654: -  ctx - optional user-defined function context

8656:   Level: developer

8658: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8659: @*/
8660: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8661: {
8662:   Vec            localX;

8667:   DMGetLocalVector(dm, &localX);
8668:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8669:   DMLocalToGlobalBegin(dm, localX, mode, X);
8670:   DMLocalToGlobalEnd(dm, localX, mode, X);
8671:   DMRestoreLocalVector(dm, &localX);
8672:   return(0);
8673: }

8675: /*@C
8676:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8678:   Not collective

8680:   Input Parameters:
8681: + dm      - The DM
8682: . time    - The time
8683: . funcs   - The coordinate functions to evaluate, one per field
8684: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8685: - mode    - The insertion mode for values

8687:   Output Parameter:
8688: . localX - vector

8690:    Calling sequence of func:
8691: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8693: +  dim - The spatial dimension
8694: .  x   - The coordinates
8695: .  Nf  - The number of fields
8696: .  u   - The output field values
8697: -  ctx - optional user-defined function context

8699:   Level: developer

8701: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8702: @*/
8703: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8704: {

8710:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8711:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8712:   return(0);
8713: }

8715: /*@C
8716:   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.

8718:   Collective on DM

8720:   Input Parameters:
8721: + dm      - The DM
8722: . time    - The time
8723: . label   - The DMLabel selecting the portion of the mesh for projection
8724: . funcs   - The coordinate functions to evaluate, one per field
8725: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8726: - mode    - The insertion mode for values

8728:   Output Parameter:
8729: . X - vector

8731:    Calling sequence of func:
8732: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8734: +  dim - The spatial dimension
8735: .  x   - The coordinates
8736: .  Nf  - The number of fields
8737: .  u   - The output field values
8738: -  ctx - optional user-defined function context

8740:   Level: developer

8742: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8743: @*/
8744: 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)
8745: {
8746:   Vec            localX;

8751:   DMGetLocalVector(dm, &localX);
8752:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8753:   DMLocalToGlobalBegin(dm, localX, mode, X);
8754:   DMLocalToGlobalEnd(dm, localX, mode, X);
8755:   DMRestoreLocalVector(dm, &localX);
8756:   return(0);
8757: }

8759: /*@C
8760:   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.

8762:   Not collective

8764:   Input Parameters:
8765: + dm      - The DM
8766: . time    - The time
8767: . label   - The DMLabel selecting the portion of the mesh for projection
8768: . funcs   - The coordinate functions to evaluate, one per field
8769: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8770: - mode    - The insertion mode for values

8772:   Output Parameter:
8773: . localX - vector

8775:    Calling sequence of func:
8776: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8778: +  dim - The spatial dimension
8779: .  x   - The coordinates
8780: .  Nf  - The number of fields
8781: .  u   - The output field values
8782: -  ctx - optional user-defined function context

8784:   Level: developer

8786: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8787: @*/
8788: 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)
8789: {

8795:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8796:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8797:   return(0);
8798: }

8800: /*@C
8801:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8803:   Not collective

8805:   Input Parameters:
8806: + dm      - The DM
8807: . time    - The time
8808: . localU  - The input field vector
8809: . funcs   - The functions to evaluate, one per field
8810: - mode    - The insertion mode for values

8812:   Output Parameter:
8813: . localX  - The output vector

8815:    Calling sequence of func:
8816: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8817: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8818: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8819: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8821: +  dim          - The spatial dimension
8822: .  Nf           - The number of input fields
8823: .  NfAux        - The number of input auxiliary fields
8824: .  uOff         - The offset of each field in u[]
8825: .  uOff_x       - The offset of each field in u_x[]
8826: .  u            - The field values at this point in space
8827: .  u_t          - The field time derivative at this point in space (or NULL)
8828: .  u_x          - The field derivatives at this point in space
8829: .  aOff         - The offset of each auxiliary field in u[]
8830: .  aOff_x       - The offset of each auxiliary field in u_x[]
8831: .  a            - The auxiliary field values at this point in space
8832: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8833: .  a_x          - The auxiliary field derivatives at this point in space
8834: .  t            - The current time
8835: .  x            - The coordinates of this point
8836: .  numConstants - The number of constants
8837: .  constants    - The value of each constant
8838: -  f            - The value of the function at this point in space

8840:   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.
8841:   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
8842:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8843:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8845:   Level: intermediate

8847: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8848: @*/
8849: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8850:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8851:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8852:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8853:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8854:                                    InsertMode mode, Vec localX)
8855: {

8862:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8863:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8864:   return(0);
8865: }

8867: /*@C
8868:   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.

8870:   Not collective

8872:   Input Parameters:
8873: + dm      - The DM
8874: . time    - The time
8875: . label   - The DMLabel marking the portion of the domain to output
8876: . numIds  - The number of label ids to use
8877: . ids     - The label ids to use for marking
8878: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8879: . comps   - The components to set in the output, or NULL for all components
8880: . localU  - The input field vector
8881: . funcs   - The functions to evaluate, one per field
8882: - mode    - The insertion mode for values

8884:   Output Parameter:
8885: . localX  - The output vector

8887:    Calling sequence of func:
8888: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8889: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8890: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8891: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8893: +  dim          - The spatial dimension
8894: .  Nf           - The number of input fields
8895: .  NfAux        - The number of input auxiliary fields
8896: .  uOff         - The offset of each field in u[]
8897: .  uOff_x       - The offset of each field in u_x[]
8898: .  u            - The field values at this point in space
8899: .  u_t          - The field time derivative at this point in space (or NULL)
8900: .  u_x          - The field derivatives at this point in space
8901: .  aOff         - The offset of each auxiliary field in u[]
8902: .  aOff_x       - The offset of each auxiliary field in u_x[]
8903: .  a            - The auxiliary field values at this point in space
8904: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8905: .  a_x          - The auxiliary field derivatives at this point in space
8906: .  t            - The current time
8907: .  x            - The coordinates of this point
8908: .  numConstants - The number of constants
8909: .  constants    - The value of each constant
8910: -  f            - The value of the function at this point in space

8912:   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.
8913:   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
8914:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8915:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8917:   Level: intermediate

8919: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8920: @*/
8921: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8922:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8923:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8924:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8925:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8926:                                         InsertMode mode, Vec localX)
8927: {

8934:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8935:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8936:   return(0);
8937: }

8939: /*@C
8940:   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.

8942:   Not collective

8944:   Input Parameters:
8945: + dm      - The DM
8946: . time    - The time
8947: . label   - The DMLabel marking the portion of the domain boundary to output
8948: . numIds  - The number of label ids to use
8949: . ids     - The label ids to use for marking
8950: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8951: . comps   - The components to set in the output, or NULL for all components
8952: . localU  - The input field vector
8953: . funcs   - The functions to evaluate, one per field
8954: - mode    - The insertion mode for values

8956:   Output Parameter:
8957: . localX  - The output vector

8959:    Calling sequence of func:
8960: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8961: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8962: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8963: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8965: +  dim          - The spatial dimension
8966: .  Nf           - The number of input fields
8967: .  NfAux        - The number of input auxiliary fields
8968: .  uOff         - The offset of each field in u[]
8969: .  uOff_x       - The offset of each field in u_x[]
8970: .  u            - The field values at this point in space
8971: .  u_t          - The field time derivative at this point in space (or NULL)
8972: .  u_x          - The field derivatives at this point in space
8973: .  aOff         - The offset of each auxiliary field in u[]
8974: .  aOff_x       - The offset of each auxiliary field in u_x[]
8975: .  a            - The auxiliary field values at this point in space
8976: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8977: .  a_x          - The auxiliary field derivatives at this point in space
8978: .  t            - The current time
8979: .  x            - The coordinates of this point
8980: .  n            - The face normal
8981: .  numConstants - The number of constants
8982: .  constants    - The value of each constant
8983: -  f            - The value of the function at this point in space

8985:   Note:
8986:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8987:   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
8988:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8989:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8991:   Level: intermediate

8993: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8994: @*/
8995: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8996:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8997:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8998:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8999:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9000:                                           InsertMode mode, Vec localX)
9001: {

9008:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9009:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
9010:   return(0);
9011: }

9013: /*@C
9014:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

9016:   Input Parameters:
9017: + dm    - The DM
9018: . time  - The time
9019: . funcs - The functions to evaluate for each field component
9020: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9021: - X     - The coefficient vector u_h, a global vector

9023:   Output Parameter:
9024: . diff - The diff ||u - u_h||_2

9026:   Level: developer

9028: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9029: @*/
9030: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
9031: {

9037:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9038:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
9039:   return(0);
9040: }

9042: /*@C
9043:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

9045:   Collective on dm

9047:   Input Parameters:
9048: + dm    - The DM
9049: , time  - The time
9050: . funcs - The gradient functions to evaluate for each field component
9051: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9052: . X     - The coefficient vector u_h, a global vector
9053: - n     - The vector to project along

9055:   Output Parameter:
9056: . diff - The diff ||(grad u - grad u_h) . n||_2

9058:   Level: developer

9060: .seealso: DMProjectFunction(), DMComputeL2Diff()
9061: @*/
9062: 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)
9063: {

9069:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9070:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
9071:   return(0);
9072: }

9074: /*@C
9075:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

9077:   Collective on dm

9079:   Input Parameters:
9080: + dm    - The DM
9081: . time  - The time
9082: . funcs - The functions to evaluate for each field component
9083: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9084: - X     - The coefficient vector u_h, a global vector

9086:   Output Parameter:
9087: . diff - The array of differences, ||u^f - u^f_h||_2

9089:   Level: developer

9091: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9092: @*/
9093: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9094: {

9100:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9101:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9102:   return(0);
9103: }

9105: /*@C
9106:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
9107:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

9109:   Collective on dm

9111:   Input parameters:
9112: + dm - the pre-adaptation DM object
9113: - label - label with the flags

9115:   Output parameters:
9116: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

9118:   Level: intermediate

9120: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9121: @*/
9122: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9123: {

9130:   *dmAdapt = NULL;
9131:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9132:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
9133:   if (*dmAdapt) {
9134:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
9135:     PetscFree((*dmAdapt)->vectype);
9136:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9137:     PetscFree((*dmAdapt)->mattype);
9138:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9139:   }
9140:   return(0);
9141: }

9143: /*@C
9144:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

9146:   Input Parameters:
9147: + dm - The DM object
9148: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9149: - 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_".

9151:   Output Parameter:
9152: . dmAdapt  - Pointer to the DM object containing the adapted mesh

9154:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

9156:   Level: advanced

9158: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9159: @*/
9160: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9161: {

9169:   *dmAdapt = NULL;
9170:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9171:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9172:   return(0);
9173: }

9175: /*@C
9176:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

9178:  Not Collective

9180:  Input Parameter:
9181: .  dm    - The DM

9183:  Output Parameters:
9184: +  nranks - the number of neighbours
9185: -  ranks - the neighbors ranks

9187:  Notes:
9188:  Do not free the array, it is freed when the DM is destroyed.

9190:  Level: beginner

9192:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9193: @*/
9194: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9195: {

9200:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9201:   (dm->ops->getneighbors)(dm,nranks,ranks);
9202:   return(0);
9203: }

9205: #include <petsc/private/matimpl.h>

9207: /*
9208:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9209:     This has be a different function because it requires DM which is not defined in the Mat library
9210: */
9211: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9212: {

9216:   if (coloring->ctype == IS_COLORING_LOCAL) {
9217:     Vec x1local;
9218:     DM  dm;
9219:     MatGetDM(J,&dm);
9220:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9221:     DMGetLocalVector(dm,&x1local);
9222:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9223:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9224:     x1   = x1local;
9225:   }
9226:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9227:   if (coloring->ctype == IS_COLORING_LOCAL) {
9228:     DM  dm;
9229:     MatGetDM(J,&dm);
9230:     DMRestoreLocalVector(dm,&x1);
9231:   }
9232:   return(0);
9233: }

9235: /*@
9236:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

9238:     Input Parameter:
9239: .    coloring - the MatFDColoring object

9241:     Developer Notes:
9242:     this routine exists because the PETSc Mat library does not know about the DM objects

9244:     Level: advanced

9246: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9247: @*/
9248: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9249: {
9251:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9252:   return(0);
9253: }

9255: /*@
9256:     DMGetCompatibility - determine if two DMs are compatible

9258:     Collective

9260:     Input Parameters:
9261: +    dm1 - the first DM
9262: -    dm2 - the second DM

9264:     Output Parameters:
9265: +    compatible - whether or not the two DMs are compatible
9266: -    set - whether or not the compatible value was set

9268:     Notes:
9269:     Two DMs are deemed compatible if they represent the same parallel decomposition
9270:     of the same topology. This implies that the section (field data) on one
9271:     "makes sense" with respect to the topology and parallel decomposition of the other.
9272:     Loosely speaking, compatible DMs represent the same domain and parallel
9273:     decomposition, but hold different data.

9275:     Typically, one would confirm compatibility if intending to simultaneously iterate
9276:     over a pair of vectors obtained from different DMs.

9278:     For example, two DMDA objects are compatible if they have the same local
9279:     and global sizes and the same stencil width. They can have different numbers
9280:     of degrees of freedom per node. Thus, one could use the node numbering from
9281:     either DM in bounds for a loop over vectors derived from either DM.

9283:     Consider the operation of summing data living on a 2-dof DMDA to data living
9284:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9285: .vb
9286:   ...
9287:   DMGetCompatibility(da1,da2,&compatible,&set);
9288:   if (set && compatible)  {
9289:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9290:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9291:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9292:     for (j=y; j<y+n; ++j) {
9293:       for (i=x; i<x+m, ++i) {
9294:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9295:       }
9296:     }
9297:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9298:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9299:   } else {
9300:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9301:   }
9302:   ...
9303: .ve

9305:     Checking compatibility might be expensive for a given implementation of DM,
9306:     or might be impossible to unambiguously confirm or deny. For this reason,
9307:     this function may decline to determine compatibility, and hence users should
9308:     always check the "set" output parameter.

9310:     A DM is always compatible with itself.

9312:     In the current implementation, DMs which live on "unequal" communicators
9313:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9314:     incompatible.

9316:     This function is labeled "Collective," as information about all subdomains
9317:     is required on each rank. However, in DM implementations which store all this
9318:     information locally, this function may be merely "Logically Collective".

9320:     Developer Notes:
9321:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9322:     iff B is compatible with A. Thus, this function checks the implementations
9323:     of both dm and dmc (if they are of different types), attempting to determine
9324:     compatibility. It is left to DM implementers to ensure that symmetry is
9325:     preserved. The simplest way to do this is, when implementing type-specific
9326:     logic for this function, is to check for existing logic in the implementation
9327:     of other DM types and let *set = PETSC_FALSE if found.

9329:     Level: advanced

9331: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9332: @*/

9334: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9335: {
9337:   PetscMPIInt    compareResult;
9338:   DMType         type,type2;
9339:   PetscBool      sameType;


9345:   /* Declare a DM compatible with itself */
9346:   if (dm1 == dm2) {
9347:     *set = PETSC_TRUE;
9348:     *compatible = PETSC_TRUE;
9349:     return(0);
9350:   }

9352:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9353:      communicator. Note that this does not preclude compatibility with
9354:      DMs living on "congruent" or "similar" communicators, but this must be
9355:      determined by the implementation-specific logic */
9356:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9357:   if (compareResult == MPI_UNEQUAL) {
9358:     *set = PETSC_TRUE;
9359:     *compatible = PETSC_FALSE;
9360:     return(0);
9361:   }

9363:   /* Pass to the implementation-specific routine, if one exists. */
9364:   if (dm1->ops->getcompatibility) {
9365:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9366:     if (*set) return(0);
9367:   }

9369:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9370:      with an implementation of this function from dm2 */
9371:   DMGetType(dm1,&type);
9372:   DMGetType(dm2,&type2);
9373:   PetscStrcmp(type,type2,&sameType);
9374:   if (!sameType && dm2->ops->getcompatibility) {
9375:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9376:   } else {
9377:     *set = PETSC_FALSE;
9378:   }
9379:   return(0);
9380: }

9382: /*@C
9383:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

9385:   Logically Collective on DM

9387:   Input Parameters:
9388: + DM - the DM
9389: . f - the monitor function
9390: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9391: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

9393:   Options Database Keys:
9394: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9395:                             does not cancel those set via the options database.

9397:   Notes:
9398:   Several different monitoring routines may be set by calling
9399:   DMMonitorSet() multiple times; all will be called in the
9400:   order in which they were set.

9402:   Fortran Notes:
9403:   Only a single monitor function can be set for each DM object

9405:   Level: intermediate

9407: .seealso: DMMonitorCancel()
9408: @*/
9409: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9410: {
9411:   PetscInt       m;

9416:   for (m = 0; m < dm->numbermonitors; ++m) {
9417:     PetscBool identical;

9419:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9420:     if (identical) return(0);
9421:   }
9422:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9423:   dm->monitor[dm->numbermonitors]          = f;
9424:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9425:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9426:   return(0);
9427: }

9429: /*@
9430:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9432:   Logically Collective on DM

9434:   Input Parameter:
9435: . dm - the DM

9437:   Options Database Key:
9438: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9439:   into a code by calls to DMonitorSet(), but does not cancel those
9440:   set via the options database

9442:   Notes:
9443:   There is no way to clear one specific monitor from a DM object.

9445:   Level: intermediate

9447: .seealso: DMMonitorSet()
9448: @*/
9449: PetscErrorCode DMMonitorCancel(DM dm)
9450: {
9452:   PetscInt       m;

9456:   for (m = 0; m < dm->numbermonitors; ++m) {
9457:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9458:   }
9459:   dm->numbermonitors = 0;
9460:   return(0);
9461: }

9463: /*@C
9464:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9466:   Collective on DM

9468:   Input Parameters:
9469: + dm   - DM object you wish to monitor
9470: . name - the monitor type one is seeking
9471: . help - message indicating what monitoring is done
9472: . manual - manual page for the monitor
9473: . monitor - the monitor function
9474: - 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

9476:   Output Parameter:
9477: . flg - Flag set if the monitor was created

9479:   Level: developer

9481: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9482:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9483:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9484:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9485:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9486:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9487:           PetscOptionsFList(), PetscOptionsEList()
9488: @*/
9489: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9490: {
9491:   PetscViewer       viewer;
9492:   PetscViewerFormat format;
9493:   PetscErrorCode    ierr;

9497:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9498:   if (*flg) {
9499:     PetscViewerAndFormat *vf;

9501:     PetscViewerAndFormatCreate(viewer, format, &vf);
9502:     PetscObjectDereference((PetscObject) viewer);
9503:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9504:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9505:   }
9506:   return(0);
9507: }

9509: /*@
9510:    DMMonitor - runs the user provided monitor routines, if they exist

9512:    Collective on DM

9514:    Input Parameters:
9515: .  dm - The DM

9517:    Level: developer

9519: .seealso: DMMonitorSet()
9520: @*/
9521: PetscErrorCode DMMonitor(DM dm)
9522: {
9523:   PetscInt       m;

9527:   if (!dm) return(0);
9529:   for (m = 0; m < dm->numbermonitors; ++m) {
9530:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9531:   }
9532:   return(0);
9533: }

9535: /*@
9536:   DMComputeError - Computes the error assuming the user has given exact solution functions

9538:   Collective on DM

9540:   Input Parameters:
9541: + dm     - The DM
9542: - sol    - The solution vector

9544:   Input/Output Parameter:
9545: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9546:            contains the error in each field

9548:   Output Parameter:
9549: . errorVec - A vector to hold the cellwise error (may be NULL)

9551:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

9553:   Level: developer

9555: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9556: @*/
9557: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9558: {
9559:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9560:   void            **ctxs;
9561:   PetscReal         time;
9562:   PetscInt          Nf, f, Nds, s;
9563:   PetscErrorCode    ierr;

9566:   DMGetNumFields(dm, &Nf);
9567:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9568:   DMGetNumDS(dm, &Nds);
9569:   for (s = 0; s < Nds; ++s) {
9570:     PetscDS         ds;
9571:     DMLabel         label;
9572:     IS              fieldIS;
9573:     const PetscInt *fields;
9574:     PetscInt        dsNf;

9576:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9577:     PetscDSGetNumFields(ds, &dsNf);
9578:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9579:     for (f = 0; f < dsNf; ++f) {
9580:       const PetscInt field = fields[f];
9581:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9582:     }
9583:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9584:   }
9585:   for (f = 0; f < Nf; ++f) {
9586:     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);
9587:   }
9588:   DMGetOutputSequenceNumber(dm, NULL, &time);
9589:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9590:   if (errorVec) {
9591:     DM             edm;
9592:     DMPolytopeType ct;
9593:     PetscBool      simplex;
9594:     PetscInt       dim, cStart, Nf;

9596:     DMClone(dm, &edm);
9597:     DMGetDimension(edm, &dim);
9598:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9599:     DMPlexGetCellType(dm, cStart, &ct);
9600:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9601:     DMGetNumFields(dm, &Nf);
9602:     for (f = 0; f < Nf; ++f) {
9603:       PetscFE         fe, efe;
9604:       PetscQuadrature q;
9605:       const char     *name;

9607:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
9608:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9609:       PetscObjectGetName((PetscObject) fe, &name);
9610:       PetscObjectSetName((PetscObject) efe, name);
9611:       PetscFEGetQuadrature(fe, &q);
9612:       PetscFESetQuadrature(efe, q);
9613:       DMSetField(edm, f, NULL, (PetscObject) efe);
9614:       PetscFEDestroy(&efe);
9615:     }
9616:     DMCreateDS(edm);

9618:     DMCreateGlobalVector(edm, errorVec);
9619:     PetscObjectSetName((PetscObject) *errorVec, "Error");
9620:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9621:     DMDestroy(&edm);
9622:   }
9623:   PetscFree2(exactSol, ctxs);
9624:   return(0);
9625: }

9627: /*@
9628:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

9630:   Not collective

9632:   Input Parameter:
9633: . dm     - The DM

9635:   Output Parameter:
9636: . numAux - The number of auxiliary data vectors

9638:   Level: advanced

9640: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9641: @*/
9642: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9643: {

9648:   PetscHMapAuxGetSize(dm->auxData, numAux);
9649:   return(0);
9650: }

9652: /*@
9653:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value

9655:   Not collective

9657:   Input Parameters:
9658: + dm     - The DM
9659: . label  - The DMLabel
9660: - value  - The label value indicating the region

9662:   Output Parameter:
9663: . aux    - The Vec holding auxiliary field data

9665:   Note: If no auxiliary vector is found for this (label, value), (NULL, 0) is checked as well.

9667:   Level: advanced

9669: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9670: @*/
9671: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec *aux)
9672: {
9673:   PetscHashAuxKey key, wild = {NULL, 0};
9674:   PetscBool       has;
9675:   PetscErrorCode  ierr;

9680:   key.label = label;
9681:   key.value = value;
9682:   PetscHMapAuxHas(dm->auxData, key, &has);
9683:   if (has) {PetscHMapAuxGet(dm->auxData, key,  aux);}
9684:   else     {PetscHMapAuxGet(dm->auxData, wild, aux);}
9685:   return(0);
9686: }

9688: /*@
9689:   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value

9691:   Not collective

9693:   Input Parameters:
9694: + dm     - The DM
9695: . label  - The DMLabel
9696: . value  - The label value indicating the region
9697: - aux    - The Vec holding auxiliary field data

9699:   Level: advanced

9701: .seealso: DMGetAuxiliaryVec()
9702: @*/
9703: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec aux)
9704: {
9705:   Vec             old;
9706:   PetscHashAuxKey key;
9707:   PetscErrorCode  ierr;

9712:   key.label = label;
9713:   key.value = value;
9714:   PetscHMapAuxGet(dm->auxData, key, &old);
9715:   PetscObjectReference((PetscObject) aux);
9716:   PetscObjectDereference((PetscObject) old);
9717:   if (!aux) {PetscHMapAuxDel(dm->auxData, key);}
9718:   else      {PetscHMapAuxSet(dm->auxData, key, aux);}
9719:   return(0);
9720: }

9722: /*@C
9723:   DMGetAuxiliaryLabels - Get the labels and values for all auxiliary vectors in this DM

9725:   Not collective

9727:   Input Parameter:
9728: . dm      - The DM

9730:   Output Parameters:
9731: + labels  - The DMLabels for each Vec
9732: - values  - The label values for each Vec

9734:   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().

9736:   Level: advanced

9738: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9739: @*/
9740: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[])
9741: {
9742:   PetscHashAuxKey *keys;
9743:   PetscInt         n, i, off = 0;
9744:   PetscErrorCode   ierr;

9750:   DMGetNumAuxiliaryVec(dm, &n);
9751:   PetscMalloc1(n, &keys);
9752:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
9753:   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value;}
9754:   PetscFree(keys);
9755:   return(0);
9756: }

9758: /*@
9759:   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM

9761:   Not collective

9763:   Input Parameter:
9764: . dm    - The DM

9766:   Output Parameter:
9767: . dmNew - The new DM, now with the same auxiliary data

9769:   Level: advanced

9771: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9772: @*/
9773: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9774: {

9779:   PetscHMapAuxDestroy(&dmNew->auxData);
9780:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
9781:   return(0);
9782: }

9784: /*@C
9785:   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

9787:   Not collective

9789:   Input Parameters:
9790: + ct         - The DMPolytopeType
9791: . sourceCone - The source arrangement of faces
9792: - targetCone - The target arrangement of faces

9794:   Output Parameters:
9795: + ornt  - The orientation which will take the source arrangement to the target arrangement
9796: - found - Flag indicating that a suitable orientation was found

9798:   Level: advanced

9800: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
9801: @*/
9802: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9803: {
9804:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9805:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9806:   PetscInt       o, c;

9809:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9810:   for (o = -nO; o < nO; ++o) {
9811:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

9813:     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9814:     if (c == cS) {*ornt = o; break;}
9815:   }
9816:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9817:   return(0);
9818: }

9820: /*@C
9821:   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

9823:   Not collective

9825:   Input Parameters:
9826: + ct         - The DMPolytopeType
9827: . sourceCone - The source arrangement of faces
9828: - targetCone - The target arrangement of faces

9830:   Output Parameters:
9831: . ornt  - The orientation which will take the source arrangement to the target arrangement

9833:   Note: This function will fail if no suitable orientation can be found.

9835:   Level: advanced

9837: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
9838: @*/
9839: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9840: {
9841:   PetscBool      found;

9845:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
9846:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9847:   return(0);
9848: }

9850: /*@C
9851:   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

9853:   Not collective

9855:   Input Parameters:
9856: + ct         - The DMPolytopeType
9857: . sourceVert - The source arrangement of vertices
9858: - targetVert - The target arrangement of vertices

9860:   Output Parameters:
9861: + ornt  - The orientation which will take the source arrangement to the target arrangement
9862: - found - Flag indicating that a suitable orientation was found

9864:   Level: advanced

9866: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
9867: @*/
9868: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9869: {
9870:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9871:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9872:   PetscInt       o, c;

9875:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
9876:   for (o = -nO; o < nO; ++o) {
9877:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

9879:     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9880:     if (c == cS) {*ornt = o; break;}
9881:   }
9882:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9883:   return(0);
9884: }

9886: /*@C
9887:   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

9889:   Not collective

9891:   Input Parameters:
9892: + ct         - The DMPolytopeType
9893: . sourceCone - The source arrangement of vertices
9894: - targetCone - The target arrangement of vertices

9896:   Output Parameters:
9897: . ornt  - The orientation which will take the source arrangement to the target arrangement

9899:   Note: This function will fail if no suitable orientation can be found.

9901:   Level: advanced

9903: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
9904: @*/
9905: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9906: {
9907:   PetscBool      found;

9911:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
9912:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9913:   return(0);
9914: }

9916: /*@C
9917:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

9919:   Not collective

9921:   Input Parameters:
9922: + ct    - The DMPolytopeType
9923: - point - Coordinates of the point

9925:   Output Parameters:
9926: . inside  - Flag indicating whether the point is inside the reference cell of given type

9928:   Level: advanced

9930: .seealso: DMLocatePoints()
9931: @*/
9932: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9933: {
9934:   PetscReal sum = 0.0;
9935:   PetscInt  d;

9938:   *inside = PETSC_TRUE;
9939:   switch (ct) {
9940:   case DM_POLYTOPE_TRIANGLE:
9941:   case DM_POLYTOPE_TETRAHEDRON:
9942:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9943:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
9944:       sum += point[d];
9945:     }
9946:     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9947:     break;
9948:   case DM_POLYTOPE_QUADRILATERAL:
9949:   case DM_POLYTOPE_HEXAHEDRON:
9950:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9951:       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
9952:     break;
9953:   default:
9954:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9955:   }
9956:   return(0);
9957: }