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:   if (dm->dim >= 0) {
6027:     DMGetNumDS(dm, &Nds);
6028:     for (n = 0; n < Nds; ++n) {
6029:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6030:       if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
6031:     }
6032:   }
6033:   return(0);
6034: }

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

6039:   Collective on dm

6041:   Input Parameters:
6042: + dm - the DM
6043: - dim - the dimension

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

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

6054:   Level: intermediate

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

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

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

6075:   Collective on dm

6077:   Input Parameters:
6078: + dm - the DM
6079: - c - coordinate vector

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

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

6086:   Level: intermediate

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

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

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

6109:   Not collective

6111:    Input Parameters:
6112: +  dm - the DM
6113: -  c - coordinate vector

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

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

6122:   Level: intermediate

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

6133:   PetscObjectReference((PetscObject) c);
6134:   VecDestroy(&dm->coordinatesLocal);

6136:   dm->coordinatesLocal = c;

6138:   VecDestroy(&dm->coordinates);
6139:   return(0);
6140: }

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

6145:   Collective on dm

6147:   Input Parameter:
6148: . dm - the DM

6150:   Output Parameter:
6151: . c - global coordinate vector

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

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

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

6162:   Level: intermediate

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

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

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

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

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

6198:   Collective on dm

6200:   Input Parameter:
6201: . dm - the DM

6203:   Level: advanced

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

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

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

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

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

6237:   Collective on dm

6239:   Input Parameter:
6240: . dm - the DM

6242:   Output Parameter:
6243: . c - coordinate vector

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

6248:   Each process has the local and ghost coordinates

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

6253:   Level: intermediate

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

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

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

6272:   Not collective

6274:   Input Parameter:
6275: . dm - the DM

6277:   Output Parameter:
6278: . c - coordinate vector

6280:   Level: advanced

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

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

6297:   Not collective

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

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

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

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

6312:   Each process has the local and ghost coordinates

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

6317:   Level: advanced

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

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

6355: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6356: {

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

6371: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6372: {

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

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

6387:   Collective on dm

6389:   Input Parameter:
6390: . dm - the DM

6392:   Output Parameter:
6393: . cdm - coordinate DM

6395:   Level: intermediate

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

6406:   if (!dm->coordinateDM) {
6407:     DM cdm;

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

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

6423:   Logically Collective on dm

6425:   Input Parameters:
6426: + dm - the DM
6427: - cdm - coordinate DM

6429:   Level: intermediate

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

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

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

6449:   Not Collective

6451:   Input Parameter:
6452: . dm - The DM object

6454:   Output Parameter:
6455: . dim - The embedding dimension

6457:   Level: intermediate

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

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

6476:   Not Collective

6478:   Input Parameters:
6479: + dm  - The DM object
6480: - dim - The embedding dimension

6482:   Level: intermediate

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

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

6505: /*@
6506:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6508:   Collective on dm

6510:   Input Parameter:
6511: . dm - The DM object

6513:   Output Parameter:
6514: . section - The PetscSection object

6516:   Level: intermediate

6518: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6519: @*/
6520: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6521: {
6522:   DM             cdm;

6528:   DMGetCoordinateDM(dm, &cdm);
6529:   DMGetLocalSection(cdm, section);
6530:   return(0);
6531: }

6533: /*@
6534:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6536:   Not Collective

6538:   Input Parameters:
6539: + dm      - The DM object
6540: . dim     - The embedding dimension, or PETSC_DETERMINE
6541: - section - The PetscSection object

6543:   Level: intermediate

6545: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6546: @*/
6547: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6548: {
6549:   DM             cdm;

6555:   DMGetCoordinateDM(dm, &cdm);
6556:   DMSetLocalSection(cdm, section);
6557:   if (dim == PETSC_DETERMINE) {
6558:     PetscInt d = PETSC_DEFAULT;
6559:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

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

6574: /*@
6575:   DMProjectCoordinates - Project coordinates to a different space

6577:   Input Parameters:
6578: + dm      - The DM object
6579: - disc    - The new coordinate discretization

6581:   Level: intermediate

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


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

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

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

6651: /*@C
6652:   DMGetPeriodicity - Get the description of mesh periodicity

6654:   Input Parameter:
6655: . dm      - The DM object

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

6663:   Level: developer

6665: .seealso: DMGetPeriodicity()
6666: @*/
6667: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6668: {
6671:   if (per)     *per     = dm->periodic;
6672:   if (L)       *L       = dm->L;
6673:   if (maxCell) *maxCell = dm->maxCell;
6674:   if (bd)      *bd      = dm->bdtype;
6675:   return(0);
6676: }

6678: /*@C
6679:   DMSetPeriodicity - Set the description of mesh periodicity

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

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

6690:   Level: developer

6692: .seealso: DMGetPeriodicity()
6693: @*/
6694: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6695: {
6696:   PetscInt       dim, d;

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

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

6725: /*@
6726:   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.

6728:   Input Parameters:
6729: + dm     - The DM
6730: . in     - The input coordinate point (dim numbers)
6731: - endpoint - Include the endpoint L_i

6733:   Output Parameter:
6734: . out - The localized coordinate point

6736:   Level: developer

6738: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6739: @*/
6740: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6741: {
6742:   PetscInt       dim, d;

6746:   DMGetCoordinateDim(dm, &dim);
6747:   if (!dm->maxCell) {
6748:     for (d = 0; d < dim; ++d) out[d] = in[d];
6749:   } else {
6750:     if (endpoint) {
6751:       for (d = 0; d < dim; ++d) {
6752:         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)) {
6753:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6754:         } else {
6755:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6756:         }
6757:       }
6758:     } else {
6759:       for (d = 0; d < dim; ++d) {
6760:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6761:       }
6762:     }
6763:   }
6764:   return(0);
6765: }

6767: /*
6768:   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.

6770:   Input Parameters:
6771: + dm     - The DM
6772: . dim    - The spatial dimension
6773: . anchor - The anchor point, the input point can be no more than maxCell away from it
6774: - in     - The input coordinate point (dim numbers)

6776:   Output Parameter:
6777: . out - The localized coordinate point

6779:   Level: developer

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

6783: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6784: */
6785: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6786: {
6787:   PetscInt d;

6790:   if (!dm->maxCell) {
6791:     for (d = 0; d < dim; ++d) out[d] = in[d];
6792:   } else {
6793:     for (d = 0; d < dim; ++d) {
6794:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6795:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6796:       } else {
6797:         out[d] = in[d];
6798:       }
6799:     }
6800:   }
6801:   return(0);
6802: }

6804: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6805: {
6806:   PetscInt d;

6809:   if (!dm->maxCell) {
6810:     for (d = 0; d < dim; ++d) out[d] = in[d];
6811:   } else {
6812:     for (d = 0; d < dim; ++d) {
6813:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6814:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6815:       } else {
6816:         out[d] = in[d];
6817:       }
6818:     }
6819:   }
6820:   return(0);
6821: }

6823: /*
6824:   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.

6826:   Input Parameters:
6827: + dm     - The DM
6828: . dim    - The spatial dimension
6829: . anchor - The anchor point, the input point can be no more than maxCell away from it
6830: . in     - The input coordinate delta (dim numbers)
6831: - out    - The input coordinate point (dim numbers)

6833:   Output Parameter:
6834: . out    - The localized coordinate in + out

6836:   Level: developer

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

6840: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6841: */
6842: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6843: {
6844:   PetscInt d;

6847:   if (!dm->maxCell) {
6848:     for (d = 0; d < dim; ++d) out[d] += in[d];
6849:   } else {
6850:     for (d = 0; d < dim; ++d) {
6851:       const PetscReal maxC = dm->maxCell[d];

6853:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6854:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6856:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6857:           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]));
6858:         out[d] += newCoord;
6859:       } else {
6860:         out[d] += in[d];
6861:       }
6862:     }
6863:   }
6864:   return(0);
6865: }

6867: /*@
6868:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6870:   Not collective

6872:   Input Parameter:
6873: . dm - The DM

6875:   Output Parameter:
6876:   areLocalized - True if localized

6878:   Level: developer

6880: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6881: @*/
6882: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6883: {
6884:   DM             cdm;
6885:   PetscSection   coordSection;
6886:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
6887:   PetscBool      isPlex, alreadyLocalized;

6893:   *areLocalized = PETSC_FALSE;

6895:   /* We need some generic way of refering to cells/vertices */
6896:   DMGetCoordinateDM(dm, &cdm);
6897:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6898:   if (!isPlex) return(0);
6899:   DMPlexGetDepth(cdm, &depth);
6900:   if (!depth) return(0);

6902:   DMGetCoordinateSection(dm, &coordSection);
6903:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6904:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6905:   alreadyLocalized = PETSC_FALSE;
6906:   for (c = cStart; c < cEnd; ++c) {
6907:     if (c < sStart || c >= sEnd) continue;
6908:     PetscSectionGetDof(coordSection, c, &dof);
6909:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6910:   }
6911:   *areLocalized = alreadyLocalized;
6912:   return(0);
6913: }

6915: /*@
6916:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6918:   Collective on dm

6920:   Input Parameter:
6921: . dm - The DM

6923:   Output Parameter:
6924:   areLocalized - True if localized

6926:   Level: developer

6928: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6929: @*/
6930: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6931: {
6932:   PetscBool      localized;

6938:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6939:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6940:   return(0);
6941: }

6943: /*@
6944:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6946:   Collective on dm

6948:   Input Parameter:
6949: . dm - The DM

6951:   Level: developer

6953: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6954: @*/
6955: PetscErrorCode DMLocalizeCoordinates(DM dm)
6956: {
6957:   DM             cdm;
6958:   PetscSection   coordSection, cSection;
6959:   Vec            coordinates,  cVec;
6960:   PetscScalar   *coords, *coords2, *anchor, *localized;
6961:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6962:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6963:   PetscInt       maxHeight = 0, h;
6964:   PetscInt       *pStart = NULL, *pEnd = NULL;

6969:   if (!dm->periodic) return(0);
6970:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6971:   if (alreadyLocalized) return(0);

6973:   /* We need some generic way of refering to cells/vertices */
6974:   DMGetCoordinateDM(dm, &cdm);
6975:   {
6976:     PetscBool isplex;

6978:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6979:     if (isplex) {
6980:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6981:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6982:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6983:       pEnd = &pStart[maxHeight + 1];
6984:       newStart = vStart;
6985:       newEnd   = vEnd;
6986:       for (h = 0; h <= maxHeight; h++) {
6987:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6988:         newStart = PetscMin(newStart,pStart[h]);
6989:         newEnd   = PetscMax(newEnd,pEnd[h]);
6990:       }
6991:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6992:   }
6993:   DMGetCoordinatesLocal(dm, &coordinates);
6994:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6995:   DMGetCoordinateSection(dm, &coordSection);
6996:   VecGetBlockSize(coordinates, &bs);
6997:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6999:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
7000:   PetscSectionSetNumFields(cSection, 1);
7001:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
7002:   PetscSectionSetFieldComponents(cSection, 0, Nc);
7003:   PetscSectionSetChart(cSection, newStart, newEnd);

7005:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7006:   localized = &anchor[bs];
7007:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7008:   for (h = 0; h <= maxHeight; h++) {
7009:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7011:     for (c = cStart; c < cEnd; ++c) {
7012:       PetscScalar *cellCoords = NULL;
7013:       PetscInt     b;

7015:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7016:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7017:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7018:       for (d = 0; d < dof/bs; ++d) {
7019:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
7020:         for (b = 0; b < bs; b++) {
7021:           if (cellCoords[d*bs + b] != localized[b]) break;
7022:         }
7023:         if (b < bs) break;
7024:       }
7025:       if (d < dof/bs) {
7026:         if (c >= sStart && c < sEnd) {
7027:           PetscInt cdof;

7029:           PetscSectionGetDof(coordSection, c, &cdof);
7030:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7031:         }
7032:         PetscSectionSetDof(cSection, c, dof);
7033:         PetscSectionSetFieldDof(cSection, c, 0, dof);
7034:       }
7035:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7036:     }
7037:   }
7038:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
7039:   if (alreadyLocalizedGlobal) {
7040:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7041:     PetscSectionDestroy(&cSection);
7042:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7043:     return(0);
7044:   }
7045:   for (v = vStart; v < vEnd; ++v) {
7046:     PetscSectionGetDof(coordSection, v, &dof);
7047:     PetscSectionSetDof(cSection, v, dof);
7048:     PetscSectionSetFieldDof(cSection, v, 0, dof);
7049:   }
7050:   PetscSectionSetUp(cSection);
7051:   PetscSectionGetStorageSize(cSection, &coordSize);
7052:   VecCreate(PETSC_COMM_SELF, &cVec);
7053:   PetscObjectSetName((PetscObject)cVec,"coordinates");
7054:   VecSetBlockSize(cVec, bs);
7055:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
7056:   VecSetType(cVec, VECSTANDARD);
7057:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
7058:   VecGetArray(cVec, &coords2);
7059:   for (v = vStart; v < vEnd; ++v) {
7060:     PetscSectionGetDof(coordSection, v, &dof);
7061:     PetscSectionGetOffset(coordSection, v, &off);
7062:     PetscSectionGetOffset(cSection,     v, &off2);
7063:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7064:   }
7065:   for (h = 0; h <= maxHeight; h++) {
7066:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

7068:     for (c = cStart; c < cEnd; ++c) {
7069:       PetscScalar *cellCoords = NULL;
7070:       PetscInt     b, cdof;

7072:       PetscSectionGetDof(cSection,c,&cdof);
7073:       if (!cdof) continue;
7074:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7075:       PetscSectionGetOffset(cSection, c, &off2);
7076:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7077:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
7078:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
7079:     }
7080:   }
7081:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
7082:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
7083:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
7084:   VecRestoreArray(cVec, &coords2);
7085:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
7086:   DMSetCoordinatesLocal(dm, cVec);
7087:   VecDestroy(&cVec);
7088:   PetscSectionDestroy(&cSection);
7089:   return(0);
7090: }

7092: /*@
7093:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

7095:   Collective on v (see explanation below)

7097:   Input Parameters:
7098: + dm - The DM
7099: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

7101:   Input/Output Parameters:
7102: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7103: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7104:            on output, the PetscSF containing the ranks and local indices of the containing points

7106:   Level: developer

7108:   Notes:
7109:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7110:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

7112:   If *cellSF is NULL on input, a PetscSF will be created.
7113:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

7115:   An array that maps each point to its containing cell can be obtained with

7117: $    const PetscSFNode *cells;
7118: $    PetscInt           nFound;
7119: $    const PetscInt    *found;
7120: $
7121: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

7123:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7124:   the index of the cell in its rank's local numbering.

7126: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7127: @*/
7128: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7129: {

7136:   if (*cellSF) {
7137:     PetscMPIInt result;

7140:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7141:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7142:   } else {
7143:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7144:   }
7145:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7146:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7147:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7148:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7149:   return(0);
7150: }

7152: /*@
7153:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7155:   Collective on dm

7157:   Input Parameter:
7158: . dm - The original DM

7160:   Output Parameter:
7161: . odm - The DM which provides the layout for output

7163:   Level: intermediate

7165: .seealso: VecView(), DMGetGlobalSection()
7166: @*/
7167: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7168: {
7169:   PetscSection   section;
7170:   PetscBool      hasConstraints, ghasConstraints;

7176:   DMGetLocalSection(dm, &section);
7177:   PetscSectionHasConstraints(section, &hasConstraints);
7178:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7179:   if (!ghasConstraints) {
7180:     *odm = dm;
7181:     return(0);
7182:   }
7183:   if (!dm->dmBC) {
7184:     PetscSection newSection, gsection;
7185:     PetscSF      sf;

7187:     DMClone(dm, &dm->dmBC);
7188:     DMCopyDisc(dm, dm->dmBC);
7189:     PetscSectionClone(section, &newSection);
7190:     DMSetLocalSection(dm->dmBC, newSection);
7191:     PetscSectionDestroy(&newSection);
7192:     DMGetPointSF(dm->dmBC, &sf);
7193:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7194:     DMSetGlobalSection(dm->dmBC, gsection);
7195:     PetscSectionDestroy(&gsection);
7196:   }
7197:   *odm = dm->dmBC;
7198:   return(0);
7199: }

7201: /*@
7202:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7204:   Input Parameter:
7205: . dm - The original DM

7207:   Output Parameters:
7208: + num - The output sequence number
7209: - val - The output sequence value

7211:   Level: intermediate

7213:   Note: This is intended for output that should appear in sequence, for instance
7214:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7216: .seealso: VecView()
7217: @*/
7218: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7219: {
7224:   return(0);
7225: }

7227: /*@
7228:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7230:   Input Parameters:
7231: + dm - The original DM
7232: . num - The output sequence number
7233: - val - The output sequence value

7235:   Level: intermediate

7237:   Note: This is intended for output that should appear in sequence, for instance
7238:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7240: .seealso: VecView()
7241: @*/
7242: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7243: {
7246:   dm->outputSequenceNum = num;
7247:   dm->outputSequenceVal = val;
7248:   return(0);
7249: }

7251: /*@C
7252:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7254:   Input Parameters:
7255: + dm   - The original DM
7256: . name - The sequence name
7257: - num  - The output sequence number

7259:   Output Parameter:
7260: . val  - The output sequence value

7262:   Level: intermediate

7264:   Note: This is intended for output that should appear in sequence, for instance
7265:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

7267: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7268: @*/
7269: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7270: {
7271:   PetscBool      ishdf5;

7278:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7279:   if (ishdf5) {
7280: #if defined(PETSC_HAVE_HDF5)
7281:     PetscScalar value;

7283:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7284:     *val = PetscRealPart(value);
7285: #endif
7286:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7287:   return(0);
7288: }

7290: /*@
7291:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

7293:   Not collective

7295:   Input Parameter:
7296: . dm - The DM

7298:   Output Parameter:
7299: . useNatural - The flag to build the mapping to a natural order during distribution

7301:   Level: beginner

7303: .seealso: DMSetUseNatural(), DMCreate()
7304: @*/
7305: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7306: {
7310:   *useNatural = dm->useNatural;
7311:   return(0);
7312: }

7314: /*@
7315:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7317:   Collective on dm

7319:   Input Parameters:
7320: + dm - The DM
7321: - useNatural - The flag to build the mapping to a natural order during distribution

7323:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7325:   Level: beginner

7327: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7328: @*/
7329: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7330: {
7334:   dm->useNatural = useNatural;
7335:   return(0);
7336: }

7338: /*@C
7339:   DMCreateLabel - Create a label of the given name if it does not already exist

7341:   Not Collective

7343:   Input Parameters:
7344: + dm   - The DM object
7345: - name - The label name

7347:   Level: intermediate

7349: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7350: @*/
7351: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7352: {
7353:   PetscBool      flg;
7354:   DMLabel        label;

7360:   DMHasLabel(dm, name, &flg);
7361:   if (!flg) {
7362:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7363:     DMAddLabel(dm, label);
7364:     DMLabelDestroy(&label);
7365:   }
7366:   return(0);
7367: }

7369: /*@C
7370:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

7372:   Not Collective

7374:   Input Parameters:
7375: + dm   - The DM object
7376: . l    - The index for the label
7377: - name - The label name

7379:   Level: intermediate

7381: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7382: @*/
7383: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7384: {
7385:   DMLabelLink    orig, prev = NULL;
7386:   DMLabel        label;
7387:   PetscInt       Nl, m;
7388:   PetscBool      flg, match;
7389:   const char    *lname;

7395:   DMHasLabel(dm, name, &flg);
7396:   if (!flg) {
7397:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7398:     DMAddLabel(dm, label);
7399:     DMLabelDestroy(&label);
7400:   }
7401:   DMGetNumLabels(dm, &Nl);
7402:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7403:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7404:     PetscObjectGetName((PetscObject) orig->label, &lname);
7405:     PetscStrcmp(name, lname, &match);
7406:     if (match) break;
7407:   }
7408:   if (m == l) return(0);
7409:   if (!m) dm->labels = orig->next;
7410:   else    prev->next = orig->next;
7411:   if (!l) {
7412:     orig->next = dm->labels;
7413:     dm->labels = orig;
7414:   } else {
7415:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7416:     orig->next = prev->next;
7417:     prev->next = orig;
7418:   }
7419:   return(0);
7420: }

7422: /*@C
7423:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

7425:   Not Collective

7427:   Input Parameters:
7428: + dm   - The DM object
7429: . name - The label name
7430: - point - The mesh point

7432:   Output Parameter:
7433: . value - The label value for this point, or -1 if the point is not in the label

7435:   Level: beginner

7437: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7438: @*/
7439: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7440: {
7441:   DMLabel        label;

7447:   DMGetLabel(dm, name, &label);
7448:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7449:   DMLabelGetValue(label, point, value);
7450:   return(0);
7451: }

7453: /*@C
7454:   DMSetLabelValue - Add a point to a Sieve Label with given value

7456:   Not Collective

7458:   Input Parameters:
7459: + dm   - The DM object
7460: . name - The label name
7461: . point - The mesh point
7462: - value - The label value for this point

7464:   Output Parameter:

7466:   Level: beginner

7468: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7469: @*/
7470: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7471: {
7472:   DMLabel        label;

7478:   DMGetLabel(dm, name, &label);
7479:   if (!label) {
7480:     DMCreateLabel(dm, name);
7481:     DMGetLabel(dm, name, &label);
7482:   }
7483:   DMLabelSetValue(label, point, value);
7484:   return(0);
7485: }

7487: /*@C
7488:   DMClearLabelValue - Remove a point from a Sieve Label with given value

7490:   Not Collective

7492:   Input Parameters:
7493: + dm   - The DM object
7494: . name - The label name
7495: . point - The mesh point
7496: - value - The label value for this point

7498:   Output Parameter:

7500:   Level: beginner

7502: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7503: @*/
7504: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7505: {
7506:   DMLabel        label;

7512:   DMGetLabel(dm, name, &label);
7513:   if (!label) return(0);
7514:   DMLabelClearValue(label, point, value);
7515:   return(0);
7516: }

7518: /*@C
7519:   DMGetLabelSize - Get the number of different integer ids in a Label

7521:   Not Collective

7523:   Input Parameters:
7524: + dm   - The DM object
7525: - name - The label name

7527:   Output Parameter:
7528: . size - The number of different integer ids, or 0 if the label does not exist

7530:   Level: beginner

7532: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7533: @*/
7534: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7535: {
7536:   DMLabel        label;

7543:   DMGetLabel(dm, name, &label);
7544:   *size = 0;
7545:   if (!label) return(0);
7546:   DMLabelGetNumValues(label, size);
7547:   return(0);
7548: }

7550: /*@C
7551:   DMGetLabelIdIS - Get the integer ids in a label

7553:   Not Collective

7555:   Input Parameters:
7556: + mesh - The DM object
7557: - name - The label name

7559:   Output Parameter:
7560: . ids - The integer ids, or NULL if the label does not exist

7562:   Level: beginner

7564: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7565: @*/
7566: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7567: {
7568:   DMLabel        label;

7575:   DMGetLabel(dm, name, &label);
7576:   *ids = NULL;
7577:  if (label) {
7578:     DMLabelGetValueIS(label, ids);
7579:   } else {
7580:     /* returning an empty IS */
7581:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7582:   }
7583:   return(0);
7584: }

7586: /*@C
7587:   DMGetStratumSize - Get the number of points in a label stratum

7589:   Not Collective

7591:   Input Parameters:
7592: + dm - The DM object
7593: . name - The label name
7594: - value - The stratum value

7596:   Output Parameter:
7597: . size - The stratum size

7599:   Level: beginner

7601: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7602: @*/
7603: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7604: {
7605:   DMLabel        label;

7612:   DMGetLabel(dm, name, &label);
7613:   *size = 0;
7614:   if (!label) return(0);
7615:   DMLabelGetStratumSize(label, value, size);
7616:   return(0);
7617: }

7619: /*@C
7620:   DMGetStratumIS - Get the points in a label stratum

7622:   Not Collective

7624:   Input Parameters:
7625: + dm - The DM object
7626: . name - The label name
7627: - value - The stratum value

7629:   Output Parameter:
7630: . points - The stratum points, or NULL if the label does not exist or does not have that value

7632:   Level: beginner

7634: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7635: @*/
7636: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7637: {
7638:   DMLabel        label;

7645:   DMGetLabel(dm, name, &label);
7646:   *points = NULL;
7647:   if (!label) return(0);
7648:   DMLabelGetStratumIS(label, value, points);
7649:   return(0);
7650: }

7652: /*@C
7653:   DMSetStratumIS - Set the points in a label stratum

7655:   Not Collective

7657:   Input Parameters:
7658: + dm - The DM object
7659: . name - The label name
7660: . value - The stratum value
7661: - points - The stratum points

7663:   Level: beginner

7665: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7666: @*/
7667: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7668: {
7669:   DMLabel        label;

7676:   DMGetLabel(dm, name, &label);
7677:   if (!label) return(0);
7678:   DMLabelSetStratumIS(label, value, points);
7679:   return(0);
7680: }

7682: /*@C
7683:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7685:   Not Collective

7687:   Input Parameters:
7688: + dm   - The DM object
7689: . name - The label name
7690: - value - The label value for this point

7692:   Output Parameter:

7694:   Level: beginner

7696: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7697: @*/
7698: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7699: {
7700:   DMLabel        label;

7706:   DMGetLabel(dm, name, &label);
7707:   if (!label) return(0);
7708:   DMLabelClearStratum(label, value);
7709:   return(0);
7710: }

7712: /*@
7713:   DMGetNumLabels - Return the number of labels defined by the mesh

7715:   Not Collective

7717:   Input Parameter:
7718: . dm   - The DM object

7720:   Output Parameter:
7721: . numLabels - the number of Labels

7723:   Level: intermediate

7725: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7726: @*/
7727: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7728: {
7729:   DMLabelLink next = dm->labels;
7730:   PetscInt  n    = 0;

7735:   while (next) {++n; next = next->next;}
7736:   *numLabels = n;
7737:   return(0);
7738: }

7740: /*@C
7741:   DMGetLabelName - Return the name of nth label

7743:   Not Collective

7745:   Input Parameters:
7746: + dm - The DM object
7747: - n  - the label number

7749:   Output Parameter:
7750: . name - the label name

7752:   Level: intermediate

7754: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7755: @*/
7756: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7757: {
7758:   DMLabelLink    next = dm->labels;
7759:   PetscInt       l    = 0;

7765:   while (next) {
7766:     if (l == n) {
7767:       PetscObjectGetName((PetscObject) next->label, name);
7768:       return(0);
7769:     }
7770:     ++l;
7771:     next = next->next;
7772:   }
7773:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7774: }

7776: /*@C
7777:   DMHasLabel - Determine whether the mesh has a label of a given name

7779:   Not Collective

7781:   Input Parameters:
7782: + dm   - The DM object
7783: - name - The label name

7785:   Output Parameter:
7786: . hasLabel - PETSC_TRUE if the label is present

7788:   Level: intermediate

7790: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7791: @*/
7792: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7793: {
7794:   DMLabelLink    next = dm->labels;
7795:   const char    *lname;

7802:   *hasLabel = PETSC_FALSE;
7803:   while (next) {
7804:     PetscObjectGetName((PetscObject) next->label, &lname);
7805:     PetscStrcmp(name, lname, hasLabel);
7806:     if (*hasLabel) break;
7807:     next = next->next;
7808:   }
7809:   return(0);
7810: }

7812: /*@C
7813:   DMGetLabel - Return the label of a given name, or NULL

7815:   Not Collective

7817:   Input Parameters:
7818: + dm   - The DM object
7819: - name - The label name

7821:   Output Parameter:
7822: . label - The DMLabel, or NULL if the label is absent

7824:   Note: Some of the default labels in a DMPlex will be
7825: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7826: $ "celltype"    - Holds the topological type of each cell
7827: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7828: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7829: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7830: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7832:   Level: intermediate

7834: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7835: @*/
7836: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7837: {
7838:   DMLabelLink    next = dm->labels;
7839:   PetscBool      hasLabel;
7840:   const char    *lname;

7847:   *label = NULL;
7848:   while (next) {
7849:     PetscObjectGetName((PetscObject) next->label, &lname);
7850:     PetscStrcmp(name, lname, &hasLabel);
7851:     if (hasLabel) {
7852:       *label = next->label;
7853:       break;
7854:     }
7855:     next = next->next;
7856:   }
7857:   return(0);
7858: }

7860: /*@C
7861:   DMGetLabelByNum - Return the nth label

7863:   Not Collective

7865:   Input Parameters:
7866: + dm - The DM object
7867: - n  - the label number

7869:   Output Parameter:
7870: . label - the label

7872:   Level: intermediate

7874: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7875: @*/
7876: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7877: {
7878:   DMLabelLink next = dm->labels;
7879:   PetscInt    l    = 0;

7884:   while (next) {
7885:     if (l == n) {
7886:       *label = next->label;
7887:       return(0);
7888:     }
7889:     ++l;
7890:     next = next->next;
7891:   }
7892:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7893: }

7895: /*@C
7896:   DMAddLabel - Add the label to this mesh

7898:   Not Collective

7900:   Input Parameters:
7901: + dm   - The DM object
7902: - label - The DMLabel

7904:   Level: developer

7906: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7907: @*/
7908: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7909: {
7910:   DMLabelLink    l, *p, tmpLabel;
7911:   PetscBool      hasLabel;
7912:   const char    *lname;
7913:   PetscBool      flg;

7918:   PetscObjectGetName((PetscObject) label, &lname);
7919:   DMHasLabel(dm, lname, &hasLabel);
7920:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7921:   PetscCalloc1(1, &tmpLabel);
7922:   tmpLabel->label  = label;
7923:   tmpLabel->output = PETSC_TRUE;
7924:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7925:   *p = tmpLabel;
7926:   PetscObjectReference((PetscObject)label);
7927:   PetscStrcmp(lname, "depth", &flg);
7928:   if (flg) dm->depthLabel = label;
7929:   PetscStrcmp(lname, "celltype", &flg);
7930:   if (flg) dm->celltypeLabel = label;
7931:   return(0);
7932: }

7934: /*@C
7935:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

7937:   Not Collective

7939:   Input Parameters:
7940: + dm    - The DM object
7941: - label - The DMLabel, having the same name, to substitute

7943:   Note: Some of the default labels in a DMPlex will be
7944: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7945: $ "celltype"    - Holds the topological type of each cell
7946: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7947: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7948: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7949: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7951:   Level: intermediate

7953: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7954: @*/
7955: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7956: {
7957:   DMLabelLink    next = dm->labels;
7958:   PetscBool      hasLabel, flg;
7959:   const char    *name, *lname;

7965:   PetscObjectGetName((PetscObject) label, &name);
7966:   while (next) {
7967:     PetscObjectGetName((PetscObject) next->label, &lname);
7968:     PetscStrcmp(name, lname, &hasLabel);
7969:     if (hasLabel) {
7970:       PetscObjectReference((PetscObject) label);
7971:       PetscStrcmp(lname, "depth", &flg);
7972:       if (flg) dm->depthLabel = label;
7973:       PetscStrcmp(lname, "celltype", &flg);
7974:       if (flg) dm->celltypeLabel = label;
7975:       DMLabelDestroy(&next->label);
7976:       next->label = label;
7977:       break;
7978:     }
7979:     next = next->next;
7980:   }
7981:   return(0);
7982: }

7984: /*@C
7985:   DMRemoveLabel - Remove the label given by name from this mesh

7987:   Not Collective

7989:   Input Parameters:
7990: + dm   - The DM object
7991: - name - The label name

7993:   Output Parameter:
7994: . label - The DMLabel, or NULL if the label is absent

7996:   Level: developer

7998:   Notes:
7999:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
8000:   DMLabelDestroy() on the label.

8002:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
8003:   call DMLabelDestroy(). Instead, the label is returned and the user is
8004:   responsible of calling DMLabelDestroy() at some point.

8006: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
8007: @*/
8008: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8009: {
8010:   DMLabelLink    link, *pnext;
8011:   PetscBool      hasLabel;
8012:   const char    *lname;

8018:   if (label) {
8020:     *label = NULL;
8021:   }
8022:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8023:     PetscObjectGetName((PetscObject) link->label, &lname);
8024:     PetscStrcmp(name, lname, &hasLabel);
8025:     if (hasLabel) {
8026:       *pnext = link->next; /* Remove from list */
8027:       PetscStrcmp(name, "depth", &hasLabel);
8028:       if (hasLabel) dm->depthLabel = NULL;
8029:       PetscStrcmp(name, "celltype", &hasLabel);
8030:       if (hasLabel) dm->celltypeLabel = NULL;
8031:       if (label) *label = link->label;
8032:       else       {DMLabelDestroy(&link->label);}
8033:       PetscFree(link);
8034:       break;
8035:     }
8036:   }
8037:   return(0);
8038: }

8040: /*@
8041:   DMRemoveLabelBySelf - Remove the label from this mesh

8043:   Not Collective

8045:   Input Parameters:
8046: + dm   - The DM object
8047: . label - The DMLabel to be removed from the DM
8048: - failNotFound - Should it fail if the label is not found in the DM?

8050:   Level: developer

8052:   Notes:
8053:   Only exactly the same instance is removed if found, name match is ignored.
8054:   If the DM has an exclusive reference to the label, it gets destroyed and
8055:   *label nullified.

8057: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
8058: @*/
8059: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8060: {
8061:   DMLabelLink    link, *pnext;
8062:   PetscBool      hasLabel = PETSC_FALSE;

8068:   if (!*label && !failNotFound) return(0);
8071:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8072:     if (*label == link->label) {
8073:       hasLabel = PETSC_TRUE;
8074:       *pnext = link->next; /* Remove from list */
8075:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
8076:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8077:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8078:       DMLabelDestroy(&link->label);
8079:       PetscFree(link);
8080:       break;
8081:     }
8082:   }
8083:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8084:   return(0);
8085: }

8087: /*@C
8088:   DMGetLabelOutput - Get the output flag for a given label

8090:   Not Collective

8092:   Input Parameters:
8093: + dm   - The DM object
8094: - name - The label name

8096:   Output Parameter:
8097: . output - The flag for output

8099:   Level: developer

8101: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8102: @*/
8103: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8104: {
8105:   DMLabelLink    next = dm->labels;
8106:   const char    *lname;

8113:   while (next) {
8114:     PetscBool flg;

8116:     PetscObjectGetName((PetscObject) next->label, &lname);
8117:     PetscStrcmp(name, lname, &flg);
8118:     if (flg) {*output = next->output; return(0);}
8119:     next = next->next;
8120:   }
8121:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8122: }

8124: /*@C
8125:   DMSetLabelOutput - Set the output flag for a given label

8127:   Not Collective

8129:   Input Parameters:
8130: + dm     - The DM object
8131: . name   - The label name
8132: - output - The flag for output

8134:   Level: developer

8136: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
8137: @*/
8138: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8139: {
8140:   DMLabelLink    next = dm->labels;
8141:   const char    *lname;

8147:   while (next) {
8148:     PetscBool flg;

8150:     PetscObjectGetName((PetscObject) next->label, &lname);
8151:     PetscStrcmp(name, lname, &flg);
8152:     if (flg) {next->output = output; return(0);}
8153:     next = next->next;
8154:   }
8155:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8156: }

8158: /*@
8159:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

8161:   Collective on dmA

8163:   Input Parameters:
8164: + dmA - The DM object with initial labels
8165: . dmB - The DM object with copied labels
8166: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8167: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

8169:   Level: intermediate

8171:   Note: This is typically used when interpolating or otherwise adding to a mesh

8173: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8174: @*/
8175: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8176: {
8177:   DMLabel        label, labelNew;
8178:   const char    *name;
8179:   PetscBool      flg;
8180:   DMLabelLink    link;

8188:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8189:   if (dmA == dmB) return(0);
8190:   for (link=dmA->labels; link; link=link->next) {
8191:     label=link->label;
8192:     PetscObjectGetName((PetscObject)label, &name);
8193:     if (!all) {
8194:       PetscStrcmp(name, "depth", &flg);
8195:       if (flg) continue;
8196:       PetscStrcmp(name, "dim", &flg);
8197:       if (flg) continue;
8198:       PetscStrcmp(name, "celltype", &flg);
8199:       if (flg) continue;
8200:     }
8201:     if (mode==PETSC_COPY_VALUES) {
8202:       DMLabelDuplicate(label, &labelNew);
8203:     } else {
8204:       labelNew = label;
8205:     }
8206:     DMAddLabel(dmB, labelNew);
8207:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8208:   }
8209:   return(0);
8210: }

8212: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8213: {
8217:   if (!*label) {
8218:     DMCreateLabel(dm, name);
8219:     DMGetLabel(dm, name, label);
8220:   }
8221:   DMLabelSetValue(*label, point, value);
8222:   return(0);
8223: }

8225: /*
8226:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8227:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8228:   (label, id) pair in the DM.

8230:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8231:   each label.
8232: */
8233: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8234: {
8235:   DMUniversalLabel ul;
8236:   PetscBool       *active;
8237:   PetscInt         pStart, pEnd, p, Nl, l, m;
8238:   PetscErrorCode   ierr;

8241:   PetscMalloc1(1, &ul);
8242:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8243:   DMGetNumLabels(dm, &Nl);
8244:   PetscCalloc1(Nl, &active);
8245:   ul->Nl = 0;
8246:   for (l = 0; l < Nl; ++l) {
8247:     PetscBool   isdepth, iscelltype;
8248:     const char *name;

8250:     DMGetLabelName(dm, l, &name);
8251:     PetscStrncmp(name, "depth", 6, &isdepth);
8252:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8253:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8254:     if (active[l]) ++ul->Nl;
8255:   }
8256:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8257:   ul->Nv = 0;
8258:   for (l = 0, m = 0; l < Nl; ++l) {
8259:     DMLabel     label;
8260:     PetscInt    nv;
8261:     const char *name;

8263:     if (!active[l]) continue;
8264:     DMGetLabelName(dm, l, &name);
8265:     DMGetLabelByNum(dm, l, &label);
8266:     DMLabelGetNumValues(label, &nv);
8267:     PetscStrallocpy(name, &ul->names[m]);
8268:     ul->indices[m]   = l;
8269:     ul->Nv          += nv;
8270:     ul->offsets[m+1] = nv;
8271:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8272:     ++m;
8273:   }
8274:   for (l = 1; l <= ul->Nl; ++l) {
8275:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8276:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8277:   }
8278:   for (l = 0; l < ul->Nl; ++l) {
8279:     PetscInt b;

8281:     ul->masks[l] = 0;
8282:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8283:   }
8284:   PetscMalloc1(ul->Nv, &ul->values);
8285:   for (l = 0, m = 0; l < Nl; ++l) {
8286:     DMLabel         label;
8287:     IS              valueIS;
8288:     const PetscInt *varr;
8289:     PetscInt        nv, v;

8291:     if (!active[l]) continue;
8292:     DMGetLabelByNum(dm, l, &label);
8293:     DMLabelGetNumValues(label, &nv);
8294:     DMLabelGetValueIS(label, &valueIS);
8295:     ISGetIndices(valueIS, &varr);
8296:     for (v = 0; v < nv; ++v) {
8297:       ul->values[ul->offsets[m]+v] = varr[v];
8298:     }
8299:     ISRestoreIndices(valueIS, &varr);
8300:     ISDestroy(&valueIS);
8301:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8302:     ++m;
8303:   }
8304:   DMPlexGetChart(dm, &pStart, &pEnd);
8305:   for (p = pStart; p < pEnd; ++p) {
8306:     PetscInt  uval = 0;
8307:     PetscBool marked = PETSC_FALSE;

8309:     for (l = 0, m = 0; l < Nl; ++l) {
8310:       DMLabel  label;
8311:       PetscInt val, defval, loc, nv;

8313:       if (!active[l]) continue;
8314:       DMGetLabelByNum(dm, l, &label);
8315:       DMLabelGetValue(label, p, &val);
8316:       DMLabelGetDefaultValue(label, &defval);
8317:       if (val == defval) {++m; continue;}
8318:       nv = ul->offsets[m+1]-ul->offsets[m];
8319:       marked = PETSC_TRUE;
8320:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8321:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8322:       uval += (loc+1) << ul->bits[m];
8323:       ++m;
8324:     }
8325:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8326:   }
8327:   PetscFree(active);
8328:   *universal = ul;
8329:   return(0);
8330: }

8332: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8333: {
8334:   PetscInt       l;

8338:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8339:   DMLabelDestroy(&(*universal)->label);
8340:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8341:   PetscFree((*universal)->values);
8342:   PetscFree(*universal);
8343:   *universal = NULL;
8344:   return(0);
8345: }

8347: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8348: {
8351:   *ulabel = ul->label;
8352:   return(0);
8353: }

8355: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8356: {
8357:   PetscInt       Nl = ul->Nl, l;

8362:   for (l = 0; l < Nl; ++l) {
8363:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8364:     else               {DMCreateLabel(dm, ul->names[l]);}
8365:   }
8366:   if (preserveOrder) {
8367:     for (l = 0; l < ul->Nl; ++l) {
8368:       const char *name;
8369:       PetscBool   match;

8371:       DMGetLabelName(dm, ul->indices[l], &name);
8372:       PetscStrcmp(name, ul->names[l], &match);
8373:       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]);
8374:     }
8375:   }
8376:   return(0);
8377: }

8379: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8380: {
8381:   PetscInt       l;

8385:   for (l = 0; l < ul->Nl; ++l) {
8386:     DMLabel  label;
8387:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

8389:     if (lval) {
8390:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8391:       else          {DMGetLabel(dm, ul->names[l], &label);}
8392:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8393:     }
8394:   }
8395:   return(0);
8396: }

8398: /*@
8399:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

8401:   Input Parameter:
8402: . dm - The DM object

8404:   Output Parameter:
8405: . cdm - The coarse DM

8407:   Level: intermediate

8409: .seealso: DMSetCoarseDM()
8410: @*/
8411: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8412: {
8416:   *cdm = dm->coarseMesh;
8417:   return(0);
8418: }

8420: /*@
8421:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

8423:   Input Parameters:
8424: + dm - The DM object
8425: - cdm - The coarse DM

8427:   Level: intermediate

8429: .seealso: DMGetCoarseDM()
8430: @*/
8431: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8432: {

8438:   PetscObjectReference((PetscObject)cdm);
8439:   DMDestroy(&dm->coarseMesh);
8440:   dm->coarseMesh = cdm;
8441:   return(0);
8442: }

8444: /*@
8445:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

8447:   Input Parameter:
8448: . dm - The DM object

8450:   Output Parameter:
8451: . fdm - The fine DM

8453:   Level: intermediate

8455: .seealso: DMSetFineDM()
8456: @*/
8457: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8458: {
8462:   *fdm = dm->fineMesh;
8463:   return(0);
8464: }

8466: /*@
8467:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

8469:   Input Parameters:
8470: + dm - The DM object
8471: - fdm - The fine DM

8473:   Level: intermediate

8475: .seealso: DMGetFineDM()
8476: @*/
8477: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8478: {

8484:   PetscObjectReference((PetscObject)fdm);
8485:   DMDestroy(&dm->fineMesh);
8486:   dm->fineMesh = fdm;
8487:   return(0);
8488: }

8490: /*=== DMBoundary code ===*/

8492: /*@C
8493:   DMAddBoundary - Add a boundary condition to the model

8495:   Collective on dm

8497:   Input Parameters:
8498: + dm       - The DM, with a PetscDS that matches the problem being constrained
8499: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8500: . name     - The BC name
8501: . label    - The label defining constrained points
8502: . Nv       - The number of DMLabel values for constrained points
8503: . values   - An array of values for constrained points
8504: . field    - The field to constrain
8505: . Nc       - The number of constrained field components (0 will constrain all fields)
8506: . comps    - An array of constrained component numbers
8507: . bcFunc   - A pointwise function giving boundary values
8508: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8509: - ctx      - An optional user context for bcFunc

8511:   Output Parameter:
8512: . bd          - (Optional) Boundary number

8514:   Options Database Keys:
8515: + -bc_<boundary name> <num> - Overrides the boundary ids
8516: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8518:   Note:
8519:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8521: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8523:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8525: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8526: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8527: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8528: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8530: + dim - the spatial dimension
8531: . Nf - the number of fields
8532: . uOff - the offset into u[] and u_t[] for each field
8533: . uOff_x - the offset into u_x[] for each field
8534: . u - each field evaluated at the current point
8535: . u_t - the time derivative of each field evaluated at the current point
8536: . u_x - the gradient of each field evaluated at the current point
8537: . aOff - the offset into a[] and a_t[] for each auxiliary field
8538: . aOff_x - the offset into a_x[] for each auxiliary field
8539: . a - each auxiliary field evaluated at the current point
8540: . a_t - the time derivative of each auxiliary field evaluated at the current point
8541: . a_x - the gradient of auxiliary each field evaluated at the current point
8542: . t - current time
8543: . x - coordinates of the current point
8544: . numConstants - number of constant parameters
8545: . constants - constant parameters
8546: - bcval - output values at the current point

8548:   Level: developer

8550: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8551: @*/
8552: 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)
8553: {
8554:   PetscDS        ds;

8564:   DMGetDS(dm, &ds);
8565:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8566:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8567:   return(0);
8568: }

8570: /* TODO Remove this since now the structures are the same */
8571: static PetscErrorCode DMPopulateBoundary(DM dm)
8572: {
8573:   PetscDS        ds;
8574:   DMBoundary    *lastnext;
8575:   DSBoundary     dsbound;

8579:   DMGetDS(dm, &ds);
8580:   dsbound = ds->boundary;
8581:   if (dm->boundary) {
8582:     DMBoundary next = dm->boundary;

8584:     /* quick check to see if the PetscDS has changed */
8585:     if (next->dsboundary == dsbound) return(0);
8586:     /* the PetscDS has changed: tear down and rebuild */
8587:     while (next) {
8588:       DMBoundary b = next;

8590:       next = b->next;
8591:       PetscFree(b);
8592:     }
8593:     dm->boundary = NULL;
8594:   }

8596:   lastnext = &(dm->boundary);
8597:   while (dsbound) {
8598:     DMBoundary dmbound;

8600:     PetscNew(&dmbound);
8601:     dmbound->dsboundary = dsbound;
8602:     dmbound->label      = dsbound->label;
8603:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8604:     *lastnext = dmbound;
8605:     lastnext = &(dmbound->next);
8606:     dsbound = dsbound->next;
8607:   }
8608:   return(0);
8609: }

8611: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8612: {
8613:   DMBoundary     b;

8619:   *isBd = PETSC_FALSE;
8620:   DMPopulateBoundary(dm);
8621:   b = dm->boundary;
8622:   while (b && !(*isBd)) {
8623:     DMLabel    label = b->label;
8624:     DSBoundary dsb   = b->dsboundary;
8625:     PetscInt   i;

8627:     if (label) {
8628:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
8629:     }
8630:     b = b->next;
8631:   }
8632:   return(0);
8633: }

8635: /*@C
8636:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8638:   Collective on DM

8640:   Input Parameters:
8641: + dm      - The DM
8642: . time    - The time
8643: . funcs   - The coordinate functions to evaluate, one per field
8644: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8645: - mode    - The insertion mode for values

8647:   Output Parameter:
8648: . X - vector

8650:    Calling sequence of func:
8651: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8653: +  dim - The spatial dimension
8654: .  time - The time at which to sample
8655: .  x   - The coordinates
8656: .  Nc  - The number of components
8657: .  u   - The output field values
8658: -  ctx - optional user-defined function context

8660:   Level: developer

8662: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8663: @*/
8664: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8665: {
8666:   Vec            localX;

8671:   DMGetLocalVector(dm, &localX);
8672:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8673:   DMLocalToGlobalBegin(dm, localX, mode, X);
8674:   DMLocalToGlobalEnd(dm, localX, mode, X);
8675:   DMRestoreLocalVector(dm, &localX);
8676:   return(0);
8677: }

8679: /*@C
8680:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8682:   Not collective

8684:   Input Parameters:
8685: + dm      - The DM
8686: . time    - The time
8687: . funcs   - The coordinate functions to evaluate, one per field
8688: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8689: - mode    - The insertion mode for values

8691:   Output Parameter:
8692: . localX - vector

8694:    Calling sequence of func:
8695: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8697: +  dim - The spatial dimension
8698: .  x   - The coordinates
8699: .  Nc  - The number of components
8700: .  u   - The output field values
8701: -  ctx - optional user-defined function context

8703:   Level: developer

8705: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8706: @*/
8707: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8708: {

8714:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8715:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8716:   return(0);
8717: }

8719: /*@C
8720:   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.

8722:   Collective on DM

8724:   Input Parameters:
8725: + dm      - The DM
8726: . time    - The time
8727: . label   - The DMLabel selecting the portion of the mesh for projection
8728: . funcs   - The coordinate functions to evaluate, one per field
8729: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8730: - mode    - The insertion mode for values

8732:   Output Parameter:
8733: . X - vector

8735:    Calling sequence of func:
8736: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8738: +  dim - The spatial dimension
8739: .  x   - The coordinates
8740: .  Nc  - The number of components
8741: .  u   - The output field values
8742: -  ctx - optional user-defined function context

8744:   Level: developer

8746: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8747: @*/
8748: 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)
8749: {
8750:   Vec            localX;

8755:   DMGetLocalVector(dm, &localX);
8756:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8757:   DMLocalToGlobalBegin(dm, localX, mode, X);
8758:   DMLocalToGlobalEnd(dm, localX, mode, X);
8759:   DMRestoreLocalVector(dm, &localX);
8760:   return(0);
8761: }

8763: /*@C
8764:   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.

8766:   Not collective

8768:   Input Parameters:
8769: + dm      - The DM
8770: . time    - The time
8771: . label   - The DMLabel selecting the portion of the mesh for projection
8772: . funcs   - The coordinate functions to evaluate, one per field
8773: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8774: - mode    - The insertion mode for values

8776:   Output Parameter:
8777: . localX - vector

8779:    Calling sequence of func:
8780: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8782: +  dim - The spatial dimension
8783: .  x   - The coordinates
8784: .  Nc  - The number of components
8785: .  u   - The output field values
8786: -  ctx - optional user-defined function context

8788:   Level: developer

8790: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8791: @*/
8792: 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)
8793: {

8799:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8800:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8801:   return(0);
8802: }

8804: /*@C
8805:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8807:   Not collective

8809:   Input Parameters:
8810: + dm      - The DM
8811: . time    - The time
8812: . localU  - The input field vector
8813: . funcs   - The functions to evaluate, one per field
8814: - mode    - The insertion mode for values

8816:   Output Parameter:
8817: . localX  - The output vector

8819:    Calling sequence of func:
8820: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8821: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8822: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8823: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8825: +  dim          - The spatial dimension
8826: .  Nf           - The number of input fields
8827: .  NfAux        - The number of input auxiliary fields
8828: .  uOff         - The offset of each field in u[]
8829: .  uOff_x       - The offset of each field in u_x[]
8830: .  u            - The field values at this point in space
8831: .  u_t          - The field time derivative at this point in space (or NULL)
8832: .  u_x          - The field derivatives at this point in space
8833: .  aOff         - The offset of each auxiliary field in u[]
8834: .  aOff_x       - The offset of each auxiliary field in u_x[]
8835: .  a            - The auxiliary field values at this point in space
8836: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8837: .  a_x          - The auxiliary field derivatives at this point in space
8838: .  t            - The current time
8839: .  x            - The coordinates of this point
8840: .  numConstants - The number of constants
8841: .  constants    - The value of each constant
8842: -  f            - The value of the function at this point in space

8844:   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.
8845:   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
8846:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8847:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8849:   Level: intermediate

8851: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8852: @*/
8853: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8854:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8855:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8856:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8857:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8858:                                    InsertMode mode, Vec localX)
8859: {

8866:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8867:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8868:   return(0);
8869: }

8871: /*@C
8872:   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.

8874:   Not collective

8876:   Input Parameters:
8877: + dm      - The DM
8878: . time    - The time
8879: . label   - The DMLabel marking the portion of the domain to output
8880: . numIds  - The number of label ids to use
8881: . ids     - The label ids to use for marking
8882: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8883: . comps   - The components to set in the output, or NULL for all components
8884: . localU  - The input field vector
8885: . funcs   - The functions to evaluate, one per field
8886: - mode    - The insertion mode for values

8888:   Output Parameter:
8889: . localX  - The output vector

8891:    Calling sequence of func:
8892: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8893: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8894: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8895: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8897: +  dim          - The spatial dimension
8898: .  Nf           - The number of input fields
8899: .  NfAux        - The number of input auxiliary fields
8900: .  uOff         - The offset of each field in u[]
8901: .  uOff_x       - The offset of each field in u_x[]
8902: .  u            - The field values at this point in space
8903: .  u_t          - The field time derivative at this point in space (or NULL)
8904: .  u_x          - The field derivatives at this point in space
8905: .  aOff         - The offset of each auxiliary field in u[]
8906: .  aOff_x       - The offset of each auxiliary field in u_x[]
8907: .  a            - The auxiliary field values at this point in space
8908: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8909: .  a_x          - The auxiliary field derivatives at this point in space
8910: .  t            - The current time
8911: .  x            - The coordinates of this point
8912: .  numConstants - The number of constants
8913: .  constants    - The value of each constant
8914: -  f            - The value of the function at this point in space

8916:   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.
8917:   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
8918:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8919:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8921:   Level: intermediate

8923: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8924: @*/
8925: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8926:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8927:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8928:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8929:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8930:                                         InsertMode mode, Vec localX)
8931: {

8938:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8939:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8940:   return(0);
8941: }

8943: /*@C
8944:   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.

8946:   Not collective

8948:   Input Parameters:
8949: + dm      - The DM
8950: . time    - The time
8951: . label   - The DMLabel marking the portion of the domain boundary to output
8952: . numIds  - The number of label ids to use
8953: . ids     - The label ids to use for marking
8954: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8955: . comps   - The components to set in the output, or NULL for all components
8956: . localU  - The input field vector
8957: . funcs   - The functions to evaluate, one per field
8958: - mode    - The insertion mode for values

8960:   Output Parameter:
8961: . localX  - The output vector

8963:    Calling sequence of func:
8964: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8965: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8966: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8967: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8969: +  dim          - The spatial dimension
8970: .  Nf           - The number of input fields
8971: .  NfAux        - The number of input auxiliary fields
8972: .  uOff         - The offset of each field in u[]
8973: .  uOff_x       - The offset of each field in u_x[]
8974: .  u            - The field values at this point in space
8975: .  u_t          - The field time derivative at this point in space (or NULL)
8976: .  u_x          - The field derivatives at this point in space
8977: .  aOff         - The offset of each auxiliary field in u[]
8978: .  aOff_x       - The offset of each auxiliary field in u_x[]
8979: .  a            - The auxiliary field values at this point in space
8980: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8981: .  a_x          - The auxiliary field derivatives at this point in space
8982: .  t            - The current time
8983: .  x            - The coordinates of this point
8984: .  n            - The face normal
8985: .  numConstants - The number of constants
8986: .  constants    - The value of each constant
8987: -  f            - The value of the function at this point in space

8989:   Note:
8990:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8991:   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
8992:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8993:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8995:   Level: intermediate

8997: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8998: @*/
8999: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9000:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
9001:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9002:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9003:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9004:                                           InsertMode mode, Vec localX)
9005: {

9012:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9013:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
9014:   return(0);
9015: }

9017: /*@C
9018:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

9020:   Input Parameters:
9021: + dm    - The DM
9022: . time  - The time
9023: . funcs - The functions to evaluate for each field component
9024: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9025: - X     - The coefficient vector u_h, a global vector

9027:   Output Parameter:
9028: . diff - The diff ||u - u_h||_2

9030:   Level: developer

9032: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9033: @*/
9034: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
9035: {

9041:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9042:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
9043:   return(0);
9044: }

9046: /*@C
9047:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

9049:   Collective on dm

9051:   Input Parameters:
9052: + dm    - The DM
9053: , time  - The time
9054: . funcs - The gradient functions to evaluate for each field component
9055: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9056: . X     - The coefficient vector u_h, a global vector
9057: - n     - The vector to project along

9059:   Output Parameter:
9060: . diff - The diff ||(grad u - grad u_h) . n||_2

9062:   Level: developer

9064: .seealso: DMProjectFunction(), DMComputeL2Diff()
9065: @*/
9066: 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)
9067: {

9073:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9074:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
9075:   return(0);
9076: }

9078: /*@C
9079:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

9081:   Collective on dm

9083:   Input Parameters:
9084: + dm    - The DM
9085: . time  - The time
9086: . funcs - The functions to evaluate for each field component
9087: . ctxs  - Optional array of contexts to pass to each function, or NULL.
9088: - X     - The coefficient vector u_h, a global vector

9090:   Output Parameter:
9091: . diff - The array of differences, ||u^f - u^f_h||_2

9093:   Level: developer

9095: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9096: @*/
9097: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9098: {

9104:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9105:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9106:   return(0);
9107: }

9109: /*@C
9110:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
9111:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

9113:   Collective on dm

9115:   Input parameters:
9116: + dm - the pre-adaptation DM object
9117: - label - label with the flags

9119:   Output parameters:
9120: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

9122:   Level: intermediate

9124: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9125: @*/
9126: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9127: {

9134:   *dmAdapt = NULL;
9135:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9136:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
9137:   if (*dmAdapt) {
9138:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
9139:     PetscFree((*dmAdapt)->vectype);
9140:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9141:     PetscFree((*dmAdapt)->mattype);
9142:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9143:   }
9144:   return(0);
9145: }

9147: /*@C
9148:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

9150:   Input Parameters:
9151: + dm - The DM object
9152: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9153: - 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_".

9155:   Output Parameter:
9156: . dmAdapt  - Pointer to the DM object containing the adapted mesh

9158:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

9160:   Level: advanced

9162: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9163: @*/
9164: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9165: {

9173:   *dmAdapt = NULL;
9174:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9175:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9176:   return(0);
9177: }

9179: /*@C
9180:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

9182:  Not Collective

9184:  Input Parameter:
9185: .  dm    - The DM

9187:  Output Parameters:
9188: +  nranks - the number of neighbours
9189: -  ranks - the neighbors ranks

9191:  Notes:
9192:  Do not free the array, it is freed when the DM is destroyed.

9194:  Level: beginner

9196:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9197: @*/
9198: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9199: {

9204:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9205:   (dm->ops->getneighbors)(dm,nranks,ranks);
9206:   return(0);
9207: }

9209: #include <petsc/private/matimpl.h>

9211: /*
9212:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9213:     This has be a different function because it requires DM which is not defined in the Mat library
9214: */
9215: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9216: {

9220:   if (coloring->ctype == IS_COLORING_LOCAL) {
9221:     Vec x1local;
9222:     DM  dm;
9223:     MatGetDM(J,&dm);
9224:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9225:     DMGetLocalVector(dm,&x1local);
9226:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9227:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9228:     x1   = x1local;
9229:   }
9230:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9231:   if (coloring->ctype == IS_COLORING_LOCAL) {
9232:     DM  dm;
9233:     MatGetDM(J,&dm);
9234:     DMRestoreLocalVector(dm,&x1);
9235:   }
9236:   return(0);
9237: }

9239: /*@
9240:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

9242:     Input Parameter:
9243: .    coloring - the MatFDColoring object

9245:     Developer Notes:
9246:     this routine exists because the PETSc Mat library does not know about the DM objects

9248:     Level: advanced

9250: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9251: @*/
9252: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9253: {
9255:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9256:   return(0);
9257: }

9259: /*@
9260:     DMGetCompatibility - determine if two DMs are compatible

9262:     Collective

9264:     Input Parameters:
9265: +    dm1 - the first DM
9266: -    dm2 - the second DM

9268:     Output Parameters:
9269: +    compatible - whether or not the two DMs are compatible
9270: -    set - whether or not the compatible value was set

9272:     Notes:
9273:     Two DMs are deemed compatible if they represent the same parallel decomposition
9274:     of the same topology. This implies that the section (field data) on one
9275:     "makes sense" with respect to the topology and parallel decomposition of the other.
9276:     Loosely speaking, compatible DMs represent the same domain and parallel
9277:     decomposition, but hold different data.

9279:     Typically, one would confirm compatibility if intending to simultaneously iterate
9280:     over a pair of vectors obtained from different DMs.

9282:     For example, two DMDA objects are compatible if they have the same local
9283:     and global sizes and the same stencil width. They can have different numbers
9284:     of degrees of freedom per node. Thus, one could use the node numbering from
9285:     either DM in bounds for a loop over vectors derived from either DM.

9287:     Consider the operation of summing data living on a 2-dof DMDA to data living
9288:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9289: .vb
9290:   ...
9291:   DMGetCompatibility(da1,da2,&compatible,&set);
9292:   if (set && compatible)  {
9293:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9294:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9295:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9296:     for (j=y; j<y+n; ++j) {
9297:       for (i=x; i<x+m, ++i) {
9298:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9299:       }
9300:     }
9301:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9302:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9303:   } else {
9304:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9305:   }
9306:   ...
9307: .ve

9309:     Checking compatibility might be expensive for a given implementation of DM,
9310:     or might be impossible to unambiguously confirm or deny. For this reason,
9311:     this function may decline to determine compatibility, and hence users should
9312:     always check the "set" output parameter.

9314:     A DM is always compatible with itself.

9316:     In the current implementation, DMs which live on "unequal" communicators
9317:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9318:     incompatible.

9320:     This function is labeled "Collective," as information about all subdomains
9321:     is required on each rank. However, in DM implementations which store all this
9322:     information locally, this function may be merely "Logically Collective".

9324:     Developer Notes:
9325:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9326:     iff B is compatible with A. Thus, this function checks the implementations
9327:     of both dm and dmc (if they are of different types), attempting to determine
9328:     compatibility. It is left to DM implementers to ensure that symmetry is
9329:     preserved. The simplest way to do this is, when implementing type-specific
9330:     logic for this function, is to check for existing logic in the implementation
9331:     of other DM types and let *set = PETSC_FALSE if found.

9333:     Level: advanced

9335: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9336: @*/

9338: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9339: {
9341:   PetscMPIInt    compareResult;
9342:   DMType         type,type2;
9343:   PetscBool      sameType;


9349:   /* Declare a DM compatible with itself */
9350:   if (dm1 == dm2) {
9351:     *set = PETSC_TRUE;
9352:     *compatible = PETSC_TRUE;
9353:     return(0);
9354:   }

9356:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9357:      communicator. Note that this does not preclude compatibility with
9358:      DMs living on "congruent" or "similar" communicators, but this must be
9359:      determined by the implementation-specific logic */
9360:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9361:   if (compareResult == MPI_UNEQUAL) {
9362:     *set = PETSC_TRUE;
9363:     *compatible = PETSC_FALSE;
9364:     return(0);
9365:   }

9367:   /* Pass to the implementation-specific routine, if one exists. */
9368:   if (dm1->ops->getcompatibility) {
9369:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9370:     if (*set) return(0);
9371:   }

9373:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9374:      with an implementation of this function from dm2 */
9375:   DMGetType(dm1,&type);
9376:   DMGetType(dm2,&type2);
9377:   PetscStrcmp(type,type2,&sameType);
9378:   if (!sameType && dm2->ops->getcompatibility) {
9379:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9380:   } else {
9381:     *set = PETSC_FALSE;
9382:   }
9383:   return(0);
9384: }

9386: /*@C
9387:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

9389:   Logically Collective on DM

9391:   Input Parameters:
9392: + DM - the DM
9393: . f - the monitor function
9394: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9395: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

9397:   Options Database Keys:
9398: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9399:                             does not cancel those set via the options database.

9401:   Notes:
9402:   Several different monitoring routines may be set by calling
9403:   DMMonitorSet() multiple times; all will be called in the
9404:   order in which they were set.

9406:   Fortran Notes:
9407:   Only a single monitor function can be set for each DM object

9409:   Level: intermediate

9411: .seealso: DMMonitorCancel()
9412: @*/
9413: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9414: {
9415:   PetscInt       m;

9420:   for (m = 0; m < dm->numbermonitors; ++m) {
9421:     PetscBool identical;

9423:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9424:     if (identical) return(0);
9425:   }
9426:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9427:   dm->monitor[dm->numbermonitors]          = f;
9428:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9429:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9430:   return(0);
9431: }

9433: /*@
9434:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9436:   Logically Collective on DM

9438:   Input Parameter:
9439: . dm - the DM

9441:   Options Database Key:
9442: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9443:   into a code by calls to DMonitorSet(), but does not cancel those
9444:   set via the options database

9446:   Notes:
9447:   There is no way to clear one specific monitor from a DM object.

9449:   Level: intermediate

9451: .seealso: DMMonitorSet()
9452: @*/
9453: PetscErrorCode DMMonitorCancel(DM dm)
9454: {
9456:   PetscInt       m;

9460:   for (m = 0; m < dm->numbermonitors; ++m) {
9461:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9462:   }
9463:   dm->numbermonitors = 0;
9464:   return(0);
9465: }

9467: /*@C
9468:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9470:   Collective on DM

9472:   Input Parameters:
9473: + dm   - DM object you wish to monitor
9474: . name - the monitor type one is seeking
9475: . help - message indicating what monitoring is done
9476: . manual - manual page for the monitor
9477: . monitor - the monitor function
9478: - 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

9480:   Output Parameter:
9481: . flg - Flag set if the monitor was created

9483:   Level: developer

9485: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9486:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9487:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9488:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9489:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9490:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9491:           PetscOptionsFList(), PetscOptionsEList()
9492: @*/
9493: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9494: {
9495:   PetscViewer       viewer;
9496:   PetscViewerFormat format;
9497:   PetscErrorCode    ierr;

9501:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9502:   if (*flg) {
9503:     PetscViewerAndFormat *vf;

9505:     PetscViewerAndFormatCreate(viewer, format, &vf);
9506:     PetscObjectDereference((PetscObject) viewer);
9507:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9508:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9509:   }
9510:   return(0);
9511: }

9513: /*@
9514:    DMMonitor - runs the user provided monitor routines, if they exist

9516:    Collective on DM

9518:    Input Parameters:
9519: .  dm - The DM

9521:    Level: developer

9523: .seealso: DMMonitorSet()
9524: @*/
9525: PetscErrorCode DMMonitor(DM dm)
9526: {
9527:   PetscInt       m;

9531:   if (!dm) return(0);
9533:   for (m = 0; m < dm->numbermonitors; ++m) {
9534:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9535:   }
9536:   return(0);
9537: }

9539: /*@
9540:   DMComputeError - Computes the error assuming the user has given exact solution functions

9542:   Collective on DM

9544:   Input Parameters:
9545: + dm     - The DM
9546: - sol    - The solution vector

9548:   Input/Output Parameter:
9549: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9550:            contains the error in each field

9552:   Output Parameter:
9553: . errorVec - A vector to hold the cellwise error (may be NULL)

9555:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

9557:   Level: developer

9559: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9560: @*/
9561: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9562: {
9563:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9564:   void            **ctxs;
9565:   PetscReal         time;
9566:   PetscInt          Nf, f, Nds, s;
9567:   PetscErrorCode    ierr;

9570:   DMGetNumFields(dm, &Nf);
9571:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9572:   DMGetNumDS(dm, &Nds);
9573: