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: #if defined(PETSC_HAVE_VALGRIND)
 11: #  include <valgrind/memcheck.h>
 12: #endif

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

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

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

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

 28:   Collective

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

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

 36:   Level: beginner

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

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

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

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

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

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

 98:   Collective

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

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

106:   Level: beginner

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

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

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

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

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

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

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

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

192:    Logically Collective on da

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

198:    Options Database:
199: .   -dm_vec_type ctype

201:    Level: intermediate

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

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

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

219:    Logically Collective on da

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

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

227:    Level: intermediate

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

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

242:   Not collective

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

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

250:   Level: intermediate

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

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

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

268:   Not collective

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

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

276:   Level: intermediate

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

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

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

294:    Logically Collective on dm

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

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

303:    Level: intermediate

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

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

319:    Logically Collective on dm

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

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

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

330:    Level: intermediate

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

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

346:    Logically Collective on dm

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

352:    Options Database:
353: .   -dm_mat_type ctype

355:    Level: intermediate

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

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

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

373:    Logically Collective on dm

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

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

381:    Options Database:
382: .   -dm_mat_type ctype

384:    Level: intermediate

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

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

399:   Not collective

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

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

407:   Level: intermediate

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

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

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

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

428:   Not collective

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

434:   Level: intermediate

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


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

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

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

457:    Logically Collective on dm

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

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

467:    Level: advanced

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

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

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

491:    Logically Collective on dm

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

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

501:    Level: advanced

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

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

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

519:    Not Collective

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

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

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

531:    Level: advanced

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

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

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

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

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

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

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

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

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

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

597:     Collective on dm

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

602:     Level: developer

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

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

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

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

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

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

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

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

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

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

725:   PetscSectionDestroy(&(*dm)->localSection);
726:   PetscSectionDestroy(&(*dm)->globalSection);
727:   PetscLayoutDestroy(&(*dm)->map);
728:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
729:   MatDestroy(&(*dm)->defaultConstraintMat);
730:   PetscSFDestroy(&(*dm)->sf);
731:   PetscSFDestroy(&(*dm)->sectionSF);
732:   if ((*dm)->useNatural) {
733:     if ((*dm)->sfNatural) {
734:       PetscSFDestroy(&(*dm)->sfNatural);
735:     }
736:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
737:   }
738:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
739:     DMSetFineDM((*dm)->coarseMesh,NULL);
740:   }

742:   DMDestroy(&(*dm)->coarseMesh);
743:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
744:     DMSetCoarseDM((*dm)->fineMesh,NULL);
745:   }
746:   DMDestroy(&(*dm)->fineMesh);
747:   DMFieldDestroy(&(*dm)->coordinateField);
748:   DMDestroy(&(*dm)->coordinateDM);
749:   VecDestroy(&(*dm)->coordinates);
750:   VecDestroy(&(*dm)->coordinatesLocal);
751:   PetscFree((*dm)->L);
752:   PetscFree((*dm)->maxCell);
753:   PetscFree((*dm)->bdtype);
754:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
755:   DMDestroy(&(*dm)->transformDM);
756:   VecDestroy(&(*dm)->transform);

758:   DMClearDS(*dm);
759:   DMDestroy(&(*dm)->dmBC);
760:   /* if memory was published with SAWs then destroy it */
761:   PetscObjectSAWsViewOff((PetscObject)*dm);

763:   if ((*dm)->ops->destroy) {
764:     (*(*dm)->ops->destroy)(*dm);
765:   }
766:   DMMonitorCancel(*dm);
767:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
768:   PetscHeaderDestroy(dm);
769:   return(0);
770: }

772: /*@
773:     DMSetUp - sets up the data structures inside a DM object

775:     Collective on dm

777:     Input Parameter:
778: .   dm - the DM object to setup

780:     Level: developer

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

784: @*/
785: PetscErrorCode  DMSetUp(DM dm)
786: {

791:   if (dm->setupcalled) return(0);
792:   if (dm->ops->setup) {
793:     (*dm->ops->setup)(dm);
794:   }
795:   dm->setupcalled = PETSC_TRUE;
796:   return(0);
797: }

799: /*@
800:     DMSetFromOptions - sets parameters in a DM from the options database

802:     Collective on dm

804:     Input Parameter:
805: .   dm - the DM object to set options for

807:     Options Database:
808: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
809: .   -dm_vec_type <type>  - type of vector to create inside DM
810: .   -dm_mat_type <type>  - type of matrix to create inside DM
811: -   -dm_is_coloring_type - <global or local>

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

822:     Level: intermediate

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

827: @*/
828: PetscErrorCode DMSetFromOptions(DM dm)
829: {
830:   char           typeName[256];
831:   PetscBool      flg;

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

859: /*@C
860:    DMViewFromOptions - View from Options

862:    Collective on DM

864:    Input Parameters:
865: +  dm - the DM object
866: .  obj - Optional object
867: -  name - command line option

869:    Level: intermediate
870: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
871: @*/
872: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
873: {

878:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
879:   return(0);
880: }

882: /*@C
883:     DMView - Views a DM

885:     Collective on dm

887:     Input Parameter:
888: +   dm - the DM object to view
889: -   v - the viewer

891:     Level: beginner

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

895: @*/
896: PetscErrorCode  DMView(DM dm,PetscViewer v)
897: {
898:   PetscErrorCode    ierr;
899:   PetscBool         isbinary;
900:   PetscMPIInt       size;
901:   PetscViewerFormat format;

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

919:   PetscViewerGetFormat(v,&format);
920:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
921:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
922:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
923:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
924:   if (isbinary) {
925:     PetscInt classid = DM_FILE_CLASSID;
926:     char     type[256];

928:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
929:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
930:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
931:   }
932:   if (dm->ops->view) {
933:     (*dm->ops->view)(dm,v);
934:   }
935:   return(0);
936: }

938: /*@
939:     DMCreateGlobalVector - Creates a global vector from a DM object

941:     Collective on dm

943:     Input Parameter:
944: .   dm - the DM object

946:     Output Parameter:
947: .   vec - the global vector

949:     Level: beginner

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

953: @*/
954: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
955: {

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

966:     VecGetDM(*vec,&vdm);
967:     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);
968:   }
969:   return(0);
970: }

972: /*@
973:     DMCreateLocalVector - Creates a local vector from a DM object

975:     Not Collective

977:     Input Parameter:
978: .   dm - the DM object

980:     Output Parameter:
981: .   vec - the local vector

983:     Level: beginner

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

987: @*/
988: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
989: {

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

1000:     VecGetDM(*vec,&vdm);
1001:     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);
1002:   }
1003:   return(0);
1004: }

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

1009:    Collective on dm

1011:    Input Parameter:
1012: .  dm - the DM that provides the mapping

1014:    Output Parameter:
1015: .  ltog - the mapping

1017:    Level: intermediate

1019:    Notes:
1020:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1021:    MatSetLocalToGlobalMapping().

1023: .seealso: DMCreateLocalVector()
1024: @*/
1025: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1026: {
1027:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1033:   if (!dm->ltogmap) {
1034:     PetscSection section, sectionGlobal;

1036:     DMGetLocalSection(dm, &section);
1037:     if (section) {
1038:       const PetscInt *cdofs;
1039:       PetscInt       *ltog;
1040:       PetscInt        pStart, pEnd, n, p, k, l;

1042:       DMGetGlobalSection(dm, &sectionGlobal);
1043:       PetscSectionGetChart(section, &pStart, &pEnd);
1044:       PetscSectionGetStorageSize(section, &n);
1045:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1046:       for (p = pStart, l = 0; p < pEnd; ++p) {
1047:         PetscInt bdof, cdof, dof, off, c, cind = 0;

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

1087: /*@
1088:    DMGetBlockSize - Gets the inherent block size associated with a DM

1090:    Not Collective

1092:    Input Parameter:
1093: .  dm - the DM with block structure

1095:    Output Parameter:
1096: .  bs - the block size, 1 implies no exploitable block structure

1098:    Level: intermediate

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

1112: /*@C
1113:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1115:     Collective on dmc

1117:     Input Parameter:
1118: +   dmc - the DM object
1119: -   dmf - the second, finer DM object

1121:     Output Parameter:
1122: +  mat - the interpolation
1123: -  vec - the scaling (optional)

1125:     Level: developer

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

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


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

1137: @*/
1138: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1139: {

1146:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1147:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1148:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1149:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1150:   return(0);
1151: }

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

1156:   Input Parameters:
1157: +      dac - DM that defines a coarse mesh
1158: .      daf - DM that defines a fine mesh
1159: -      mat - the restriction (or interpolation operator) from fine to coarse

1161:   Output Parameter:
1162: .    scale - the scaled vector

1164:   Level: developer

1166: .seealso: DMCreateInterpolation()

1168: @*/
1169: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1170: {
1172:   Vec            fine;
1173:   PetscScalar    one = 1.0;

1176:   DMCreateGlobalVector(daf,&fine);
1177:   DMCreateGlobalVector(dac,scale);
1178:   VecSet(fine,one);
1179:   MatRestrict(mat,fine,*scale);
1180:   VecDestroy(&fine);
1181:   VecReciprocal(*scale);
1182:   return(0);
1183: }

1185: /*@
1186:     DMCreateRestriction - Gets restriction matrix between two DM objects

1188:     Collective on dmc

1190:     Input Parameter:
1191: +   dmc - the DM object
1192: -   dmf - the second, finer DM object

1194:     Output Parameter:
1195: .  mat - the restriction


1198:     Level: developer

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


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

1207: @*/
1208: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1209: {

1216:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1217:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1218:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1219:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1220:   return(0);
1221: }

1223: /*@
1224:     DMCreateInjection - Gets injection matrix between two DM objects

1226:     Collective on dac

1228:     Input Parameter:
1229: +   dac - the DM object
1230: -   daf - the second, finer DM object

1232:     Output Parameter:
1233: .   mat - the injection

1235:     Level: developer

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

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

1243: @*/
1244: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1245: {

1252:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1253:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1254:   (*dac->ops->createinjection)(dac,daf,mat);
1255:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1256:   return(0);
1257: }

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

1262:   Collective on dac

1264:   Input Parameter:
1265: + dac - the DM object
1266: - daf - the second, finer DM object

1268:   Output Parameter:
1269: . mat - the interpolation

1271:   Level: developer

1273: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1274: @*/
1275: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1276: {

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

1288: /*@
1289:     DMCreateColoring - Gets coloring for a DM

1291:     Collective on dm

1293:     Input Parameter:
1294: +   dm - the DM object
1295: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1297:     Output Parameter:
1298: .   coloring - the coloring

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

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

1306:     Level: developer

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

1310: @*/
1311: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1312: {

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

1323: /*@
1324:     DMCreateMatrix - Gets empty Jacobian for a DM

1326:     Collective on dm

1328:     Input Parameter:
1329: .   dm - the DM object

1331:     Output Parameter:
1332: .   mat - the empty Jacobian

1334:     Level: beginner


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

1340:     Notes:
1341:     This properly preallocates the number of nonzeros in the sparse matrix so you
1342:        do not need to do it yourself.

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

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

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

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

1355: @*/
1356: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1357: {

1363:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1364:   MatInitializePackage();
1365:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1366:   (*dm->ops->creatematrix)(dm,mat);
1367:   if (PetscDefined(USE_DEBUG)) {
1368:     DM mdm;

1370:     MatGetDM(*mat,&mdm);
1371:     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);
1372:   }
1373:   /* Handle nullspace and near nullspace */
1374:   if (dm->Nf) {
1375:     MatNullSpace nullSpace;
1376:     PetscInt     Nf, f;

1378:     DMGetNumFields(dm, &Nf);
1379:     for (f = 0; f < Nf; ++f) {
1380:       if (dm->nullspaceConstructors[f]) {
1381:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1382:         MatSetNullSpace(*mat, nullSpace);
1383:         MatNullSpaceDestroy(&nullSpace);
1384:         break;
1385:       }
1386:     }
1387:     for (f = 0; f < Nf; ++f) {
1388:       if (dm->nearnullspaceConstructors[f]) {
1389:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1390:         MatSetNearNullSpace(*mat, nullSpace);
1391:         MatNullSpaceDestroy(&nullSpace);
1392:       }
1393:     }
1394:   }
1395:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1396:   return(0);
1397: }

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

1403:   Logically Collective on dm

1405:   Input Parameter:
1406: + dm - the DM
1407: - only - PETSC_TRUE if only want preallocation

1409:   Level: developer

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

1414: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1415: @*/
1416: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1417: {
1420:   dm->prealloc_only = only;
1421:   return(0);
1422: }

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

1428:   Logically Collective on dm

1430:   Input Parameter:
1431: + dm - the DM
1432: - only - PETSC_TRUE if only want matrix stucture

1434:   Level: developer
1435: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1436: @*/
1437: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1438: {
1441:   dm->structure_only = only;
1442:   return(0);
1443: }

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

1448:   Not Collective

1450:   Input Parameters:
1451: + dm - the DM object
1452: . count - The minium size
1453: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1455:   Output Parameter:
1456: . array - the work array

1458:   Level: developer

1460: .seealso DMDestroy(), DMCreate()
1461: @*/
1462: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1463: {
1465:   DMWorkLink     link;
1466:   PetscMPIInt    dsize;

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

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

1496:   Not Collective

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

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

1506:   Level: developer

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

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

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

1534:   Logically collective on DM

1536:   Input Parameters:
1537: + dm     - The DM
1538: . field  - The field number for the nullspace
1539: - nullsp - A callback to create the nullspace

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

1549:   This function is currently not available from Fortran.

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

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

1565:   Not collective

1567:   Input Parameters:
1568: + dm     - The DM
1569: - field  - The field number for the nullspace

1571:   Output Parameter:
1572: . nullsp - A callback to create the nullspace

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

1582:   This function is currently not available from Fortran.

1584: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1585: */
1586: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1587: {
1591:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1592:   *nullsp = dm->nullspaceConstructors[field];
1593:   return(0);
1594: }

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

1599:   Logically collective on DM

1601:   Input Parameters:
1602: + dm     - The DM
1603: . field  - The field number for the nullspace
1604: - nullsp - A callback to create the near-nullspace

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

1614:   This function is currently not available from Fortran.

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

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

1630:   Not collective

1632:   Input Parameters:
1633: + dm     - The DM
1634: - field  - The field number for the nullspace

1636:   Output Parameter:
1637: . nullsp - A callback to create the near-nullspace

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

1647:   This function is currently not available from Fortran.

1649: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1650: */
1651: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1652: {
1656:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1657:   *nullsp = dm->nearnullspaceConstructors[field];
1658:   return(0);
1659: }

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

1664:   Not collective

1666:   Input Parameter:
1667: . dm - the DM object

1669:   Output Parameters:
1670: + numFields  - The number of fields (or NULL if not requested)
1671: . fieldNames - The name for each field (or NULL if not requested)
1672: - fields     - The global indices for each field (or NULL if not requested)

1674:   Level: intermediate

1676:   Notes:
1677:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1678:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1679:   PetscFree().

1681: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1682: @*/
1683: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1684: {
1685:   PetscSection   section, sectionGlobal;

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

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

1718:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1719:       if (gdof > 0) {
1720:         for (f = 0; f < nF; ++f) {
1721:           PetscInt fdof, fcdof, fpdof;

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

1741:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1742:       if (gdof > 0) {
1743:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1744:         for (f = 0; f < nF; ++f) {
1745:           PetscInt fdof, fcdof, fc;

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

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

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


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

1792:   Not collective

1794:   Input Parameter:
1795: . dm - the DM object

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

1803:   Level: intermediate

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

1810: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1811: @*/
1812: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1813: {

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

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

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

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

1875:   Not collective

1877:   Input Parameters:
1878: + dm        - The DM object
1879: . numFields - The number of fields in this subproblem
1880: - fields    - The field numbers of the selected fields

1882:   Output Parameters:
1883: + is - The global indices for the subproblem
1884: - subdm - The DM for the subproblem

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

1888:   Level: intermediate

1890: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1891: @*/
1892: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1893: {

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

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

1909:   Not collective

1911:   Input Parameter:
1912: + dms - The DM objects
1913: - len - The number of DMs

1915:   Output Parameters:
1916: + is - The global indices for the subproblem, or NULL
1917: - superdm - The DM for the superproblem

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

1921:   Level: intermediate

1923: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1924: @*/
1925: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1926: {
1927:   PetscInt       i;

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


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

1952:   Not collective

1954:   Input Parameter:
1955: . dm - the DM object

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

1964:   Level: intermediate

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

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

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


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

2012:   Not collective

2014:   Input Parameters:
2015: + dm - the DM object
2016: . n  - the number of subdomain scatters
2017: - subdms - the local subdomains

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

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

2031:   Level: developer

2033: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2034: @*/
2035: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2036: {

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

2047: /*@
2048:   DMRefine - Refines a DM object

2050:   Collective on dm

2052:   Input Parameter:
2053: + dm   - the DM object
2054: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2056:   Output Parameter:
2057: . dmf - the refined DM, or NULL

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

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

2064:   Level: developer

2066: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2067: @*/
2068: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2069: {
2070:   PetscErrorCode   ierr;
2071:   DMRefineHookLink link;

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

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

2083:     (*dmf)->ctx       = dm->ctx;
2084:     (*dmf)->leveldown = dm->leveldown;
2085:     (*dmf)->levelup   = dm->levelup + 1;

2087:     DMSetMatType(*dmf,dm->mattype);
2088:     for (link=dm->refinehook; link; link=link->next) {
2089:       if (link->refinehook) {
2090:         (*link->refinehook)(dm,*dmf,link->ctx);
2091:       }
2092:     }
2093:   }
2094:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2095:   return(0);
2096: }

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

2101:    Logically Collective

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

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

2112: +  coarse - coarse level DM
2113: .  fine - fine level DM to interpolate problem to
2114: -  ctx - optional user-defined function context

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

2119: +  coarse - coarse level DM
2120: .  interp - matrix interpolating a coarse-level solution to the finer grid
2121: .  fine - fine level DM to update
2122: -  ctx - optional user-defined function context

2124:    Level: advanced

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

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

2131:    This function is currently not available from Fortran.

2133: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2134: @*/
2135: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2136: {
2137:   PetscErrorCode   ierr;
2138:   DMRefineHookLink link,*p;

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

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

2157:    Logically Collective

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

2165:    Level: advanced

2167:    Notes:
2168:    This function does nothing if the hook is not in the list.

2170:    This function is currently not available from Fortran.

2172: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2173: @*/
2174: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2175: {
2176:   PetscErrorCode   ierr;
2177:   DMRefineHookLink link,*p;

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

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

2195:    Collective if any hooks are

2197:    Input Arguments:
2198: +  coarse - coarser DM to use as a base
2199: .  interp - interpolation matrix, apply using MatInterpolate()
2200: -  fine - finer DM to update

2202:    Level: developer

2204: .seealso: DMRefineHookAdd(), MatInterpolate()
2205: @*/
2206: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2207: {
2208:   PetscErrorCode   ierr;
2209:   DMRefineHookLink link;

2212:   for (link=fine->refinehook; link; link=link->next) {
2213:     if (link->interphook) {
2214:       (*link->interphook)(coarse,interp,fine,link->ctx);
2215:     }
2216:   }
2217:   return(0);
2218: }

2220: /*@
2221:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2223:    Collective on DM

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

2233:    Output Arguments:
2234: .  fineSol - the interpolation of coarseSol to the fine mesh

2236:    Level: developer

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

2243: .seealso DMInterpolate(), DMCreateInterpolation()
2244: @*/
2245: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2246: {
2247:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;


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

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

2269:     Not Collective

2271:     Input Parameter:
2272: .   dm - the DM object

2274:     Output Parameter:
2275: .   level - number of refinements

2277:     Level: developer

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

2281: @*/
2282: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2283: {
2286:   *level = dm->levelup;
2287:   return(0);
2288: }

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

2293:     Not Collective

2295:     Input Parameter:
2296: +   dm - the DM object
2297: -   level - number of refinements

2299:     Level: advanced

2301:     Notes:
2302:     This value is used by PCMG to determine how many multigrid levels to use

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

2306: @*/
2307: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2308: {
2311:   dm->levelup = level;
2312:   return(0);
2313: }

2315: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2316: {
2320:   *tdm = dm->transformDM;
2321:   return(0);
2322: }

2324: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2325: {
2329:   *tv = dm->transform;
2330:   return(0);
2331: }

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

2336:   Input Parameter:
2337: . dm - The DM

2339:   Output Parameter:
2340: . flg - PETSC_TRUE if a basis transformation should be done

2342:   Level: developer

2344: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2345: @*/
2346: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2347: {
2348:   Vec            tv;

2354:   DMGetBasisTransformVec_Internal(dm, &tv);
2355:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2356:   return(0);
2357: }

2359: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2360: {
2361:   PetscSection   s, ts;
2362:   PetscScalar   *ta;
2363:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

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

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

2408: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2409: {

2415:   newdm->transformCtx       = dm->transformCtx;
2416:   newdm->transformSetUp     = dm->transformSetUp;
2417:   newdm->transformDestroy   = NULL;
2418:   newdm->transformGetMatrix = dm->transformGetMatrix;
2419:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2420:   return(0);
2421: }

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

2426:    Logically Collective

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

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

2437: +  dm - global DM
2438: .  g - global vector
2439: .  mode - mode
2440: .  l - local vector
2441: -  ctx - optional user-defined function context


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

2447: +  global - global DM
2448: -  ctx - optional user-defined function context

2450:    Level: advanced

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

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

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

2481:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2482:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2483:     PetscInt nRows;

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

2504: /*@
2505:     DMGlobalToLocal - update local vectors from global vector

2507:     Neighbor-wise Collective on dm

2509:     Input Parameters:
2510: +   dm - the DM object
2511: .   g - the global vector
2512: .   mode - INSERT_VALUES or ADD_VALUES
2513: -   l - the local vector

2515:     Notes:
2516:     The communication involved in this update can be overlapped with computation by using
2517:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2519:     Level: beginner

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

2523: @*/
2524: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2525: {

2529:   DMGlobalToLocalBegin(dm,g,mode,l);
2530:   DMGlobalToLocalEnd(dm,g,mode,l);
2531:   return(0);
2532: }

2534: /*@
2535:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2537:     Neighbor-wise Collective on dm

2539:     Input Parameters:
2540: +   dm - the DM object
2541: .   g - the global vector
2542: .   mode - INSERT_VALUES or ADD_VALUES
2543: -   l - the local vector

2545:     Level: intermediate

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

2549: @*/
2550: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2551: {
2552:   PetscSF                 sf;
2553:   PetscErrorCode          ierr;
2554:   DMGlobalToLocalHookLink link;


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

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

2583: /*@
2584:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2586:     Neighbor-wise Collective on dm

2588:     Input Parameters:
2589: +   dm - the DM object
2590: .   g - the global vector
2591: .   mode - INSERT_VALUES or ADD_VALUES
2592: -   l - the local vector

2594:     Level: intermediate

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

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

2611:   DMGetSectionSF(dm, &sf);
2612:   DMHasBasisTransform(dm, &transform);
2613:   if (sf) {
2614:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

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

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

2636:    Logically Collective

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

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

2647: +  dm - global DM
2648: .  l - local vector
2649: .  mode - mode
2650: .  g - global vector
2651: -  ctx - optional user-defined function context


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

2657: +  global - global DM
2658: .  l - local vector
2659: .  mode - mode
2660: .  g - global vector
2661: -  ctx - optional user-defined function context

2663:    Level: advanced

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

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

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

2694:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2695:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2696:     PetscInt nRows;

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

2725:     Neighbor-wise Collective on dm

2727:     Input Parameters:
2728: +   dm - the DM object
2729: .   l - the local vector
2730: .   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.
2731: -   g - the global vector

2733:     Notes:
2734:     The communication involved in this update can be overlapped with computation by using
2735:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2740:     Level: beginner

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

2744: @*/
2745: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2746: {

2750:   DMLocalToGlobalBegin(dm,l,mode,g);
2751:   DMLocalToGlobalEnd(dm,l,mode,g);
2752:   return(0);
2753: }

2755: /*@
2756:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2758:     Neighbor-wise Collective on dm

2760:     Input Parameters:
2761: +   dm - the DM object
2762: .   l - the local vector
2763: .   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.
2764: -   g - the global vector

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

2770:     Level: intermediate

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

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

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

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

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

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

2884: /*@
2885:     DMLocalToGlobalEnd - updates global vectors from local vectors

2887:     Neighbor-wise Collective on dm

2889:     Input Parameters:
2890: +   dm - the DM object
2891: .   l - the local vector
2892: .   mode - INSERT_VALUES or ADD_VALUES
2893: -   g - the global vector

2895:     Level: intermediate

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

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

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

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

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

2959:    Neighbor-wise Collective on dm

2961:    Input Parameters:
2962: +  dm - the DM object
2963: .  g - the original local vector
2964: -  mode - one of INSERT_VALUES or ADD_VALUES

2966:    Output Parameter:
2967: .  l  - the local vector with correct ghost values

2969:    Level: intermediate

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

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

2979: @*/
2980: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2981: {
2982:   PetscErrorCode          ierr;

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

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

2996:    Neighbor-wise Collective on dm

2998:    Input Parameters:
2999: +  da - the DM object
3000: .  g - the original local vector
3001: -  mode - one of INSERT_VALUES or ADD_VALUES

3003:    Output Parameter:
3004: .  l  - the local vector with correct ghost values

3006:    Level: intermediate

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

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

3016: @*/
3017: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3018: {
3019:   PetscErrorCode          ierr;

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


3029: /*@
3030:     DMCoarsen - Coarsens a DM object

3032:     Collective on dm

3034:     Input Parameter:
3035: +   dm - the DM object
3036: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

3038:     Output Parameter:
3039: .   dmc - the coarsened DM

3041:     Level: developer

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

3045: @*/
3046: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3047: {
3048:   PetscErrorCode    ierr;
3049:   DMCoarsenHookLink link;

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

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

3076:    Logically Collective

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

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

3087: +  fine - fine level DM
3088: .  coarse - coarse level DM to restrict problem to
3089: -  ctx - optional user-defined function context

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

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

3101:    Level: advanced

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

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

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

3111:    This function is currently not available from Fortran.

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

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

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

3137:    Logically Collective

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

3145:    Level: advanced

3147:    Notes:
3148:    This function does nothing if the hook is not in the list.

3150:    This function is currently not available from Fortran.

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

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


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

3176:    Collective if any hooks are

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

3185:    Level: developer

3187: .seealso: DMCoarsenHookAdd(), MatRestrict()
3188: @*/
3189: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3190: {
3191:   PetscErrorCode    ierr;
3192:   DMCoarsenHookLink link;

3195:   for (link=fine->coarsenhook; link; link=link->next) {
3196:     if (link->restricthook) {
3197:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3198:     }
3199:   }
3200:   return(0);
3201: }

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

3206:    Logically Collective on global

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


3215:    Calling sequence for ddhook:
3216: $    ddhook(DM global,DM block,void *ctx)

3218: +  global - global DM
3219: .  block  - block DM
3220: -  ctx - optional user-defined function context

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

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

3231:    Level: advanced

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

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

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

3241:    This function is currently not available from Fortran.

3243: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3244: @*/
3245: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3246: {
3247:   PetscErrorCode      ierr;
3248:   DMSubDomainHookLink link,*p;

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

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

3267:    Logically Collective

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

3275:    Level: advanced

3277:    Notes:

3279:    This function is currently not available from Fortran.

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

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

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

3304:    Collective if any hooks are

3306:    Input Arguments:
3307: +  fine - finer DM to use as a base
3308: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3309: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3310: -  coarse - coarer DM to update

3312:    Level: developer

3314: .seealso: DMCoarsenHookAdd(), MatRestrict()
3315: @*/
3316: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3317: {
3318:   PetscErrorCode      ierr;
3319:   DMSubDomainHookLink link;

3322:   for (link=global->subdomainhook; link; link=link->next) {
3323:     if (link->restricthook) {
3324:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3325:     }
3326:   }
3327:   return(0);
3328: }

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

3333:     Not Collective

3335:     Input Parameter:
3336: .   dm - the DM object

3338:     Output Parameter:
3339: .   level - number of coarsenings

3341:     Level: developer

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

3345: @*/
3346: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3347: {
3351:   *level = dm->leveldown;
3352:   return(0);
3353: }

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

3358:     Not Collective

3360:     Input Parameters:
3361: +   dm - the DM object
3362: -   level - number of coarsenings

3364:     Level: developer

3366: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3367: @*/
3368: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3369: {
3372:   dm->leveldown = level;
3373:   return(0);
3374: }



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

3381:     Collective on dm

3383:     Input Parameter:
3384: +   dm - the DM object
3385: -   nlevels - the number of levels of refinement

3387:     Output Parameter:
3388: .   dmf - the refined DM hierarchy

3390:     Level: developer

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

3394: @*/
3395: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3396: {

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

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

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

3420:     Collective on dm

3422:     Input Parameter:
3423: +   dm - the DM object
3424: -   nlevels - the number of levels of coarsening

3426:     Output Parameter:
3427: .   dmc - the coarsened DM hierarchy

3429:     Level: developer

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

3433: @*/
3434: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3435: {

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

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

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

3459:     Not Collective

3461:     Input Parameters:
3462: +   dm - the DM object
3463: -   destroy - the destroy function

3465:     Level: intermediate

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

3469: @*/
3470: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3471: {
3474:   dm->ctxdestroy = destroy;
3475:   return(0);
3476: }

3478: /*@
3479:     DMSetApplicationContext - Set a user context into a DM object

3481:     Not Collective

3483:     Input Parameters:
3484: +   dm - the DM object
3485: -   ctx - the user context

3487:     Level: intermediate

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

3491: @*/
3492: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3493: {
3496:   dm->ctx = ctx;
3497:   return(0);
3498: }

3500: /*@
3501:     DMGetApplicationContext - Gets a user context from a DM object

3503:     Not Collective

3505:     Input Parameter:
3506: .   dm - the DM object

3508:     Output Parameter:
3509: .   ctx - the user context

3511:     Level: intermediate

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

3515: @*/
3516: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3517: {
3520:   *(void**)ctx = dm->ctx;
3521:   return(0);
3522: }

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

3527:     Logically Collective on dm

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

3533:     Level: intermediate

3535: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3536:          DMSetJacobian()

3538: @*/
3539: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3540: {
3543:   dm->ops->computevariablebounds = f;
3544:   return(0);
3545: }

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

3550:     Not Collective

3552:     Input Parameter:
3553: .   dm - the DM object to destroy

3555:     Output Parameter:
3556: .   flg - PETSC_TRUE if the variable bounds function exists

3558:     Level: developer

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

3562: @*/
3563: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3564: {
3568:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3569:   return(0);
3570: }

3572: /*@C
3573:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3575:     Logically Collective on dm

3577:     Input Parameters:
3578: .   dm - the DM object

3580:     Output parameters:
3581: +   xl - lower bound
3582: -   xu - upper bound

3584:     Level: advanced

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

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

3591: @*/
3592: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3593: {

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

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

3608:     Not Collective

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

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

3616:     Level: developer

3618: .seealso DMCreateColoring()

3620: @*/
3621: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3622: {
3626:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3627:   return(0);
3628: }

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

3633:     Not Collective

3635:     Input Parameter:
3636: .   dm - the DM object

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

3641:     Level: developer

3643: .seealso DMCreateRestriction()

3645: @*/
3646: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3647: {
3651:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3652:   return(0);
3653: }


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

3659:     Not Collective

3661:     Input Parameter:
3662: .   dm - the DM object

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

3667:     Level: developer

3669: .seealso DMCreateInjection()

3671: @*/
3672: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3673: {

3679:   if (dm->ops->hascreateinjection) {
3680:     (*dm->ops->hascreateinjection)(dm,flg);
3681:   } else {
3682:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3683:   }
3684:   return(0);
3685: }

3687: PetscFunctionList DMList              = NULL;
3688: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3690: /*@C
3691:   DMSetType - Builds a DM, for a particular DM implementation.

3693:   Collective on dm

3695:   Input Parameters:
3696: + dm     - The DM object
3697: - method - The name of the DM type

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

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

3705:   Level: intermediate

3707: .seealso: DMGetType(), DMCreate()
3708: @*/
3709: PetscErrorCode  DMSetType(DM dm, DMType method)
3710: {
3711:   PetscErrorCode (*r)(DM);
3712:   PetscBool      match;

3717:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3718:   if (match) return(0);

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

3724:   if (dm->ops->destroy) {
3725:     (*dm->ops->destroy)(dm);
3726:   }
3727:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3728:   PetscObjectChangeTypeName((PetscObject)dm,method);
3729:   (*r)(dm);
3730:   return(0);
3731: }

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

3736:   Not Collective

3738:   Input Parameter:
3739: . dm  - The DM

3741:   Output Parameter:
3742: . type - The DM type name

3744:   Level: intermediate

3746: .seealso: DMSetType(), DMCreate()
3747: @*/
3748: PetscErrorCode  DMGetType(DM dm, DMType *type)
3749: {

3755:   DMRegisterAll();
3756:   *type = ((PetscObject)dm)->type_name;
3757:   return(0);
3758: }

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

3763:   Collective on dm

3765:   Input Parameters:
3766: + dm - the DM
3767: - newtype - new DM type (use "same" for the same type)

3769:   Output Parameter:
3770: . M - pointer to new DM

3772:   Notes:
3773:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3774:   the MPI communicator of the generated DM is always the same as the communicator
3775:   of the input DM.

3777:   Level: intermediate

3779: .seealso: DMCreate()
3780: @*/
3781: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3782: {
3783:   DM             B;
3784:   char           convname[256];
3785:   PetscBool      sametype/*, issame */;

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

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

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

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

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

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

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

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

3871: /*--------------------------------------------------------------------------------------------------------------------*/

3873: /*@C
3874:   DMRegister -  Adds a new DM component implementation

3876:   Not Collective

3878:   Input Parameters:
3879: + name        - The name of a new user-defined creation routine
3880: - create_func - The creation routine itself

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


3886:   Sample usage:
3887: .vb
3888:     DMRegister("my_da", MyDMCreate);
3889: .ve

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

3901:   Level: advanced

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

3905: @*/
3906: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3907: {

3911:   DMInitializePackage();
3912:   PetscFunctionListAdd(&DMList,sname,function);
3913:   return(0);
3914: }

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

3919:   Collective on viewer

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

3927:    Level: intermediate

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

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

3941: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3942: @*/
3943: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3944: {
3945:   PetscBool      isbinary, ishdf5;

3951:   PetscViewerCheckReadable(viewer);
3952:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3953:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3954:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3955:   if (isbinary) {
3956:     PetscInt classid;
3957:     char     type[256];

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

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

3974:   Not collective

3976:   Input Parameter:
3977: . dm - the DM

3979:   Output Parameters:
3980: + lmin - local minimum coordinates (length coord dim, optional)
3981: - lmax - local maximim coordinates (length coord dim, optional)

3983:   Level: beginner

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


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

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

4018:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
4019:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
4020:   }
4021:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
4022:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
4023:   return(0);
4024: }

4026: /*@
4027:   DMGetBoundingBox - Returns the global bounding box for the DM.

4029:   Collective

4031:   Input Parameter:
4032: . dm - the DM

4034:   Output Parameters:
4035: + gmin - global minimum coordinates (length coord dim, optional)
4036: - gmax - global maximim coordinates (length coord dim, optional)

4038:   Level: beginner

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

4051:   DMGetCoordinateDim(dm, &cdim);
4052:   PetscMPIIntCast(cdim, &count);
4053:   DMGetLocalBoundingBox(dm, lmin, lmax);
4054:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
4055:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
4056:   return(0);
4057: }

4059: /******************************** FEM Support **********************************/

4061: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4062: {
4063:   PetscInt       f;

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

4074: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4075: {
4076:   PetscInt       f, g;

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

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

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

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

4125:   Input Parameter:
4126: . dm - The DM

4128:   Output Parameter:
4129: . section - The PetscSection

4131:   Options Database Keys:
4132: . -dm_petscsection_view - View the Section created by the DM

4134:   Level: advanced

4136:   Notes:
4137:   Use DMGetLocalSection() in new code.

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

4141: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4142: @*/
4143: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4144: {

4148:   DMGetLocalSection(dm,section);
4149:   return(0);
4150: }

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

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

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

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

4164:   Level: intermediate

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

4168: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4169: @*/
4170: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4171: {

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

4180:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4181:     (*dm->ops->createlocalsection)(dm);
4182:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4183:   }
4184:   *section = dm->localSection;
4185:   return(0);
4186: }

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

4191:   Input Parameters:
4192: + dm - The DM
4193: - section - The PetscSection

4195:   Level: advanced

4197:   Notes:
4198:   Use DMSetLocalSection() in new code.

4200:   Any existing Section will be destroyed

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

4209:   DMSetLocalSection(dm,section);
4210:   return(0);
4211: }

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

4216:   Input Parameters:
4217: + dm - The DM
4218: - section - The PetscSection

4220:   Level: intermediate

4222:   Note: Any existing Section will be destroyed

4224: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4225: @*/
4226: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4227: {
4228:   PetscInt       numFields = 0;
4229:   PetscInt       f;

4235:   PetscObjectReference((PetscObject)section);
4236:   PetscSectionDestroy(&dm->localSection);
4237:   dm->localSection = section;
4238:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4239:   if (numFields) {
4240:     DMSetNumFields(dm, numFields);
4241:     for (f = 0; f < numFields; ++f) {
4242:       PetscObject disc;
4243:       const char *name;

4245:       PetscSectionGetFieldName(dm->localSection, f, &name);
4246:       DMGetField(dm, f, NULL, &disc);
4247:       PetscObjectSetName(disc, name);
4248:     }
4249:   }
4250:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4251:   PetscSectionDestroy(&dm->globalSection);
4252:   return(0);
4253: }

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

4258:   not collective

4260:   Input Parameter:
4261: . dm - The DM

4263:   Output Parameter:
4264: + 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.
4265: - 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.

4267:   Level: advanced

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

4271: .seealso: DMSetDefaultConstraints()
4272: @*/
4273: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4274: {

4279:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4280:   if (section) {*section = dm->defaultConstraintSection;}
4281:   if (mat) {*mat = dm->defaultConstraintMat;}
4282:   return(0);
4283: }

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

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

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

4292:   collective on dm

4294:   Input Parameters:
4295: + dm - The DM
4296: + 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).
4297: - 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).

4299:   Level: advanced

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

4303: .seealso: DMGetDefaultConstraints()
4304: @*/
4305: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4306: {
4307:   PetscMPIInt result;

4312:   if (section) {
4314:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4315:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4316:   }
4317:   if (mat) {
4319:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4320:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4321:   }
4322:   PetscObjectReference((PetscObject)section);
4323:   PetscSectionDestroy(&dm->defaultConstraintSection);
4324:   dm->defaultConstraintSection = section;
4325:   PetscObjectReference((PetscObject)mat);
4326:   MatDestroy(&dm->defaultConstraintMat);
4327:   dm->defaultConstraintMat = mat;
4328:   return(0);
4329: }

4331: #if defined(PETSC_USE_DEBUG)
4332: /*
4333:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4335:   Input Parameters:
4336: + dm - The DM
4337: . localSection - PetscSection describing the local data layout
4338: - globalSection - PetscSection describing the global data layout

4340:   Level: intermediate

4342: .seealso: DMGetSectionSF(), DMSetSectionSF()
4343: */
4344: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4345: {
4346:   MPI_Comm        comm;
4347:   PetscLayout     layout;
4348:   const PetscInt *ranges;
4349:   PetscInt        pStart, pEnd, p, nroots;
4350:   PetscMPIInt     size, rank;
4351:   PetscBool       valid = PETSC_TRUE, gvalid;
4352:   PetscErrorCode  ierr;

4355:   PetscObjectGetComm((PetscObject)dm,&comm);
4357:   MPI_Comm_size(comm, &size);
4358:   MPI_Comm_rank(comm, &rank);
4359:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4360:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4361:   PetscLayoutCreate(comm, &layout);
4362:   PetscLayoutSetBlockSize(layout, 1);
4363:   PetscLayoutSetLocalSize(layout, nroots);
4364:   PetscLayoutSetUp(layout);
4365:   PetscLayoutGetRanges(layout, &ranges);
4366:   for (p = pStart; p < pEnd; ++p) {
4367:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4369:     PetscSectionGetDof(localSection, p, &dof);
4370:     PetscSectionGetOffset(localSection, p, &off);
4371:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4372:     PetscSectionGetDof(globalSection, p, &gdof);
4373:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4374:     PetscSectionGetOffset(globalSection, p, &goff);
4375:     if (!gdof) continue; /* Censored point */
4376:     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;}
4377:     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;}
4378:     if (gdof < 0) {
4379:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4380:       for (d = 0; d < gsize; ++d) {
4381:         PetscInt offset = -(goff+1) + d, r;

4383:         PetscFindInt(offset,size+1,ranges,&r);
4384:         if (r < 0) r = -(r+2);
4385:         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;}
4386:       }
4387:     }
4388:   }
4389:   PetscLayoutDestroy(&layout);
4390:   PetscSynchronizedFlush(comm, NULL);
4391:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4392:   if (!gvalid) {
4393:     DMView(dm, NULL);
4394:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4395:   }
4396:   return(0);
4397: }
4398: #endif

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

4403:   Collective on dm

4405:   Input Parameter:
4406: . dm - The DM

4408:   Output Parameter:
4409: . section - The PetscSection

4411:   Level: intermediate

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

4415: .seealso: DMSetLocalSection(), DMGetLocalSection()
4416: @*/
4417: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4418: {

4424:   if (!dm->globalSection) {
4425:     PetscSection s;

4427:     DMGetLocalSection(dm, &s);
4428:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4429:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4430:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4431:     PetscLayoutDestroy(&dm->map);
4432:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4433:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4434:   }
4435:   *section = dm->globalSection;
4436:   return(0);
4437: }

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

4442:   Input Parameters:
4443: + dm - The DM
4444: - section - The PetscSection, or NULL

4446:   Level: intermediate

4448:   Note: Any existing Section will be destroyed

4450: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4451: @*/
4452: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4453: {

4459:   PetscObjectReference((PetscObject)section);
4460:   PetscSectionDestroy(&dm->globalSection);
4461:   dm->globalSection = section;
4462: #if defined(PETSC_USE_DEBUG)
4463:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4464: #endif
4465:   return(0);
4466: }

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

4472:   Input Parameter:
4473: . dm - The DM

4475:   Output Parameter:
4476: . sf - The PetscSF

4478:   Level: intermediate

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

4482: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4483: @*/
4484: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4485: {
4486:   PetscInt       nroots;

4492:   if (!dm->sectionSF) {
4493:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4494:   }
4495:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4496:   if (nroots < 0) {
4497:     PetscSection section, gSection;

4499:     DMGetLocalSection(dm, &section);
4500:     if (section) {
4501:       DMGetGlobalSection(dm, &gSection);
4502:       DMCreateSectionSF(dm, section, gSection);
4503:     } else {
4504:       *sf = NULL;
4505:       return(0);
4506:     }
4507:   }
4508:   *sf = dm->sectionSF;
4509:   return(0);
4510: }

4512: /*@
4513:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4515:   Input Parameters:
4516: + dm - The DM
4517: - sf - The PetscSF

4519:   Level: intermediate

4521:   Note: Any previous SF is destroyed

4523: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4524: @*/
4525: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4526: {

4532:   PetscObjectReference((PetscObject) sf);
4533:   PetscSFDestroy(&dm->sectionSF);
4534:   dm->sectionSF = sf;
4535:   return(0);
4536: }

4538: /*@C
4539:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4540:   describing the data layout.

4542:   Input Parameters:
4543: + dm - The DM
4544: . localSection - PetscSection describing the local data layout
4545: - globalSection - PetscSection describing the global data layout

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

4549:   Level: developer

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

4555: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4556: @*/
4557: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4558: {

4563:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4564:   return(0);
4565: }

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

4570:   Input Parameter:
4571: . dm - The DM

4573:   Output Parameter:
4574: . sf - The PetscSF

4576:   Level: intermediate

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

4580: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4581: @*/
4582: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4583: {
4587:   *sf = dm->sf;
4588:   return(0);
4589: }

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

4594:   Input Parameters:
4595: + dm - The DM
4596: - sf - The PetscSF

4598:   Level: intermediate

4600: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4601: @*/
4602: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4603: {

4609:   PetscObjectReference((PetscObject) sf);
4610:   PetscSFDestroy(&dm->sf);
4611:   dm->sf = sf;
4612:   return(0);
4613: }

4615: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4616: {
4617:   PetscClassId   id;

4621:   PetscObjectGetClassId(disc, &id);
4622:   if (id == PETSCFE_CLASSID) {
4623:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4624:   } else if (id == PETSCFV_CLASSID) {
4625:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4626:   } else {
4627:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4628:   }
4629:   return(0);
4630: }

4632: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4633: {
4634:   RegionField   *tmpr;
4635:   PetscInt       Nf = dm->Nf, f;

4639:   if (Nf >= NfNew) return(0);
4640:   PetscMalloc1(NfNew, &tmpr);
4641:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4642:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4643:   PetscFree(dm->fields);
4644:   dm->Nf     = NfNew;
4645:   dm->fields = tmpr;
4646:   return(0);
4647: }

4649: /*@
4650:   DMClearFields - Remove all fields from the DM

4652:   Logically collective on dm

4654:   Input Parameter:
4655: . dm - The DM

4657:   Level: intermediate

4659: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4660: @*/
4661: PetscErrorCode DMClearFields(DM dm)
4662: {
4663:   PetscInt       f;

4668:   for (f = 0; f < dm->Nf; ++f) {
4669:     PetscObjectDestroy(&dm->fields[f].disc);
4670:     DMLabelDestroy(&dm->fields[f].label);
4671:   }
4672:   PetscFree(dm->fields);
4673:   dm->fields = NULL;
4674:   dm->Nf     = 0;
4675:   return(0);
4676: }

4678: /*@
4679:   DMGetNumFields - Get the number of fields in the DM

4681:   Not collective

4683:   Input Parameter:
4684: . dm - The DM

4686:   Output Parameter:
4687: . Nf - The number of fields

4689:   Level: intermediate

4691: .seealso: DMSetNumFields(), DMSetField()
4692: @*/
4693: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4694: {
4698:   *numFields = dm->Nf;
4699:   return(0);
4700: }

4702: /*@
4703:   DMSetNumFields - Set the number of fields in the DM

4705:   Logically collective on dm

4707:   Input Parameters:
4708: + dm - The DM
4709: - Nf - The number of fields

4711:   Level: intermediate

4713: .seealso: DMGetNumFields(), DMSetField()
4714: @*/
4715: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4716: {
4717:   PetscInt       Nf, f;

4722:   DMGetNumFields(dm, &Nf);
4723:   for (f = Nf; f < numFields; ++f) {
4724:     PetscContainer obj;

4726:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4727:     DMAddField(dm, NULL, (PetscObject) obj);
4728:     PetscContainerDestroy(&obj);
4729:   }
4730:   return(0);
4731: }

4733: /*@
4734:   DMGetField - Return the discretization object for a given DM field

4736:   Not collective

4738:   Input Parameters:
4739: + dm - The DM
4740: - f  - The field number

4742:   Output Parameters:
4743: + label - The label indicating the support of the field, or NULL for the entire mesh
4744: - field - The discretization object

4746:   Level: intermediate

4748: .seealso: DMAddField(), DMSetField()
4749: @*/
4750: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4751: {
4755:   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);
4756:   if (label) *label = dm->fields[f].label;
4757:   if (field) *field = dm->fields[f].disc;
4758:   return(0);
4759: }

4761: /* Does not clear the DS */
4762: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4763: {

4767:   DMFieldEnlarge_Static(dm, f+1);
4768:   DMLabelDestroy(&dm->fields[f].label);
4769:   PetscObjectDestroy(&dm->fields[f].disc);
4770:   dm->fields[f].label = label;
4771:   dm->fields[f].disc  = field;
4772:   PetscObjectReference((PetscObject) label);
4773:   PetscObjectReference((PetscObject) field);
4774:   return(0);
4775: }

4777: /*@
4778:   DMSetField - Set the discretization object for a given DM field

4780:   Logically collective on dm

4782:   Input Parameters:
4783: + dm    - The DM
4784: . f     - The field number
4785: . label - The label indicating the support of the field, or NULL for the entire mesh
4786: - field - The discretization object

4788:   Level: intermediate

4790: .seealso: DMAddField(), DMGetField()
4791: @*/
4792: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4793: {

4800:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4801:   DMSetField_Internal(dm, f, label, field);
4802:   DMSetDefaultAdjacency_Private(dm, f, field);
4803:   DMClearDS(dm);
4804:   return(0);
4805: }

4807: /*@
4808:   DMAddField - Add the discretization object for the given DM field

4810:   Logically collective on dm

4812:   Input Parameters:
4813: + dm    - The DM
4814: . label - The label indicating the support of the field, or NULL for the entire mesh
4815: - field - The discretization object

4817:   Level: intermediate

4819: .seealso: DMSetField(), DMGetField()
4820: @*/
4821: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4822: {
4823:   PetscInt       Nf = dm->Nf;

4830:   DMFieldEnlarge_Static(dm, Nf+1);
4831:   dm->fields[Nf].label = label;
4832:   dm->fields[Nf].disc  = field;
4833:   PetscObjectReference((PetscObject) label);
4834:   PetscObjectReference((PetscObject) field);
4835:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4836:   DMClearDS(dm);
4837:   return(0);
4838: }

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

4843:   Logically collective on dm

4845:   Input Parameters:
4846: + dm          - The DM
4847: . f           - The field index
4848: - avoidTensor - The flag to avoid defining the field on tensor cells

4850:   Level: intermediate

4852: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4853: @*/
4854: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4855: {
4857:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4858:   dm->fields[f].avoidTensor = avoidTensor;
4859:   return(0);
4860: }

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

4865:   Logically collective on dm

4867:   Input Parameters:
4868: + dm          - The DM
4869: - f           - The field index

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

4874:   Level: intermediate

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

4886: /*@
4887:   DMCopyFields - Copy the discretizations for the DM into another DM

4889:   Collective on dm

4891:   Input Parameter:
4892: . dm - The DM

4894:   Output Parameter:
4895: . newdm - The DM

4897:   Level: advanced

4899: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4900: @*/
4901: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4902: {
4903:   PetscInt       Nf, f;

4907:   if (dm == newdm) return(0);
4908:   DMGetNumFields(dm, &Nf);
4909:   DMClearFields(newdm);
4910:   for (f = 0; f < Nf; ++f) {
4911:     DMLabel     label;
4912:     PetscObject field;
4913:     PetscBool   useCone, useClosure;

4915:     DMGetField(dm, f, &label, &field);
4916:     DMSetField(newdm, f, label, field);
4917:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4918:     DMSetAdjacency(newdm, f, useCone, useClosure);
4919:   }
4920:   return(0);
4921: }

4923: /*@
4924:   DMGetAdjacency - Returns the flags for determining variable influence

4926:   Not collective

4928:   Input Parameters:
4929: + dm - The DM object
4930: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4932:   Output Parameter:
4933: + useCone    - Flag for variable influence starting with the cone operation
4934: - useClosure - Flag for variable influence using transitive closure

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

4942:   Level: developer

4944: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4945: @*/
4946: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4947: {
4952:   if (f < 0) {
4953:     if (useCone)    *useCone    = dm->adjacency[0];
4954:     if (useClosure) *useClosure = dm->adjacency[1];
4955:   } else {
4956:     PetscInt       Nf;

4959:     DMGetNumFields(dm, &Nf);
4960:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4961:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4962:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4963:   }
4964:   return(0);
4965: }

4967: /*@
4968:   DMSetAdjacency - Set the flags for determining variable influence

4970:   Not collective

4972:   Input Parameters:
4973: + dm         - The DM object
4974: . f          - The field number
4975: . useCone    - Flag for variable influence starting with the cone operation
4976: - useClosure - Flag for variable influence using transitive closure

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

4984:   Level: developer

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

4999:     DMGetNumFields(dm, &Nf);
5000:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
5001:     dm->fields[f].adjacency[0] = useCone;
5002:     dm->fields[f].adjacency[1] = useClosure;
5003:   }
5004:   return(0);
5005: }

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

5010:   Not collective

5012:   Input Parameters:
5013: . dm - The DM object

5015:   Output Parameter:
5016: + useCone    - Flag for variable influence starting with the cone operation
5017: - useClosure - Flag for variable influence using transitive closure

5019:   Notes:
5020: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5021: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5022: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5024:   Level: developer

5026: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
5027: @*/
5028: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5029: {
5030:   PetscInt       Nf;

5037:   DMGetNumFields(dm, &Nf);
5038:   if (!Nf) {
5039:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5040:   } else {
5041:     DMGetAdjacency(dm, 0, useCone, useClosure);
5042:   }
5043:   return(0);
5044: }

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

5049:   Not collective

5051:   Input Parameters:
5052: + dm         - The DM object
5053: . useCone    - Flag for variable influence starting with the cone operation
5054: - useClosure - Flag for variable influence using transitive closure

5056:   Notes:
5057: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5058: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5059: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5061:   Level: developer

5063: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5064: @*/
5065: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5066: {
5067:   PetscInt       Nf;

5072:   DMGetNumFields(dm, &Nf);
5073:   if (!Nf) {
5074:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5075:   } else {
5076:     DMSetAdjacency(dm, 0, useCone, useClosure);
5077:   }
5078:   return(0);
5079: }

5081: /* Complete labels that are being used for FEM BC */
5082: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5083: {
5084:   DMLabel        label;
5085:   PetscObject    obj;
5086:   PetscClassId   id;
5087:   PetscInt       Nbd, bd;
5088:   PetscBool      isFE      = PETSC_FALSE;
5089:   PetscBool      duplicate = PETSC_FALSE;

5093:   DMGetField(dm, field, NULL, &obj);
5094:   PetscObjectGetClassId(obj, &id);
5095:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5096:   DMGetLabel(dm, labelname, &label);
5097:   if (isFE && label) {
5098:     /* Only want to modify label once */
5099:     PetscDSGetNumBoundary(ds, &Nbd);
5100:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5101:       const char *lname;

5103:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5104:       PetscStrcmp(lname, labelname, &duplicate);
5105:       if (duplicate) break;
5106:     }
5107:     if (!duplicate) {
5108:       DM plex;

5110:       DMConvert(dm, DMPLEX, &plex);
5111:       if (plex) {DMPlexLabelComplete(plex, label);}
5112:       DMDestroy(&plex);
5113:     }
5114:   }
5115:   return(0);
5116: }

5118: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5119: {
5120:   DMSpace       *tmpd;
5121:   PetscInt       Nds = dm->Nds, s;

5125:   if (Nds >= NdsNew) return(0);
5126:   PetscMalloc1(NdsNew, &tmpd);
5127:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5128:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5129:   PetscFree(dm->probs);
5130:   dm->Nds   = NdsNew;
5131:   dm->probs = tmpd;
5132:   return(0);
5133: }

5135: /*@
5136:   DMGetNumDS - Get the number of discrete systems in the DM

5138:   Not collective

5140:   Input Parameter:
5141: . dm - The DM

5143:   Output Parameter:
5144: . Nds - The number of PetscDS objects

5146:   Level: intermediate

5148: .seealso: DMGetDS(), DMGetCellDS()
5149: @*/
5150: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5151: {
5155:   *Nds = dm->Nds;
5156:   return(0);
5157: }

5159: /*@
5160:   DMClearDS - Remove all discrete systems from the DM

5162:   Logically collective on dm

5164:   Input Parameter:
5165: . dm - The DM

5167:   Level: intermediate

5169: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5170: @*/
5171: PetscErrorCode DMClearDS(DM dm)
5172: {
5173:   PetscInt       s;

5178:   for (s = 0; s < dm->Nds; ++s) {
5179:     PetscDSDestroy(&dm->probs[s].ds);
5180:     DMLabelDestroy(&dm->probs[s].label);
5181:     ISDestroy(&dm->probs[s].fields);
5182:   }
5183:   PetscFree(dm->probs);
5184:   dm->probs = NULL;
5185:   dm->Nds   = 0;
5186:   return(0);
5187: }

5189: /*@
5190:   DMGetDS - Get the default PetscDS

5192:   Not collective

5194:   Input Parameter:
5195: . dm    - The DM

5197:   Output Parameter:
5198: . prob - The default PetscDS

5200:   Level: intermediate

5202: .seealso: DMGetCellDS(), DMGetRegionDS()
5203: @*/
5204: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5205: {

5211:   if (dm->Nds <= 0) {
5212:     PetscDS ds;

5214:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5215:     DMSetRegionDS(dm, NULL, NULL, ds);
5216:     PetscDSDestroy(&ds);
5217:   }
5218:   *prob = dm->probs[0].ds;
5219:   return(0);
5220: }

5222: /*@
5223:   DMGetCellDS - Get the PetscDS defined on a given cell

5225:   Not collective

5227:   Input Parameters:
5228: + dm    - The DM
5229: - point - Cell for the DS

5231:   Output Parameter:
5232: . prob - The PetscDS defined on the given cell

5234:   Level: developer

5236: .seealso: DMGetDS(), DMSetRegionDS()
5237: @*/
5238: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5239: {
5240:   PetscDS        probDef = NULL;
5241:   PetscInt       s;

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

5252:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5253:     else {
5254:       DMLabelGetValue(dm->probs[s].label, point, &val);
5255:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5256:     }
5257:   }
5258:   if (!*prob) *prob = probDef;
5259:   return(0);
5260: }

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

5265:   Not collective

5267:   Input Parameters:
5268: + dm    - The DM
5269: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5277:   Level: advanced

5279: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5280: @*/
5281: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5282: {
5283:   PetscInt Nds = dm->Nds, s;

5290:   for (s = 0; s < Nds; ++s) {
5291:     if (dm->probs[s].label == label) {
5292:       if (fields) *fields = dm->probs[s].fields;
5293:       if (ds)     *ds     = dm->probs[s].ds;
5294:       return(0);
5295:     }
5296:   }
5297:   return(0);
5298: }

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

5303:   Collective on dm

5305:   Input Parameters:
5306: + dm     - The DM
5307: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5308: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5309: - prob   - The PetscDS defined on the given cell

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

5314:   Level: advanced

5316: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5317: @*/
5318: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5319: {
5320:   PetscInt       Nds = dm->Nds, s;

5327:   for (s = 0; s < Nds; ++s) {
5328:     if (dm->probs[s].label == label) {
5329:       PetscDSDestroy(&dm->probs[s].ds);
5330:       dm->probs[s].ds = ds;
5331:       return(0);
5332:     }
5333:   }
5334:   DMDSEnlarge_Static(dm, Nds+1);
5335:   PetscObjectReference((PetscObject) label);
5336:   PetscObjectReference((PetscObject) fields);
5337:   PetscObjectReference((PetscObject) ds);
5338:   if (!label) {
5339:     /* Put the NULL label at the front, so it is returned as the default */
5340:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5341:     Nds = 0;
5342:   }
5343:   dm->probs[Nds].label  = label;
5344:   dm->probs[Nds].fields = fields;
5345:   dm->probs[Nds].ds     = ds;
5346:   return(0);
5347: }

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

5352:   Not collective

5354:   Input Parameters:
5355: + dm  - The DM
5356: - num - The region number, in [0, Nds)

5358:   Output Parameters:
5359: + label  - The region label, or NULL
5360: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5361: - ds     - The PetscDS defined on the given region, or NULL

5363:   Level: advanced

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

5374:   DMGetNumDS(dm, &Nds);
5375:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5376:   if (label) {
5378:     *label = dm->probs[num].label;
5379:   }
5380:   if (fields) {
5382:     *fields = dm->probs[num].fields;
5383:   }
5384:   if (ds) {
5386:     *ds = dm->probs[num].ds;
5387:   }
5388:   return(0);
5389: }

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

5394:   Not collective

5396:   Input Parameters:
5397: + dm     - The DM
5398: . num    - The region number, in [0, Nds)
5399: . label  - The region label, or NULL
5400: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5401: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5403:   Level: advanced

5405: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5406: @*/
5407: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5408: {
5409:   PetscInt       Nds;

5415:   DMGetNumDS(dm, &Nds);
5416:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5417:   PetscObjectReference((PetscObject) label);
5418:   DMLabelDestroy(&dm->probs[num].label);
5419:   dm->probs[num].label = label;
5420:   if (fields) {
5422:     PetscObjectReference((PetscObject) fields);
5423:     ISDestroy(&dm->probs[num].fields);
5424:     dm->probs[num].fields = fields;
5425:   }
5426:   if (ds) {
5428:     PetscObjectReference((PetscObject) ds);
5429:     PetscDSDestroy(&dm->probs[num].ds);
5430:     dm->probs[num].ds = ds;
5431:   }
5432:   return(0);
5433: }

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

5438:   Not collective

5440:   Input Parameters:
5441: + dm  - The DM
5442: - ds  - The PetscDS defined on the given region

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

5447:   Level: advanced

5449: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5450: @*/
5451: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5452: {
5453:   PetscInt       Nds, n;

5460:   DMGetNumDS(dm, &Nds);
5461:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5462:   if (n >= Nds) *num = -1;
5463:   else          *num = n;
5464:   return(0);
5465: }

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

5470:   Collective on dm

5472:   Input Parameter:
5473: . dm - The DM

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

5477:   Level: intermediate

5479: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5480: @*/
5481: PetscErrorCode DMCreateDS(DM dm)
5482: {
5483:   MPI_Comm       comm;
5484:   PetscDS        dsDef;
5485:   DMLabel       *labelSet;
5486:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5487:   PetscBool      doSetup = PETSC_TRUE, flg;

5492:   if (!dm->fields) return(0);
5493:   PetscObjectGetComm((PetscObject) dm, &comm);
5494:   DMGetCoordinateDim(dm, &dE);
5495:   /* Determine how many regions we have */
5496:   PetscMalloc1(Nf, &labelSet);
5497:   Nl   = 0;
5498:   Ndef = 0;
5499:   for (f = 0; f < Nf; ++f) {
5500:     DMLabel  label = dm->fields[f].label;
5501:     PetscInt l;

5503:     if (!label) {++Ndef; continue;}
5504:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5505:     if (l < Nl) continue;
5506:     labelSet[Nl++] = label;
5507:   }
5508:   /* Create default DS if there are no labels to intersect with */
5509:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5510:   if (!dsDef && Ndef && !Nl) {
5511:     IS        fields;
5512:     PetscInt *fld, nf;

5514:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5515:     if (nf) {
5516:       PetscMalloc1(nf, &fld);
5517:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5518:       ISCreate(PETSC_COMM_SELF, &fields);
5519:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5520:       ISSetType(fields, ISGENERAL);
5521:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5523:       PetscDSCreate(comm, &dsDef);
5524:       DMSetRegionDS(dm, NULL, fields, dsDef);
5525:       PetscDSDestroy(&dsDef);
5526:       ISDestroy(&fields);
5527:     }
5528:   }
5529:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5530:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5531:   /* Intersect labels with default fields */
5532:   if (Ndef && Nl) {
5533:     DM              plex;
5534:     DMLabel         cellLabel;
5535:     IS              fieldIS, allcellIS, defcellIS = NULL;
5536:     PetscInt       *fields;
5537:     const PetscInt *cells;
5538:     PetscInt        depth, nf = 0, n, c;

5540:     DMConvert(dm, DMPLEX, &plex);
5541:     DMPlexGetDepth(plex, &depth);
5542:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5543:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5544:     for (l = 0; l < Nl; ++l) {
5545:       DMLabel label = labelSet[l];
5546:       IS      pointIS;

5548:       ISDestroy(&defcellIS);
5549:       DMLabelGetStratumIS(label, 1, &pointIS);
5550:       ISDifference(allcellIS, pointIS, &defcellIS);
5551:       ISDestroy(&pointIS);
5552:     }
5553:     ISDestroy(&allcellIS);

5555:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5556:     ISGetLocalSize(defcellIS, &n);
5557:     ISGetIndices(defcellIS, &cells);
5558:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5559:     ISRestoreIndices(defcellIS, &cells);
5560:     ISDestroy(&defcellIS);
5561:     DMPlexLabelComplete(plex, cellLabel);

5563:     PetscMalloc1(Ndef, &fields);
5564:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5565:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5566:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5567:     ISSetType(fieldIS, ISGENERAL);
5568:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5570:     PetscDSCreate(comm, &dsDef);
5571:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5572:     DMLabelDestroy(&cellLabel);
5573:     PetscDSSetCoordinateDimension(dsDef, dE);
5574:     PetscDSDestroy(&dsDef);
5575:     ISDestroy(&fieldIS);
5576:     DMDestroy(&plex);
5577:   }
5578:   /* Create label DSes
5579:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5580:   */
5581:   /* TODO Should check that labels are disjoint */
5582:   for (l = 0; l < Nl; ++l) {
5583:     DMLabel   label = labelSet[l];
5584:     PetscDS   ds;
5585:     IS        fields;
5586:     PetscInt *fld, nf;

5588:     PetscDSCreate(comm, &ds);
5589:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5590:     PetscMalloc1(nf, &fld);
5591:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5592:     ISCreate(PETSC_COMM_SELF, &fields);
5593:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5594:     ISSetType(fields, ISGENERAL);
5595:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5596:     DMSetRegionDS(dm, label, fields, ds);
5597:     ISDestroy(&fields);
5598:     PetscDSSetCoordinateDimension(ds, dE);
5599:     {
5600:       DMPolytopeType ct;
5601:       PetscInt       lStart, lEnd;
5602:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5604:       DMLabelGetBounds(label, &lStart, &lEnd);
5605:       if (lStart >= 0) {
5606:         DMPlexGetCellType(dm, lStart, &ct);
5607:         switch (ct) {
5608:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5609:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5610:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5611:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5612:             isHybridLocal = PETSC_TRUE;break;
5613:           default: break;
5614:         }
5615:       }
5616:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5617:       PetscDSSetHybrid(ds, isHybrid);
5618:     }
5619:     PetscDSDestroy(&ds);
5620:   }
5621:   PetscFree(labelSet);
5622:   /* Set fields in DSes */
5623:   for (s = 0; s < dm->Nds; ++s) {
5624:     PetscDS         ds     = dm->probs[s].ds;
5625:     IS              fields = dm->probs[s].fields;
5626:     const PetscInt *fld;
5627:     PetscInt        nf;

5629:     ISGetLocalSize(fields, &nf);
5630:     ISGetIndices(fields, &fld);
5631:     for (f = 0; f < nf; ++f) {
5632:       PetscObject  disc  = dm->fields[fld[f]].disc;
5633:       PetscBool    isHybrid;
5634:       PetscClassId id;

5636:       PetscDSGetHybrid(ds, &isHybrid);
5637:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5638:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5639:       PetscDSSetDiscretization(ds, f, disc);
5640:       /* We allow people to have placeholder fields and construct the Section by hand */
5641:       PetscObjectGetClassId(disc, &id);
5642:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5643:     }
5644:     ISRestoreIndices(fields, &fld);
5645:   }
5646:   /* Allow k-jet tabulation */
5647:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5648:   if (flg) {
5649:     for (s = 0; s < dm->Nds; ++s) {
5650:       PetscDS  ds = dm->probs[s].ds;
5651:       PetscInt Nf, f;

5653:       PetscDSGetNumFields(ds, &Nf);
5654:       for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
5655:     }
5656:   }
5657:   /* Setup DSes */
5658:   if (doSetup) {
5659:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5660:   }
5661:   return(0);
5662: }

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

5667:   Collective on DM

5669:   Input Parameters:
5670: + dm   - The DM
5671: - time - The time

5673:   Output Parameters:
5674: + u    - The vector will be filled with exact solution values, or NULL
5675: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

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

5679:   Level: developer

5681: .seealso: PetscDSSetExactSolution()
5682: @*/
5683: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5684: {
5685:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5686:   void            **ectxs;
5687:   PetscInt          Nf, Nds, s;
5688:   PetscErrorCode    ierr;

5694:   DMGetNumFields(dm, &Nf);
5695:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5696:   DMGetNumDS(dm, &Nds);
5697:   for (s = 0; s < Nds; ++s) {
5698:     PetscDS         ds;
5699:     DMLabel         label;
5700:     IS              fieldIS;
5701:     const PetscInt *fields, id = 1;
5702:     PetscInt        dsNf, f;

5704:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5705:     PetscDSGetNumFields(ds, &dsNf);
5706:     ISGetIndices(fieldIS, &fields);
5707:     PetscArrayzero(exacts, Nf);
5708:     PetscArrayzero(ectxs, Nf);
5709:     if (u) {
5710:       for (f = 0; f < dsNf; ++f) {
5711:         const PetscInt field = fields[f];
5712:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5713:       }
5714:       ISRestoreIndices(fieldIS, &fields);
5715:       if (label) {
5716:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5717:       } else {
5718:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5719:       }
5720:     }
5721:     if (u_t) {
5722:       PetscArrayzero(exacts, Nf);
5723:       PetscArrayzero(ectxs, Nf);
5724:       for (f = 0; f < dsNf; ++f) {
5725:         const PetscInt field = fields[f];
5726:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5727:       }
5728:       ISRestoreIndices(fieldIS, &fields);
5729:       if (label) {
5730:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5731:       } else {
5732:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5733:       }
5734:     }
5735:   }
5736:   if (u) {
5737:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5738:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5739:   }
5740:   if (u_t) {
5741:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5742:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5743:   }
5744:   PetscFree2(exacts, ectxs);
5745:   return(0);
5746: }

5748: /*@
5749:   DMCopyDS - Copy the discrete systems for the DM into another DM

5751:   Collective on dm

5753:   Input Parameter:
5754: . dm - The DM

5756:   Output Parameter:
5757: . newdm - The DM

5759:   Level: advanced

5761: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5762: @*/
5763: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5764: {
5765:   PetscInt       Nds, s;

5769:   if (dm == newdm) return(0);
5770:   DMGetNumDS(dm, &Nds);
5771:   DMClearDS(newdm);
5772:   for (s = 0; s < Nds; ++s) {
5773:     DMLabel  label;
5774:     IS       fields;
5775:     PetscDS  ds;
5776:     PetscInt Nbd, bd;

5778:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5779:     DMSetRegionDS(newdm, label, fields, ds);
5780:     PetscDSGetNumBoundary(ds, &Nbd);
5781:     for (bd = 0; bd < Nbd; ++bd) {
5782:       const char *labelname, *name;
5783:       PetscInt    field;

5785:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5786:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5787:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5788:     }
5789:   }
5790:   return(0);
5791: }

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

5796:   Collective on dm

5798:   Input Parameter:
5799: . dm - The DM

5801:   Output Parameter:
5802: . newdm - The DM

5804:   Level: advanced

5806: .seealso: DMCopyFields(), DMCopyDS()
5807: @*/
5808: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5809: {

5813:   DMCopyFields(dm, newdm);
5814:   DMCopyDS(dm, newdm);
5815:   return(0);
5816: }

5818: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5819: {
5820:   DM dm_coord,dmc_coord;
5822:   Vec coords,ccoords;
5823:   Mat inject;
5825:   DMGetCoordinateDM(dm,&dm_coord);
5826:   DMGetCoordinateDM(dmc,&dmc_coord);
5827:   DMGetCoordinates(dm,&coords);
5828:   DMGetCoordinates(dmc,&ccoords);
5829:   if (coords && !ccoords) {
5830:     DMCreateGlobalVector(dmc_coord,&ccoords);
5831:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5832:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5833:     MatRestrict(inject,coords,ccoords);
5834:     MatDestroy(&inject);
5835:     DMSetCoordinates(dmc,ccoords);
5836:     VecDestroy(&ccoords);
5837:   }
5838:   return(0);
5839: }

5841: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5842: {
5843:   DM dm_coord,subdm_coord;
5845:   Vec coords,ccoords,clcoords;
5846:   VecScatter *scat_i,*scat_g;
5848:   DMGetCoordinateDM(dm,&dm_coord);
5849:   DMGetCoordinateDM(subdm,&subdm_coord);
5850:   DMGetCoordinates(dm,&coords);
5851:   DMGetCoordinates(subdm,&ccoords);
5852:   if (coords && !ccoords) {
5853:     DMCreateGlobalVector(subdm_coord,&ccoords);
5854:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5855:     DMCreateLocalVector(subdm_coord,&clcoords);
5856:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5857:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5858:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5859:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5860:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5861:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5862:     DMSetCoordinates(subdm,ccoords);
5863:     DMSetCoordinatesLocal(subdm,clcoords);
5864:     VecScatterDestroy(&scat_i[0]);
5865:     VecScatterDestroy(&scat_g[0]);
5866:     VecDestroy(&ccoords);
5867:     VecDestroy(&clcoords);
5868:     PetscFree(scat_i);
5869:     PetscFree(scat_g);
5870:   }
5871:   return(0);
5872: }

5874: /*@
5875:   DMGetDimension - Return the topological dimension of the DM

5877:   Not collective

5879:   Input Parameter:
5880: . dm - The DM

5882:   Output Parameter:
5883: . dim - The topological dimension

5885:   Level: beginner

5887: .seealso: DMSetDimension(), DMCreate()
5888: @*/
5889: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5890: {
5894:   *dim = dm->dim;
5895:   return(0);
5896: }

5898: /*@
5899:   DMSetDimension - Set the topological dimension of the DM

5901:   Collective on dm

5903:   Input Parameters:
5904: + dm - The DM
5905: - dim - The topological dimension

5907:   Level: beginner

5909: .seealso: DMGetDimension(), DMCreate()
5910: @*/
5911: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5912: {
5913:   PetscDS        ds;

5919:   dm->dim = dim;
5920:   DMGetDS(dm, &ds);
5921:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5922:   return(0);
5923: }

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

5928:   Collective on dm

5930:   Input Parameters:
5931: + dm - the DM
5932: - dim - the dimension

5934:   Output Parameters:
5935: + pStart - The first point of the given dimension
5936: - pEnd - The first point following points of the given dimension

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

5943:   Level: intermediate

5945: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5946: @*/
5947: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5948: {
5949:   PetscInt       d;

5954:   DMGetDimension(dm, &d);
5955:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5956:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5957:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5958:   return(0);
5959: }

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

5964:   Collective on dm

5966:   Input Parameters:
5967: + dm - the DM
5968: - c - coordinate vector

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

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

5975:   Level: intermediate

5977: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
5978: @*/
5979: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5980: {

5986:   PetscObjectReference((PetscObject) c);
5987:   VecDestroy(&dm->coordinates);
5988:   dm->coordinates = c;
5989:   VecDestroy(&dm->coordinatesLocal);
5990:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5991:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5992:   return(0);
5993: }

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

5998:   Not collective

6000:    Input Parameters:
6001: +  dm - the DM
6002: -  c - coordinate vector

6004:   Notes:
6005:   The coordinates of ghost points can be set using DMSetCoordinates()
6006:   followed by DMGetCoordinatesLocal(). This is intended to enable the
6007:   setting of ghost coordinates outside of the domain.

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

6011:   Level: intermediate

6013: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6014: @*/
6015: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6016: {

6022:   PetscObjectReference((PetscObject) c);
6023:   VecDestroy(&dm->coordinatesLocal);

6025:   dm->coordinatesLocal = c;

6027:   VecDestroy(&dm->coordinates);
6028:   return(0);
6029: }

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

6034:   Collective on dm

6036:   Input Parameter:
6037: . dm - the DM

6039:   Output Parameter:
6040: . c - global coordinate vector

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

6046:   Each process has only the local coordinates (does NOT have the ghost coordinates).

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

6051:   Level: intermediate

6053: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6054: @*/
6055: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6056: {

6062:   if (!dm->coordinates && dm->coordinatesLocal) {
6063:     DM        cdm = NULL;
6064:     PetscBool localized;

6066:     DMGetCoordinateDM(dm, &cdm);
6067:     DMCreateGlobalVector(cdm, &dm->coordinates);
6068:     DMGetCoordinatesLocalized(dm, &localized);
6069:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6070:     if (localized) {
6071:       PetscInt cdim;

6073:       DMGetCoordinateDim(dm, &cdim);
6074:       VecSetBlockSize(dm->coordinates, cdim);
6075:     }
6076:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6077:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6078:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6079:   }
6080:   *c = dm->coordinates;
6081:   return(0);
6082: }

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

6087:   Collective on dm

6089:   Input Parameter:
6090: . dm - the DM

6092:   Level: advanced

6094: .seealso: DMGetCoordinatesLocalNoncollective()
6095: @*/
6096: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6097: {

6102:   if (!dm->coordinatesLocal && dm->coordinates) {
6103:     DM        cdm = NULL;
6104:     PetscBool localized;

6106:     DMGetCoordinateDM(dm, &cdm);
6107:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6108:     DMGetCoordinatesLocalized(dm, &localized);
6109:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6110:     if (localized) {
6111:       PetscInt cdim;

6113:       DMGetCoordinateDim(dm, &cdim);
6114:       VecSetBlockSize(dm->coordinates, cdim);
6115:     }
6116:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6117:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6118:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6119:   }
6120:   return(0);
6121: }

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

6126:   Collective on dm

6128:   Input Parameter:
6129: . dm - the DM

6131:   Output Parameter:
6132: . c - coordinate vector

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

6137:   Each process has the local and ghost coordinates

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

6142:   Level: intermediate

6144: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6145: @*/
6146: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6147: {

6153:   DMGetCoordinatesLocalSetUp(dm);
6154:   *c = dm->coordinatesLocal;
6155:   return(0);
6156: }

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

6161:   Not collective

6163:   Input Parameter:
6164: . dm - the DM

6166:   Output Parameter:
6167: . c - coordinate vector

6169:   Level: advanced

6171: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6172: @*/
6173: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6174: {
6178:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6179:   *c = dm->coordinatesLocal;
6180:   return(0);
6181: }

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

6186:   Not collective

6188:   Input Parameter:
6189: + dm - the DM
6190: - p - the IS of points whose coordinates will be returned

6192:   Output Parameter:
6193: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6194: - pCoord - the Vec with coordinates of points in p

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

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

6201:   Each process has the local and ghost coordinates

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

6206:   Level: advanced

6208: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6209: @*/
6210: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6211: {
6212:   PetscSection        cs, newcs;
6213:   Vec                 coords;
6214:   const PetscScalar   *arr;
6215:   PetscScalar         *newarr=NULL;
6216:   PetscInt            n;
6217:   PetscErrorCode      ierr;

6224:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6225:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6226:   cs = dm->coordinateDM->localSection;
6227:   coords = dm->coordinatesLocal;
6228:   VecGetArrayRead(coords, &arr);
6229:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6230:   VecRestoreArrayRead(coords, &arr);
6231:   if (pCoord) {
6232:     PetscSectionGetStorageSize(newcs, &n);
6233:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6234:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6235:     VecReplaceArray(*pCoord, newarr);
6236:   } else {
6237:     PetscFree(newarr);
6238:   }
6239:   if (pCoordSection) {*pCoordSection = newcs;}
6240:   else               {PetscSectionDestroy(&newcs);}
6241:   return(0);
6242: }

6244: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6245: {

6251:   if (!dm->coordinateField) {
6252:     if (dm->ops->createcoordinatefield) {
6253:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6254:     }
6255:   }
6256:   *field = dm->coordinateField;
6257:   return(0);
6258: }

6260: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6261: {

6267:   PetscObjectReference((PetscObject)field);
6268:   DMFieldDestroy(&dm->coordinateField);
6269:   dm->coordinateField = field;
6270:   return(0);
6271: }

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

6276:   Collective on dm

6278:   Input Parameter:
6279: . dm - the DM

6281:   Output Parameter:
6282: . cdm - coordinate DM

6284:   Level: intermediate

6286: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6287: @*/
6288: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6289: {

6295:   if (!dm->coordinateDM) {
6296:     DM cdm;

6298:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6299:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6300:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6301:      * until the call to CreateCoordinateDM) */
6302:     DMDestroy(&dm->coordinateDM);
6303:     dm->coordinateDM = cdm;
6304:   }
6305:   *cdm = dm->coordinateDM;
6306:   return(0);
6307: }

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

6312:   Logically Collective on dm

6314:   Input Parameters:
6315: + dm - the DM
6316: - cdm - coordinate DM

6318:   Level: intermediate

6320: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6321: @*/
6322: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6323: {

6329:   PetscObjectReference((PetscObject)cdm);
6330:   DMDestroy(&dm->coordinateDM);
6331:   dm->coordinateDM = cdm;
6332:   return(0);
6333: }

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

6338:   Not Collective

6340:   Input Parameter:
6341: . dm - The DM object

6343:   Output Parameter:
6344: . dim - The embedding dimension

6346:   Level: intermediate

6348: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6349: @*/
6350: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6351: {
6355:   if (dm->dimEmbed == PETSC_DEFAULT) {
6356:     dm->dimEmbed = dm->dim;
6357:   }
6358:   *dim = dm->dimEmbed;
6359:   return(0);
6360: }

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

6365:   Not Collective

6367:   Input Parameters:
6368: + dm  - The DM object
6369: - dim - The embedding dimension

6371:   Level: intermediate

6373: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6374: @*/
6375: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6376: {
6377:   PetscDS        ds;

6382:   dm->dimEmbed = dim;
6383:   DMGetDS(dm, &ds);
6384:   PetscDSSetCoordinateDimension(ds, dim);
6385:   return(0);
6386: }

6388: /*@
6389:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6391:   Collective on dm

6393:   Input Parameter:
6394: . dm - The DM object

6396:   Output Parameter:
6397: . section - The PetscSection object

6399:   Level: intermediate

6401: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6402: @*/
6403: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6404: {
6405:   DM             cdm;

6411:   DMGetCoordinateDM(dm, &cdm);
6412:   DMGetLocalSection(cdm, section);
6413:   return(0);
6414: }

6416: /*@
6417:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6419:   Not Collective

6421:   Input Parameters:
6422: + dm      - The DM object
6423: . dim     - The embedding dimension, or PETSC_DETERMINE
6424: - section - The PetscSection object

6426:   Level: intermediate

6428: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6429: @*/
6430: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6431: {
6432:   DM             cdm;

6438:   DMGetCoordinateDM(dm, &cdm);
6439:   DMSetLocalSection(cdm, section);
6440:   if (dim == PETSC_DETERMINE) {
6441:     PetscInt d = PETSC_DEFAULT;
6442:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6444:     PetscSectionGetChart(section, &pStart, &pEnd);
6445:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6446:     pStart = PetscMax(vStart, pStart);
6447:     pEnd   = PetscMin(vEnd, pEnd);
6448:     for (v = pStart; v < pEnd; ++v) {
6449:       PetscSectionGetDof(section, v, &dd);
6450:       if (dd) {d = dd; break;}
6451:     }
6452:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6453:   }
6454:   return(0);
6455: }

6457: /*@
6458:   DMProjectCoordinates - Project coordinates to a different space

6460:   Input Parameters:
6461: + dm      - The DM object
6462: - disc    - The new coordinate discretization

6464:   Level: intermediate

6466: .seealso: DMGetCoordinateField()
6467: @*/
6468: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6469: {
6470:   PetscObject    discOld;
6471:   PetscClassId   classid;
6472:   DM             cdmOld,cdmNew;
6473:   Vec            coordsOld,coordsNew;
6474:   Mat            matInterp;


6481:   DMGetCoordinateDM(dm, &cdmOld);
6482:   /* Check current discretization is compatible */
6483:   DMGetField(cdmOld, 0, NULL, &discOld);
6484:   PetscObjectGetClassId(discOld, &classid);
6485:   if (classid != PETSCFE_CLASSID) {
6486:     if (classid == PETSC_CONTAINER_CLASSID) {
6487:       PetscFE        feLinear;
6488:       DMPolytopeType ct;
6489:       PetscInt       dim, dE, cStart;
6490:       PetscBool      simplex;

6492:       /* Assume linear vertex coordinates */
6493:       DMGetDimension(dm, &dim);
6494:       DMGetCoordinateDim(dm, &dE);
6495:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6496:       DMPlexGetCellType(dm, cStart, &ct);
6497:       switch (ct) {
6498:         case DM_POLYTOPE_TRI_PRISM:
6499:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6500:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6501:         default: break;
6502:       }
6503:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6504:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6505:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6506:       PetscFEDestroy(&feLinear);
6507:       DMCreateDS(cdmOld);
6508:     } else {
6509:       const char *discname;

6511:       PetscObjectGetType(discOld, &discname);
6512:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6513:     }
6514:   }
6515:   /* Make a fresh clone of the coordinate DM */
6516:   DMClone(cdmOld, &cdmNew);
6517:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6518:   DMCreateDS(cdmNew);
6519:   /* Project the coordinate vector from old to new space  */
6520:   DMGetCoordinates(dm, &coordsOld);
6521:   DMCreateGlobalVector(cdmNew, &coordsNew);
6522:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6523:   MatInterpolate(matInterp, coordsOld, coordsNew);
6524:   MatDestroy(&matInterp);
6525:   /* Set new coordinate structures */
6526:   DMSetCoordinateField(dm, NULL);
6527:   DMSetCoordinateDM(dm, cdmNew);
6528:   DMSetCoordinates(dm, coordsNew);
6529:   VecDestroy(&coordsNew);
6530:   DMDestroy(&cdmNew);
6531:   return(0);
6532: }

6534: /*@C
6535:   DMGetPeriodicity - Get the description of mesh periodicity

6537:   Input Parameters:
6538: . dm      - The DM object

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

6546:   Level: developer

6548: .seealso: DMGetPeriodicity()
6549: @*/
6550: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6551: {
6554:   if (per)     *per     = dm->periodic;
6555:   if (L)       *L       = dm->L;
6556:   if (maxCell) *maxCell = dm->maxCell;
6557:   if (bd)      *bd      = dm->bdtype;
6558:   return(0);
6559: }

6561: /*@C
6562:   DMSetPeriodicity - Set the description of mesh periodicity

6564:   Input Parameters:
6565: + dm      - The DM object
6566: . per     - Whether the DM is periodic or not.
6567: . 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.
6568: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6569: - bd      - This describes the type of periodicity in each topological dimension

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

6573:   Level: developer

6575: .seealso: DMGetPeriodicity()
6576: @*/
6577: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6578: {
6579:   PetscInt       dim, d;

6588:   DMGetDimension(dm, &dim);
6589:   if (maxCell) {
6590:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6591:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6592:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6593:     PetscFree(dm->maxCell);
6594:   }

6596:   if (L) {
6597:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6598:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6599:   }
6600:   if (bd) {
6601:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6602:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6603:   }
6604:   dm->periodic = per;
6605:   return(0);
6606: }

6608: /*@
6609:   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.

6611:   Input Parameters:
6612: + dm     - The DM
6613: . in     - The input coordinate point (dim numbers)
6614: - endpoint - Include the endpoint L_i

6616:   Output Parameter:
6617: . out - The localized coordinate point

6619:   Level: developer

6621: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6622: @*/
6623: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6624: {
6625:   PetscInt       dim, d;

6629:   DMGetCoordinateDim(dm, &dim);
6630:   if (!dm->maxCell) {
6631:     for (d = 0; d < dim; ++d) out[d] = in[d];
6632:   } else {
6633:     if (endpoint) {
6634:       for (d = 0; d < dim; ++d) {
6635:         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)) {
6636:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6637:         } else {
6638:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6639:         }
6640:       }
6641:     } else {
6642:       for (d = 0; d < dim; ++d) {
6643:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6644:       }
6645:     }
6646:   }
6647:   return(0);
6648: }

6650: /*
6651:   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.

6653:   Input Parameters:
6654: + dm     - The DM
6655: . dim    - The spatial dimension
6656: . anchor - The anchor point, the input point can be no more than maxCell away from it
6657: - in     - The input coordinate point (dim numbers)

6659:   Output Parameter:
6660: . out - The localized coordinate point

6662:   Level: developer

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

6666: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6667: */
6668: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6669: {
6670:   PetscInt d;

6673:   if (!dm->maxCell) {
6674:     for (d = 0; d < dim; ++d) out[d] = in[d];
6675:   } else {
6676:     for (d = 0; d < dim; ++d) {
6677:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6678:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6679:       } else {
6680:         out[d] = in[d];
6681:       }
6682:     }
6683:   }
6684:   return(0);
6685: }

6687: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6688: {
6689:   PetscInt d;

6692:   if (!dm->maxCell) {
6693:     for (d = 0; d < dim; ++d) out[d] = in[d];
6694:   } else {
6695:     for (d = 0; d < dim; ++d) {
6696:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6697:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6698:       } else {
6699:         out[d] = in[d];
6700:       }
6701:     }
6702:   }
6703:   return(0);
6704: }

6706: /*
6707:   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.

6709:   Input Parameters:
6710: + dm     - The DM
6711: . dim    - The spatial dimension
6712: . anchor - The anchor point, the input point can be no more than maxCell away from it
6713: . in     - The input coordinate delta (dim numbers)
6714: - out    - The input coordinate point (dim numbers)

6716:   Output Parameter:
6717: . out    - The localized coordinate in + out

6719:   Level: developer

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

6723: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6724: */
6725: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6726: {
6727:   PetscInt d;

6730:   if (!dm->maxCell) {
6731:     for (d = 0; d < dim; ++d) out[d] += in[d];
6732:   } else {
6733:     for (d = 0; d < dim; ++d) {
6734:       const PetscReal maxC = dm->maxCell[d];

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

6739:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6740:           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]));
6741:         out[d] += newCoord;
6742:       } else {
6743:         out[d] += in[d];
6744:       }
6745:     }
6746:   }
6747:   return(0);
6748: }

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

6753:   Not collective

6755:   Input Parameter:
6756: . dm - The DM

6758:   Output Parameter:
6759:   areLocalized - True if localized

6761:   Level: developer

6763: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6764: @*/
6765: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6766: {
6767:   DM             cdm;
6768:   PetscSection   coordSection;
6769:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6770:   PetscBool      isPlex, alreadyLocalized;

6776:   *areLocalized = PETSC_FALSE;

6778:   /* We need some generic way of refering to cells/vertices */
6779:   DMGetCoordinateDM(dm, &cdm);
6780:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6781:   if (!isPlex) return(0);

6783:   DMGetCoordinateSection(dm, &coordSection);
6784:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6785:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6786:   alreadyLocalized = PETSC_FALSE;
6787:   for (c = cStart; c < cEnd; ++c) {
6788:     if (c < sStart || c >= sEnd) continue;
6789:     PetscSectionGetDof(coordSection, c, &dof);
6790:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6791:   }
6792:   *areLocalized = alreadyLocalized;
6793:   return(0);
6794: }

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

6799:   Collective on dm

6801:   Input Parameter:
6802: . dm - The DM

6804:   Output Parameter:
6805:   areLocalized - True if localized

6807:   Level: developer

6809: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6810: @*/
6811: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6812: {
6813:   PetscBool      localized;

6819:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6820:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6821:   return(0);
6822: }

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

6827:   Collective on dm

6829:   Input Parameter:
6830: . dm - The DM

6832:   Level: developer

6834: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6835: @*/
6836: PetscErrorCode DMLocalizeCoordinates(DM dm)
6837: {
6838:   DM             cdm;
6839:   PetscSection   coordSection, cSection;
6840:   Vec            coordinates,  cVec;
6841:   PetscScalar   *coords, *coords2, *anchor, *localized;
6842:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6843:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6844:   PetscInt       maxHeight = 0, h;
6845:   PetscInt       *pStart = NULL, *pEnd = NULL;

6850:   if (!dm->periodic) return(0);
6851:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6852:   if (alreadyLocalized) return(0);

6854:   /* We need some generic way of refering to cells/vertices */
6855:   DMGetCoordinateDM(dm, &cdm);
6856:   {
6857:     PetscBool isplex;

6859:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6860:     if (isplex) {
6861:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6862:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6863:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6864:       pEnd = &pStart[maxHeight + 1];
6865:       newStart = vStart;
6866:       newEnd   = vEnd;
6867:       for (h = 0; h <= maxHeight; h++) {
6868:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6869:         newStart = PetscMin(newStart,pStart[h]);
6870:         newEnd   = PetscMax(newEnd,pEnd[h]);
6871:       }
6872:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6873:   }
6874:   DMGetCoordinatesLocal(dm, &coordinates);
6875:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6876:   DMGetCoordinateSection(dm, &coordSection);
6877:   VecGetBlockSize(coordinates, &bs);
6878:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6880:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6881:   PetscSectionSetNumFields(cSection, 1);
6882:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6883:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6884:   PetscSectionSetChart(cSection, newStart, newEnd);

6886:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6887:   localized = &anchor[bs];
6888:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6889:   for (h = 0; h <= maxHeight; h++) {
6890:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6892:     for (c = cStart; c < cEnd; ++c) {
6893:       PetscScalar *cellCoords = NULL;
6894:       PetscInt     b;

6896:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6897:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6898:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6899:       for (d = 0; d < dof/bs; ++d) {
6900:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6901:         for (b = 0; b < bs; b++) {
6902:           if (cellCoords[d*bs + b] != localized[b]) break;
6903:         }
6904:         if (b < bs) break;
6905:       }
6906:       if (d < dof/bs) {
6907:         if (c >= sStart && c < sEnd) {
6908:           PetscInt cdof;

6910:           PetscSectionGetDof(coordSection, c, &cdof);
6911:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6912:         }
6913:         PetscSectionSetDof(cSection, c, dof);
6914:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6915:       }
6916:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6917:     }
6918:   }
6919:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6920:   if (alreadyLocalizedGlobal) {
6921:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6922:     PetscSectionDestroy(&cSection);
6923:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6924:     return(0);
6925:   }
6926:   for (v = vStart; v < vEnd; ++v) {
6927:     PetscSectionGetDof(coordSection, v, &dof);
6928:     PetscSectionSetDof(cSection, v, dof);
6929:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6930:   }
6931:   PetscSectionSetUp(cSection);
6932:   PetscSectionGetStorageSize(cSection, &coordSize);
6933:   VecCreate(PETSC_COMM_SELF, &cVec);
6934:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6935:   VecSetBlockSize(cVec, bs);
6936:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6937:   VecSetType(cVec, VECSTANDARD);
6938:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6939:   VecGetArray(cVec, &coords2);
6940:   for (v = vStart; v < vEnd; ++v) {
6941:     PetscSectionGetDof(coordSection, v, &dof);
6942:     PetscSectionGetOffset(coordSection, v, &off);
6943:     PetscSectionGetOffset(cSection,     v, &off2);
6944:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6945:   }
6946:   for (h = 0; h <= maxHeight; h++) {
6947:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6949:     for (c = cStart; c < cEnd; ++c) {
6950:       PetscScalar *cellCoords = NULL;
6951:       PetscInt     b, cdof;

6953:       PetscSectionGetDof(cSection,c,&cdof);
6954:       if (!cdof) continue;
6955:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6956:       PetscSectionGetOffset(cSection, c, &off2);
6957:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6958:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6959:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6960:     }
6961:   }
6962:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6963:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6964:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6965:   VecRestoreArray(cVec, &coords2);
6966:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6967:   DMSetCoordinatesLocal(dm, cVec);
6968:   VecDestroy(&cVec);
6969:   PetscSectionDestroy(&cSection);
6970:   return(0);
6971: }

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

6976:   Collective on v (see explanation below)

6978:   Input Parameters:
6979: + dm - The DM
6980: . v - The Vec of points
6981: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6982: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6984:   Output Parameter:
6985: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6986: - cells - The PetscSF containing the ranks and local indices of the containing points.


6989:   Level: developer

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

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

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

7000: $    const PetscSFNode *cells;
7001: $    PetscInt           nFound;
7002: $    const PetscInt    *found;
7003: $
7004: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

7009: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7010: @*/
7011: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7012: {

7019:   if (*cellSF) {
7020:     PetscMPIInt result;

7023:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7024:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7025:   } else {
7026:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7027:   }
7028:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7029:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7030:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7031:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7032:   return(0);
7033: }

7035: /*@
7036:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7038:   Collective on dm

7040:   Input Parameter:
7041: . dm - The original DM

7043:   Output Parameter:
7044: . odm - The DM which provides the layout for output

7046:   Level: intermediate

7048: .seealso: VecView(), DMGetGlobalSection()
7049: @*/
7050: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7051: {
7052:   PetscSection   section;
7053:   PetscBool      hasConstraints, ghasConstraints;

7059:   DMGetLocalSection(dm, &section);
7060:   PetscSectionHasConstraints(section, &hasConstraints);
7061:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7062:   if (!ghasConstraints) {
7063:     *odm = dm;
7064:     return(0);
7065:   }
7066:   if (!dm->dmBC) {
7067:     PetscSection newSection, gsection;
7068:     PetscSF      sf;

7070:     DMClone(dm, &dm->dmBC);
7071:     DMCopyDisc(dm, dm->dmBC);
7072:     PetscSectionClone(section, &newSection);
7073:     DMSetLocalSection(dm->dmBC, newSection);
7074:     PetscSectionDestroy(&newSection);
7075:     DMGetPointSF(dm->dmBC, &sf);
7076:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7077:     DMSetGlobalSection(dm->dmBC, gsection);
7078:     PetscSectionDestroy(&gsection);
7079:   }
7080:   *odm = dm->dmBC;
7081:   return(0);
7082: }

7084: /*@
7085:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7087:   Input Parameter:
7088: . dm - The original DM

7090:   Output Parameters:
7091: + num - The output sequence number
7092: - val - The output sequence value

7094:   Level: intermediate

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

7099: .seealso: VecView()
7100: @*/
7101: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7102: {
7107:   return(0);
7108: }

7110: /*@
7111:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7113:   Input Parameters:
7114: + dm - The original DM
7115: . num - The output sequence number
7116: - val - The output sequence value

7118:   Level: intermediate

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

7123: .seealso: VecView()
7124: @*/
7125: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7126: {
7129:   dm->outputSequenceNum = num;
7130:   dm->outputSequenceVal = val;
7131:   return(0);
7132: }

7134: /*@C
7135:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7137:   Input Parameters:
7138: + dm   - The original DM
7139: . name - The sequence name
7140: - num  - The output sequence number

7142:   Output Parameter:
7143: . val  - The output sequence value

7145:   Level: intermediate

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

7150: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7151: @*/
7152: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7153: {
7154:   PetscBool      ishdf5;

7161:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7162:   if (ishdf5) {
7163: #if defined(PETSC_HAVE_HDF5)
7164:     PetscScalar value;

7166:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7167:     *val = PetscRealPart(value);
7168: #endif
7169:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7170:   return(0);
7171: }

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

7176:   Not collective

7178:   Input Parameter:
7179: . dm - The DM

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

7184:   Level: beginner

7186: .seealso: DMSetUseNatural(), DMCreate()
7187: @*/
7188: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7189: {
7193:   *useNatural = dm->useNatural;
7194:   return(0);
7195: }

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

7200:   Collective on dm

7202:   Input Parameters:
7203: + dm - The DM
7204: - useNatural - The flag to build the mapping to a natural order during distribution

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

7208:   Level: beginner

7210: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7211: @*/
7212: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7213: {
7217:   dm->useNatural = useNatural;
7218:   return(0);
7219: }


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

7225:   Not Collective

7227:   Input Parameters:
7228: + dm   - The DM object
7229: - name - The label name

7231:   Level: intermediate

7233: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7234: @*/
7235: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7236: {
7237:   PetscBool      flg;
7238:   DMLabel        label;

7244:   DMHasLabel(dm, name, &flg);
7245:   if (!flg) {
7246:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7247:     DMAddLabel(dm, label);
7248:     DMLabelDestroy(&label);
7249:   }
7250:   return(0);
7251: }

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

7256:   Not Collective

7258:   Input Parameters:
7259: + dm   - The DM object
7260: . l    - The index for the label
7261: - name - The label name

7263:   Level: intermediate

7265: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7266: @*/
7267: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7268: {
7269:   DMLabelLink    orig, prev = NULL;
7270:   DMLabel        label;
7271:   PetscInt       Nl, m;
7272:   PetscBool      flg, match;
7273:   const char    *lname;

7279:   DMHasLabel(dm, name, &flg);
7280:   if (!flg) {
7281:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7282:     DMAddLabel(dm, label);
7283:     DMLabelDestroy(&label);
7284:   }
7285:   DMGetNumLabels(dm, &Nl);
7286:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7287:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7288:     PetscObjectGetName((PetscObject) orig->label, &lname);
7289:     PetscStrcmp(name, lname, &match);
7290:     if (match) break;
7291:   }
7292:   if (m == l) return(0);
7293:   if (!m) dm->labels = orig->next;
7294:   else    prev->next = orig->next;
7295:   if (!l) {
7296:     orig->next = dm->labels;
7297:     dm->labels = orig;
7298:   } else {
7299:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7300:     orig->next = prev->next;
7301:     prev->next = orig;
7302:   }
7303:   return(0);
7304: }

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

7309:   Not Collective

7311:   Input Parameters:
7312: + dm   - The DM object
7313: . name - The label name
7314: - point - The mesh point

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

7319:   Level: beginner

7321: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7322: @*/
7323: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7324: {
7325:   DMLabel        label;

7331:   DMGetLabel(dm, name, &label);
7332:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7333:   DMLabelGetValue(label, point, value);
7334:   return(0);
7335: }

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

7340:   Not Collective

7342:   Input Parameters:
7343: + dm   - The DM object
7344: . name - The label name
7345: . point - The mesh point
7346: - value - The label value for this point

7348:   Output Parameter:

7350:   Level: beginner

7352: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7353: @*/
7354: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7355: {
7356:   DMLabel        label;

7362:   DMGetLabel(dm, name, &label);
7363:   if (!label) {
7364:     DMCreateLabel(dm, name);
7365:     DMGetLabel(dm, name, &label);
7366:   }
7367:   DMLabelSetValue(label, point, value);
7368:   return(0);
7369: }

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

7374:   Not Collective

7376:   Input Parameters:
7377: + dm   - The DM object
7378: . name - The label name
7379: . point - The mesh point
7380: - value - The label value for this point

7382:   Output Parameter:

7384:   Level: beginner

7386: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7387: @*/
7388: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7389: {
7390:   DMLabel        label;

7396:   DMGetLabel(dm, name, &label);
7397:   if (!label) return(0);
7398:   DMLabelClearValue(label, point, value);
7399:   return(0);
7400: }

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

7405:   Not Collective

7407:   Input Parameters:
7408: + dm   - The DM object
7409: - name - The label name

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

7414:   Level: beginner

7416: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7417: @*/
7418: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7419: {
7420:   DMLabel        label;

7427:   DMGetLabel(dm, name, &label);
7428:   *size = 0;
7429:   if (!label) return(0);
7430:   DMLabelGetNumValues(label, size);
7431:   return(0);
7432: }

7434: /*@C
7435:   DMGetLabelIdIS - Get the integer ids in a label

7437:   Not Collective

7439:   Input Parameters:
7440: + mesh - The DM object
7441: - name - The label name

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

7446:   Level: beginner

7448: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7449: @*/
7450: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7451: {
7452:   DMLabel        label;

7459:   DMGetLabel(dm, name, &label);
7460:   *ids = NULL;
7461:  if (label) {
7462:     DMLabelGetValueIS(label, ids);
7463:   } else {
7464:     /* returning an empty IS */
7465:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7466:   }
7467:   return(0);
7468: }

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

7473:   Not Collective

7475:   Input Parameters:
7476: + dm - The DM object
7477: . name - The label name
7478: - value - The stratum value

7480:   Output Parameter:
7481: . size - The stratum size

7483:   Level: beginner

7485: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7486: @*/
7487: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7488: {
7489:   DMLabel        label;

7496:   DMGetLabel(dm, name, &label);
7497:   *size = 0;
7498:   if (!label) return(0);
7499:   DMLabelGetStratumSize(label, value, size);
7500:   return(0);
7501: }

7503: /*@C
7504:   DMGetStratumIS - Get the points in a label stratum

7506:   Not Collective

7508:   Input Parameters:
7509: + dm - The DM object
7510: . name - The label name
7511: - value - The stratum value

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

7516:   Level: beginner

7518: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7519: @*/
7520: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7521: {
7522:   DMLabel        label;

7529:   DMGetLabel(dm, name, &label);
7530:   *points = NULL;
7531:   if (!label) return(0);
7532:   DMLabelGetStratumIS(label, value, points);
7533:   return(0);
7534: }

7536: /*@C
7537:   DMSetStratumIS - Set the points in a label stratum

7539:   Not Collective

7541:   Input Parameters:
7542: + dm - The DM object
7543: . name - The label name
7544: . value - The stratum value
7545: - points - The stratum points

7547:   Level: beginner

7549: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7550: @*/
7551: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7552: {
7553:   DMLabel        label;

7560:   DMGetLabel(dm, name, &label);
7561:   if (!label) return(0);
7562:   DMLabelSetStratumIS(label, value, points);
7563:   return(0);
7564: }

7566: /*@C
7567:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7569:   Not Collective

7571:   Input Parameters:
7572: + dm   - The DM object
7573: . name - The label name
7574: - value - The label value for this point

7576:   Output Parameter:

7578:   Level: beginner

7580: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7581: @*/
7582: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7583: {
7584:   DMLabel        label;

7590:   DMGetLabel(dm, name, &label);
7591:   if (!label) return(0);
7592:   DMLabelClearStratum(label, value);
7593:   return(0);
7594: }

7596: /*@
7597:   DMGetNumLabels - Return the number of labels defined by the mesh

7599:   Not Collective

7601:   Input Parameter:
7602: . dm   - The DM object

7604:   Output Parameter:
7605: . numLabels - the number of Labels

7607:   Level: intermediate

7609: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7610: @*/
7611: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7612: {
7613:   DMLabelLink next = dm->labels;
7614:   PetscInt  n    = 0;

7619:   while (next) {++n; next = next->next;}
7620:   *numLabels = n;
7621:   return(0);
7622: }

7624: /*@C
7625:   DMGetLabelName - Return the name of nth label

7627:   Not Collective

7629:   Input Parameters:
7630: + dm - The DM object
7631: - n  - the label number

7633:   Output Parameter:
7634: . name - the label name

7636:   Level: intermediate

7638: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7639: @*/
7640: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7641: {
7642:   DMLabelLink    next = dm->labels;
7643:   PetscInt       l    = 0;

7649:   while (next) {
7650:     if (l == n) {
7651:       PetscObjectGetName((PetscObject) next->label, name);
7652:       return(0);
7653:     }
7654:     ++l;
7655:     next = next->next;
7656:   }
7657:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7658: }

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

7663:   Not Collective

7665:   Input Parameters:
7666: + dm   - The DM object
7667: - name - The label name

7669:   Output Parameter:
7670: . hasLabel - PETSC_TRUE if the label is present

7672:   Level: intermediate

7674: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7675: @*/
7676: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7677: {
7678:   DMLabelLink    next = dm->labels;
7679:   const char    *lname;

7686:   *hasLabel = PETSC_FALSE;
7687:   while (next) {
7688:     PetscObjectGetName((PetscObject) next->label, &lname);
7689:     PetscStrcmp(name, lname, hasLabel);
7690:     if (*hasLabel) break;
7691:     next = next->next;
7692:   }
7693:   return(0);
7694: }

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

7699:   Not Collective

7701:   Input Parameters:
7702: + dm   - The DM object
7703: - name - The label name

7705:   Output Parameter:
7706: . label - The DMLabel, or NULL if the label is absent

7708:   Note: Some of the default labels in a DMPlex will be
7709: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7710: $ "celltype"    - Holds the topological type of each cell
7711: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7712: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7713: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7714: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7716:   Level: intermediate

7718: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7719: @*/
7720: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7721: {
7722:   DMLabelLink    next = dm->labels;
7723:   PetscBool      hasLabel;
7724:   const char    *lname;

7731:   *label = NULL;
7732:   while (next) {
7733:     PetscObjectGetName((PetscObject) next->label, &lname);
7734:     PetscStrcmp(name, lname, &hasLabel);
7735:     if (hasLabel) {
7736:       *label = next->label;
7737:       break;
7738:     }
7739:     next = next->next;
7740:   }
7741:   return(0);
7742: }

7744: /*@C
7745:   DMGetLabelByNum - Return the nth label

7747:   Not Collective

7749:   Input Parameters:
7750: + dm - The DM object
7751: - n  - the label number

7753:   Output Parameter:
7754: . label - the label

7756:   Level: intermediate

7758: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7759: @*/
7760: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7761: {
7762:   DMLabelLink next = dm->labels;
7763:   PetscInt    l    = 0;

7768:   while (next) {
7769:     if (l == n) {
7770:       *label = next->label;
7771:       return(0);
7772:     }
7773:     ++l;
7774:     next = next->next;
7775:   }
7776:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7777: }

7779: /*@C
7780:   DMAddLabel - Add the label to this mesh

7782:   Not Collective

7784:   Input Parameters:
7785: + dm   - The DM object
7786: - label - The DMLabel

7788:   Level: developer

7790: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7791: @*/
7792: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7793: {
7794:   DMLabelLink    l, *p, tmpLabel;
7795:   PetscBool      hasLabel;
7796:   const char    *lname;
7797:   PetscBool      flg;

7802:   PetscObjectGetName((PetscObject) label, &lname);
7803:   DMHasLabel(dm, lname, &hasLabel);
7804:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7805:   PetscCalloc1(1, &tmpLabel);
7806:   tmpLabel->label  = label;
7807:   tmpLabel->output = PETSC_TRUE;
7808:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7809:   *p = tmpLabel;
7810:   PetscObjectReference((PetscObject)label);
7811:   PetscStrcmp(lname, "depth", &flg);
7812:   if (flg) dm->depthLabel = label;
7813:   PetscStrcmp(lname, "celltype", &flg);
7814:   if (flg) dm->celltypeLabel = label;
7815:   return(0);
7816: }

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

7821:   Not Collective

7823:   Input Parameters:
7824: + dm   - The DM object
7825: - name - The label name

7827:   Output Parameter:
7828: . label - The DMLabel, or NULL if the label is absent

7830:   Level: developer

7832:   Notes:
7833:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7834:   DMLabelDestroy() on the label.

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

7840: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7841: @*/
7842: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7843: {
7844:   DMLabelLink    link, *pnext;
7845:   PetscBool      hasLabel;
7846:   const char    *lname;

7852:   if (label) {
7854:     *label = NULL;
7855:   }
7856:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7857:     PetscObjectGetName((PetscObject) link->label, &lname);
7858:     PetscStrcmp(name, lname, &hasLabel);
7859:     if (hasLabel) {
7860:       *pnext = link->next; /* Remove from list */
7861:       PetscStrcmp(name, "depth", &hasLabel);
7862:       if (hasLabel) dm->depthLabel = NULL;
7863:       PetscStrcmp(name, "celltype", &hasLabel);
7864:       if (hasLabel) dm->celltypeLabel = NULL;
7865:       if (label) *label = link->label;
7866:       else       {DMLabelDestroy(&link->label);}
7867:       PetscFree(link);
7868:       break;
7869:     }
7870:   }
7871:   return(0);
7872: }

7874: /*@
7875:   DMRemoveLabelBySelf - Remove the label from this mesh

7877:   Not Collective

7879:   Input Parameters:
7880: + dm   - The DM object
7881: . label - (Optional) The DMLabel to be removed from the DM
7882: - failNotFound - Should it fail if the label is not found in the DM?

7884:   Level: developer

7886:   Notes:
7887:   Only exactly the same instance is removed if found, name match is ignored.
7888:   If the DM has an exclusive reference to the label, it gets destroyed and
7889:   *label nullified.

7891: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7892: @*/
7893: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7894: {
7895:   DMLabelLink    link, *pnext;
7896:   PetscBool      hasLabel = PETSC_FALSE;

7902:   if (!*label && !failNotFound) return(0);
7905:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7906:     if (*label == link->label) {
7907:       hasLabel = PETSC_TRUE;
7908:       *pnext = link->next; /* Remove from list */
7909:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7910:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7911:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7912:       DMLabelDestroy(&link->label);
7913:       PetscFree(link);
7914:       break;
7915:     }
7916:   }
7917:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7918:   return(0);
7919: }

7921: /*@C
7922:   DMGetLabelOutput - Get the output flag for a given label

7924:   Not Collective

7926:   Input Parameters:
7927: + dm   - The DM object
7928: - name - The label name

7930:   Output Parameter:
7931: . output - The flag for output

7933:   Level: developer

7935: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7936: @*/
7937: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7938: {
7939:   DMLabelLink    next = dm->labels;
7940:   const char    *lname;

7947:   while (next) {
7948:     PetscBool flg;

7950:     PetscObjectGetName((PetscObject) next->label, &lname);
7951:     PetscStrcmp(name, lname, &flg);
7952:     if (flg) {*output = next->output; return(0);}
7953:     next = next->next;
7954:   }
7955:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7956: }

7958: /*@C
7959:   DMSetLabelOutput - Set the output flag for a given label

7961:   Not Collective

7963:   Input Parameters:
7964: + dm     - The DM object
7965: . name   - The label name
7966: - output - The flag for output

7968:   Level: developer

7970: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7971: @*/
7972: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7973: {
7974:   DMLabelLink    next = dm->labels;
7975:   const char    *lname;

7981:   while (next) {
7982:     PetscBool flg;

7984:     PetscObjectGetName((PetscObject) next->label, &lname);
7985:     PetscStrcmp(name, lname, &flg);
7986:     if (flg) {next->output = output; return(0);}
7987:     next = next->next;
7988:   }
7989:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7990: }

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

7995:   Collective on dmA

7997:   Input Parameter:
7998: + dmA - The DM object with initial labels
7999: . dmB - The DM object with copied labels
8000: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8001: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

8003:   Level: intermediate

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

8007: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
8008: @*/
8009: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
8010: {
8011:   DMLabel        label, labelNew;
8012:   const char    *name;
8013:   PetscBool      flg;
8014:   DMLabelLink    link;

8022:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8023:   if (dmA == dmB) return(0);
8024:   for (link=dmA->labels; link; link=link->next) {
8025:     label=link->label;
8026:     PetscObjectGetName((PetscObject)label, &name);
8027:     if (!all) {
8028:       PetscStrcmp(name, "depth", &flg);
8029:       if (flg) continue;
8030:       PetscStrcmp(name, "dim", &flg);
8031:       if (flg) continue;
8032:       PetscStrcmp(name, "celltype", &flg);
8033:       if (flg) continue;
8034:     }
8035:     if (mode==PETSC_COPY_VALUES) {
8036:       DMLabelDuplicate(label, &labelNew);
8037:     } else {
8038:       labelNew = label;
8039:     }
8040:     DMAddLabel(dmB, labelNew);
8041:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
8042:   }
8043:   return(0);
8044: }

8046: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8047: {
8051:   if (!*label) {
8052:     DMCreateLabel(dm, name);
8053:     DMGetLabel(dm, name, label);
8054:   }
8055:   DMLabelSetValue(*label, point, value);
8056:   return(0);
8057: }

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

8064:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8065:   each label.
8066: */
8067: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8068: {
8069:   DMUniversalLabel ul;
8070:   PetscBool       *active;
8071:   PetscInt         pStart, pEnd, p, Nl, l, m;
8072:   PetscErrorCode   ierr;

8075:   PetscMalloc1(1, &ul);
8076:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8077:   DMGetNumLabels(dm, &Nl);
8078:   PetscCalloc1(Nl, &active);
8079:   ul->Nl = 0;
8080:   for (l = 0; l < Nl; ++l) {
8081:     PetscBool   isdepth, iscelltype;
8082:     const char *name;

8084:     DMGetLabelName(dm, l, &name);
8085:     PetscStrncmp(name, "depth", 6, &isdepth);
8086:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8087:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8088:     if (active[l]) ++ul->Nl;
8089:   }
8090:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8091:   ul->Nv = 0;
8092:   for (l = 0, m = 0; l < Nl; ++l) {
8093:     DMLabel     label;
8094:     PetscInt    nv;
8095:     const char *name;

8097:     if (!active[l]) continue;
8098:     DMGetLabelName(dm, l, &name);
8099:     DMGetLabelByNum(dm, l, &label);
8100:     DMLabelGetNumValues(label, &nv);
8101:     PetscStrallocpy(name, &ul->names[m]);
8102:     ul->indices[m]   = l;
8103:     ul->Nv          += nv;
8104:     ul->offsets[m+1] = nv;
8105:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8106:     ++m;
8107:   }
8108:   for (l = 1; l <= ul->Nl; ++l) {
8109:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8110:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8111:   }
8112:   for (l = 0; l < ul->Nl; ++l) {
8113:     PetscInt b;

8115:     ul->masks[l] = 0;
8116:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8117:   }
8118:   PetscMalloc1(ul->Nv, &ul->values);
8119:   for (l = 0, m = 0; l < Nl; ++l) {
8120:     DMLabel         label;
8121:     IS              valueIS;
8122:     const PetscInt *varr;
8123:     PetscInt        nv, v;

8125:     if (!active[l]) continue;
8126:     DMGetLabelByNum(dm, l, &label);
8127:     DMLabelGetNumValues(label, &nv);
8128:     DMLabelGetValueIS(label, &valueIS);
8129:     ISGetIndices(valueIS, &varr);
8130:     for (v = 0; v < nv; ++v) {
8131:       ul->values[ul->offsets[m]+v] = varr[v];
8132:     }
8133:     ISRestoreIndices(valueIS, &varr);
8134:     ISDestroy(&valueIS);
8135:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8136:     ++m;
8137:   }
8138:   DMPlexGetChart(dm, &pStart, &pEnd);
8139:   for (p = pStart; p < pEnd; ++p) {
8140:     PetscInt  uval = 0;
8141:     PetscBool marked = PETSC_FALSE;

8143:     for (l = 0, m = 0; l < Nl; ++l) {
8144:       DMLabel  label;
8145:       PetscInt val, defval, loc, nv;

8147:       if (!active[l]) continue;
8148:       DMGetLabelByNum(dm, l, &label);
8149:       DMLabelGetValue(label, p, &val);
8150:       DMLabelGetDefaultValue(label, &defval);
8151:       if (val == defval) {++m; continue;}
8152:       nv = ul->offsets[m+1]-ul->offsets[m];
8153:       marked = PETSC_TRUE;
8154:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8155:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8156:       uval += (loc+1) << ul->bits[m];
8157:       ++m;
8158:     }
8159:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8160:   }
8161:   PetscFree(active);
8162:   *universal = ul;
8163:   return(0);
8164: }

8166: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8167: {
8168:   PetscInt       l;

8172:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8173:   DMLabelDestroy(&(*universal)->label);
8174:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8175:   PetscFree((*universal)->values);
8176:   PetscFree(*universal);
8177:   *universal = NULL;
8178:   return(0);
8179: }

8181: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8182: {
8185:   *ulabel = ul->label;
8186:   return(0);
8187: }

8189: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8190: {
8191:   PetscInt       Nl = ul->Nl, l;

8196:   for (l = 0; l < Nl; ++l) {
8197:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8198:     else               {DMCreateLabel(dm, ul->names[l]);}
8199:   }
8200:   if (preserveOrder) {
8201:     for (l = 0; l < ul->Nl; ++l) {
8202:       const char *name;
8203:       PetscBool   match;

8205:       DMGetLabelName(dm, ul->indices[l], &name);
8206:       PetscStrcmp(name, ul->names[l], &match);
8207:       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]);
8208:     }
8209:   }
8210:   return(0);
8211: }

8213: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8214: {
8215:   PetscInt       l;

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

8223:     if (lval) {
8224:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8225:       else          {DMGetLabel(dm, ul->names[l], &label);}
8226:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8227:     }
8228:   }
8229:   return(0);
8230: }

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

8235:   Input Parameter:
8236: . dm - The DM object

8238:   Output Parameter:
8239: . cdm - The coarse DM

8241:   Level: intermediate

8243: .seealso: DMSetCoarseDM()
8244: @*/
8245: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8246: {
8250:   *cdm = dm->coarseMesh;
8251:   return(0);
8252: }

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

8257:   Input Parameters:
8258: + dm - The DM object
8259: - cdm - The coarse DM

8261:   Level: intermediate

8263: .seealso: DMGetCoarseDM()
8264: @*/
8265: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8266: {

8272:   PetscObjectReference((PetscObject)cdm);
8273:   DMDestroy(&dm->coarseMesh);
8274:   dm->coarseMesh = cdm;
8275:   return(0);
8276: }

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

8281:   Input Parameter:
8282: . dm - The DM object

8284:   Output Parameter:
8285: . fdm - The fine DM

8287:   Level: intermediate

8289: .seealso: DMSetFineDM()
8290: @*/
8291: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8292: {
8296:   *fdm = dm->fineMesh;
8297:   return(0);
8298: }

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

8303:   Input Parameters:
8304: + dm - The DM object
8305: - fdm - The fine DM

8307:   Level: intermediate

8309: .seealso: DMGetFineDM()
8310: @*/
8311: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8312: {

8318:   PetscObjectReference((PetscObject)fdm);
8319:   DMDestroy(&dm->fineMesh);
8320:   dm->fineMesh = fdm;
8321:   return(0);
8322: }

8324: /*=== DMBoundary code ===*/

8326: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
8327: {
8328:   PetscInt       d;

8332:   for (d = 0; d < dm->Nds; ++d) {
8333:     PetscDSCopyBoundary(dm->probs[d].ds, PETSC_DETERMINE, NULL, dmNew->probs[d].ds);
8334:   }
8335:   return(0);
8336: }

8338: /*@C
8339:   DMAddBoundary - Add a boundary condition to the model

8341:   Collective on dm

8343:   Input Parameters:
8344: + dm          - The DM, with a PetscDS that matches the problem being constrained
8345: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8346: . name        - The BC name
8347: . labelname   - The label defining constrained points
8348: . field       - The field to constrain
8349: . numcomps    - The number of constrained field components (0 will constrain all fields)
8350: . comps       - An array of constrained component numbers
8351: . bcFunc      - A pointwise function giving boundary values
8352: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8353: . numids      - The number of DMLabel ids for constrained points
8354: . ids         - An array of ids for constrained points
8355: - ctx         - An optional user context for bcFunc

8357:   Options Database Keys:
8358: + -bc_<boundary name> <num> - Overrides the boundary ids
8359: - -bc_<boundary name>_comp <num> - Overrides the boundary components

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

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

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

8368: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8369: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8370: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8371: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8373: + dim - the spatial dimension
8374: . Nf - the number of fields
8375: . uOff - the offset into u[] and u_t[] for each field
8376: . uOff_x - the offset into u_x[] for each field
8377: . u - each field evaluated at the current point
8378: . u_t - the time derivative of each field evaluated at the current point
8379: . u_x - the gradient of each field evaluated at the current point
8380: . aOff - the offset into a[] and a_t[] for each auxiliary field
8381: . aOff_x - the offset into a_x[] for each auxiliary field
8382: . a - each auxiliary field evaluated at the current point
8383: . a_t - the time derivative of each auxiliary field evaluated at the current point
8384: . a_x - the gradient of auxiliary each field evaluated at the current point
8385: . t - current time
8386: . x - coordinates of the current point
8387: . numConstants - number of constant parameters
8388: . constants - constant parameters
8389: - bcval - output values at the current point

8391:   Level: developer

8393: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8394: @*/
8395: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
8396: {
8397:   PetscDS        ds;

8406:   DMGetDS(dm, &ds);
8407:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8408:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8409:   return(0);
8410: }

8412: /*@
8413:   DMGetNumBoundary - Get the number of registered BC

8415:   Input Parameters:
8416: . dm - The mesh object

8418:   Output Parameters:
8419: . numBd - The number of BC

8421:   Level: intermediate

8423: .seealso: DMAddBoundary(), DMGetBoundary()
8424: @*/
8425: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8426: {
8427:   PetscDS        ds;

8432:   DMGetDS(dm, &ds);
8433:   PetscDSGetNumBoundary(ds, numBd);
8434:   return(0);
8435: }

8437: /*@C
8438:   DMGetBoundary - Get a model boundary condition

8440:   Input Parameters:
8441: + dm          - The mesh object
8442: - bd          - The BC number

8444:   Output Parameters:
8445: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8446: . name        - The BC name
8447: . labelname   - The label defining constrained points
8448: . field       - The field to constrain
8449: . numcomps    - The number of constrained field components
8450: . comps       - An array of constrained component numbers
8451: . bcFunc      - A pointwise function giving boundary values
8452: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8453: . numids      - The number of DMLabel ids for constrained points
8454: . ids         - An array of ids for constrained points
8455: - ctx         - An optional user context for bcFunc

8457:   Options Database Keys:
8458: + -bc_<boundary name> <num> - Overrides the boundary ids
8459: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8461:   Level: developer

8463: .seealso: DMAddBoundary()
8464: @*/
8465: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
8466: {
8467:   PetscDS        ds;

8472:   DMGetDS(dm, &ds);
8473:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8474:   return(0);
8475: }

8477: static PetscErrorCode DMPopulateBoundary(DM dm)
8478: {
8479:   PetscDS        ds;
8480:   DMBoundary    *lastnext;
8481:   DSBoundary     dsbound;

8485:   DMGetDS(dm, &ds);
8486:   dsbound = ds->boundary;
8487:   if (dm->boundary) {
8488:     DMBoundary next = dm->boundary;

8490:     /* quick check to see if the PetscDS has changed */
8491:     if (next->dsboundary == dsbound) return(0);
8492:     /* the PetscDS has changed: tear down and rebuild */
8493:     while (next) {
8494:       DMBoundary b = next;

8496:       next = b->next;
8497:       PetscFree(b);
8498:     }
8499:     dm->boundary = NULL;
8500:   }

8502:   lastnext = &(dm->boundary);
8503:   while (dsbound) {
8504:     DMBoundary dmbound;

8506:     PetscNew(&dmbound);
8507:     dmbound->dsboundary = dsbound;
8508:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8509:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8510:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8511:     *lastnext = dmbound;
8512:     lastnext = &(dmbound->next);
8513:     dsbound = dsbound->next;
8514:   }
8515:   return(0);
8516: }

8518: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8519: {
8520:   DMBoundary     b;

8526:   *isBd = PETSC_FALSE;
8527:   DMPopulateBoundary(dm);
8528:   b = dm->boundary;
8529:   while (b && !(*isBd)) {
8530:     DMLabel    label = b->label;
8531:     DSBoundary dsb = b->dsboundary;

8533:     if (label) {
8534:       PetscInt i;

8536:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8537:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8538:       }
8539:     }
8540:     b = b->next;
8541:   }
8542:   return(0);
8543: }

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

8548:   Collective on DM

8550:   Input Parameters:
8551: + dm      - The DM
8552: . time    - The time
8553: . funcs   - The coordinate functions to evaluate, one per field
8554: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8555: - mode    - The insertion mode for values

8557:   Output Parameter:
8558: . X - vector

8560:    Calling sequence of func:
8561: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8563: +  dim - The spatial dimension
8564: .  time - The time at which to sample
8565: .  x   - The coordinates
8566: .  Nf  - The number of fields
8567: .  u   - The output field values
8568: -  ctx - optional user-defined function context

8570:   Level: developer

8572: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8573: @*/
8574: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8575: {
8576:   Vec            localX;

8581:   DMGetLocalVector(dm, &localX);
8582:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8583:   DMLocalToGlobalBegin(dm, localX, mode, X);
8584:   DMLocalToGlobalEnd(dm, localX, mode, X);
8585:   DMRestoreLocalVector(dm, &localX);
8586:   return(0);
8587: }

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

8592:   Not collective

8594:   Input Parameters:
8595: + dm      - The DM
8596: . time    - The time
8597: . funcs   - The coordinate functions to evaluate, one per field
8598: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8599: - mode    - The insertion mode for values

8601:   Output Parameter:
8602: . localX - vector

8604:    Calling sequence of func:
8605: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8607: +  dim - The spatial dimension
8608: .  x   - The coordinates
8609: .  Nf  - The number of fields
8610: .  u   - The output field values
8611: -  ctx - optional user-defined function context

8613:   Level: developer

8615: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8616: @*/
8617: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8618: {

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

8629: /*@C
8630:   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.

8632:   Collective on DM

8634:   Input Parameters:
8635: + dm      - The DM
8636: . time    - The time
8637: . label   - The DMLabel selecting the portion of the mesh for projection
8638: . funcs   - The coordinate functions to evaluate, one per field
8639: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8640: - mode    - The insertion mode for values

8642:   Output Parameter:
8643: . X - vector

8645:    Calling sequence of func:
8646: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8648: +  dim - The spatial dimension
8649: .  x   - The coordinates
8650: .  Nf  - The number of fields
8651: .  u   - The output field values
8652: -  ctx - optional user-defined function context

8654:   Level: developer

8656: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8657: @*/
8658: 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)
8659: {
8660:   Vec            localX;

8665:   DMGetLocalVector(dm, &localX);
8666:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8667:   DMLocalToGlobalBegin(dm, localX, mode, X);
8668:   DMLocalToGlobalEnd(dm, localX, mode, X);
8669:   DMRestoreLocalVector(dm, &localX);
8670:   return(0);
8671: }

8673: /*@C
8674:   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.

8676:   Not collective

8678:   Input Parameters:
8679: + dm      - The DM
8680: . time    - The time
8681: . label   - The DMLabel selecting the portion of the mesh for projection
8682: . funcs   - The coordinate functions to evaluate, one per field
8683: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8684: - mode    - The insertion mode for values

8686:   Output Parameter:
8687: . localX - vector

8689:    Calling sequence of func:
8690: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8692: +  dim - The spatial dimension
8693: .  x   - The coordinates
8694: .  Nf  - The number of fields
8695: .  u   - The output field values
8696: -  ctx - optional user-defined function context

8698:   Level: developer

8700: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8701: @*/
8702: 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)
8703: {

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

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

8717:   Not collective

8719:   Input Parameters:
8720: + dm      - The DM
8721: . time    - The time
8722: . localU  - The input field vector
8723: . funcs   - The functions to evaluate, one per field
8724: - mode    - The insertion mode for values

8726:   Output Parameter:
8727: . localX  - The output vector

8729:    Calling sequence of func:
8730: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8731: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8732: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8733: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8735: +  dim          - The spatial dimension
8736: .  Nf           - The number of input fields
8737: .  NfAux        - The number of input auxiliary fields
8738: .  uOff         - The offset of each field in u[]
8739: .  uOff_x       - The offset of each field in u_x[]
8740: .  u            - The field values at this point in space
8741: .  u_t          - The field time derivative at this point in space (or NULL)
8742: .  u_x          - The field derivatives at this point in space
8743: .  aOff         - The offset of each auxiliary field in u[]
8744: .  aOff_x       - The offset of each auxiliary field in u_x[]
8745: .  a            - The auxiliary field values at this point in space
8746: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8747: .  a_x          - The auxiliary field derivatives at this point in space
8748: .  t            - The current time
8749: .  x            - The coordinates of this point
8750: .  numConstants - The number of constants
8751: .  constants    - The value of each constant
8752: -  f            - The value of the function at this point in space

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

8759:   Level: intermediate

8761: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8762: @*/
8763: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8764:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8765:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8766:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8767:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8768:                                    InsertMode mode, Vec localX)
8769: {

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

8781: /*@C
8782:   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.

8784:   Not collective

8786:   Input Parameters:
8787: + dm      - The DM
8788: . time    - The time
8789: . label   - The DMLabel marking the portion of the domain to output
8790: . numIds  - The number of label ids to use
8791: . ids     - The label ids to use for marking
8792: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8793: . comps   - The components to set in the output, or NULL for all components
8794: . localU  - The input field vector
8795: . funcs   - The functions to evaluate, one per field
8796: - mode    - The insertion mode for values

8798:   Output Parameter:
8799: . localX  - The output vector

8801:    Calling sequence of func:
8802: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8803: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8804: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8805: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8807: +  dim          - The spatial dimension
8808: .  Nf           - The number of input fields
8809: .  NfAux        - The number of input auxiliary fields
8810: .  uOff         - The offset of each field in u[]
8811: .  uOff_x       - The offset of each field in u_x[]
8812: .  u            - The field values at this point in space
8813: .  u_t          - The field time derivative at this point in space (or NULL)
8814: .  u_x          - The field derivatives at this point in space
8815: .  aOff         - The offset of each auxiliary field in u[]
8816: .  aOff_x       - The offset of each auxiliary field in u_x[]
8817: .  a            - The auxiliary field values at this point in space
8818: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8819: .  a_x          - The auxiliary field derivatives at this point in space
8820: .  t            - The current time
8821: .  x            - The coordinates of this point
8822: .  numConstants - The number of constants
8823: .  constants    - The value of each constant
8824: -  f            - The value of the function at this point in space

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

8831:   Level: intermediate

8833: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8834: @*/
8835: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8836:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8837:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8838:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8839:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8840:                                         InsertMode mode, Vec localX)
8841: {

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

8853: /*@C
8854:   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.

8856:   Not collective

8858:   Input Parameters:
8859: + dm      - The DM
8860: . time    - The time
8861: . label   - The DMLabel marking the portion of the domain boundary to output
8862: . numIds  - The number of label ids to use
8863: . ids     - The label ids to use for marking
8864: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8865: . comps   - The components to set in the output, or NULL for all components
8866: . localU  - The input field vector
8867: . funcs   - The functions to evaluate, one per field
8868: - mode    - The insertion mode for values

8870:   Output Parameter:
8871: . localX  - The output vector

8873:    Calling sequence of func:
8874: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8875: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8876: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8877: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8879: +  dim          - The spatial dimension
8880: .  Nf           - The number of input fields
8881: .  NfAux        - The number of input auxiliary fields
8882: .  uOff         - The offset of each field in u[]
8883: .  uOff_x       - The offset of each field in u_x[]
8884: .  u            - The field values at this point in space
8885: .  u_t          - The field time derivative at this point in space (or NULL)
8886: .  u_x          - The field derivatives at this point in space
8887: .  aOff         - The offset of each auxiliary field in u[]
8888: .  aOff_x       - The offset of each auxiliary field in u_x[]
8889: .  a            - The auxiliary field values at this point in space
8890: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8891: .  a_x          - The auxiliary field derivatives at this point in space
8892: .  t            - The current time
8893: .  x            - The coordinates of this point
8894: .  n            - The face normal
8895: .  numConstants - The number of constants
8896: .  constants    - The value of each constant
8897: -  f            - The value of the function at this point in space

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

8905:   Level: intermediate

8907: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8908: @*/
8909: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8910:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8911:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8912:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8913:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8914:                                           InsertMode mode, Vec localX)
8915: {

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

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

8930:   Input Parameters:
8931: + dm    - The DM
8932: . time  - The time
8933: . funcs - The functions to evaluate for each field component
8934: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8935: - X     - The coefficient vector u_h, a global vector

8937:   Output Parameter:
8938: . diff - The diff ||u - u_h||_2

8940:   Level: developer

8942: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8943: @*/
8944: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8945: {

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

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

8959:   Collective on dm

8961:   Input Parameters:
8962: + dm    - The DM
8963: , time  - The time
8964: . funcs - The gradient functions to evaluate for each field component
8965: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8966: . X     - The coefficient vector u_h, a global vector
8967: - n     - The vector to project along

8969:   Output Parameter:
8970: . diff - The diff ||(grad u - grad u_h) . n||_2

8972:   Level: developer

8974: .seealso: DMProjectFunction(), DMComputeL2Diff()
8975: @*/
8976: 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)
8977: {

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

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

8991:   Collective on dm

8993:   Input Parameters:
8994: + dm    - The DM
8995: . time  - The time
8996: . funcs - The functions to evaluate for each field component
8997: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8998: - X     - The coefficient vector u_h, a global vector

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

9003:   Level: developer

9005: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
9006: @*/
9007: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9008: {

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

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

9023:   Collective on dm

9025:   Input parameters:
9026: + dm - the pre-adaptation DM object
9027: - label - label with the flags

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

9032:   Level: intermediate

9034: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
9035: @*/
9036: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
9037: {

9044:   *dmAdapt = NULL;
9045:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
9046:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
9047:   if (*dmAdapt) {
9048:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
9049:     PetscFree((*dmAdapt)->vectype);
9050:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
9051:     PetscFree((*dmAdapt)->mattype);
9052:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
9053:   }
9054:   return(0);
9055: }

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

9060:   Input Parameters:
9061: + dm - The DM object
9062: . metric - The metric to which the mesh is adapted, defined vertex-wise.
9063: - 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_".

9065:   Output Parameter:
9066: . dmAdapt  - Pointer to the DM object containing the adapted mesh

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

9070:   Level: advanced

9072: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
9073: @*/
9074: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
9075: {

9083:   *dmAdapt = NULL;
9084:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
9085:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
9086:   return(0);
9087: }

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

9092:  Not Collective

9094:  Input Parameter:
9095: .  dm    - The DM

9097:  Output Parameters:
9098: +  nranks - the number of neighbours
9099: -  ranks - the neighbors ranks

9101:  Notes:
9102:  Do not free the array, it is freed when the DM is destroyed.

9104:  Level: beginner

9106:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9107: @*/
9108: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9109: {

9114:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9115:   (dm->ops->getneighbors)(dm,nranks,ranks);
9116:   return(0);
9117: }

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

9121: /*
9122:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9123:     This has be a different function because it requires DM which is not defined in the Mat library
9124: */
9125: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9126: {

9130:   if (coloring->ctype == IS_COLORING_LOCAL) {
9131:     Vec x1local;
9132:     DM  dm;
9133:     MatGetDM(J,&dm);
9134:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9135:     DMGetLocalVector(dm,&x1local);
9136:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9137:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9138:     x1   = x1local;
9139:   }
9140:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9141:   if (coloring->ctype == IS_COLORING_LOCAL) {
9142:     DM  dm;
9143:     MatGetDM(J,&dm);
9144:     DMRestoreLocalVector(dm,&x1);
9145:   }
9146:   return(0);
9147: }

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

9152:     Input Parameter:
9153: .    coloring - the MatFDColoring object

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

9158:     Level: advanced

9160: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9161: @*/
9162: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9163: {
9165:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9166:   return(0);
9167: }

9169: /*@
9170:     DMGetCompatibility - determine if two DMs are compatible

9172:     Collective

9174:     Input Parameters:
9175: +    dm1 - the first DM
9176: -    dm2 - the second DM

9178:     Output Parameters:
9179: +    compatible - whether or not the two DMs are compatible
9180: -    set - whether or not the compatible value was set

9182:     Notes:
9183:     Two DMs are deemed compatible if they represent the same parallel decomposition
9184:     of the same topology. This implies that the section (field data) on one
9185:     "makes sense" with respect to the topology and parallel decomposition of the other.
9186:     Loosely speaking, compatible DMs represent the same domain and parallel
9187:     decomposition, but hold different data.

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

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

9197:     Consider the operation of summing data living on a 2-dof DMDA to data living
9198:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9199: .vb
9200:   ...
9201:   DMGetCompatibility(da1,da2,&compatible,&set);
9202:   if (set && compatible)  {
9203:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9204:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9205:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9206:     for (j=y; j<y+n; ++j) {
9207:       for (i=x; i<x+m, ++i) {
9208:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9209:       }
9210:     }
9211:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9212:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9213:   } else {
9214:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9215:   }
9216:   ...
9217: .ve

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

9224:     A DM is always compatible with itself.

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

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

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

9243:     Level: advanced

9245: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9246: @*/

9248: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9249: {
9251:   PetscMPIInt    compareResult;
9252:   DMType         type,type2;
9253:   PetscBool      sameType;


9259:   /* Declare a DM compatible with itself */
9260:   if (dm1 == dm2) {
9261:     *set = PETSC_TRUE;
9262:     *compatible = PETSC_TRUE;
9263:     return(0);
9264:   }

9266:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9267:      communicator. Note that this does not preclude compatibility with
9268:      DMs living on "congruent" or "similar" communicators, but this must be
9269:      determined by the implementation-specific logic */
9270:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9271:   if (compareResult == MPI_UNEQUAL) {
9272:     *set = PETSC_TRUE;
9273:     *compatible = PETSC_FALSE;
9274:     return(0);
9275:   }

9277:   /* Pass to the implementation-specific routine, if one exists. */
9278:   if (dm1->ops->getcompatibility) {
9279:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9280:     if (*set) return(0);
9281:   }

9283:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9284:      with an implementation of this function from dm2 */
9285:   DMGetType(dm1,&type);
9286:   DMGetType(dm2,&type2);
9287:   PetscStrcmp(type,type2,&sameType);
9288:   if (!sameType && dm2->ops->getcompatibility) {
9289:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9290:   } else {
9291:     *set = PETSC_FALSE;
9292:   }
9293:   return(0);
9294: }

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

9299:   Logically Collective on DM

9301:   Input Parameters:
9302: + DM - the DM
9303: . f - the monitor function
9304: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9305: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

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

9311:   Notes:
9312:   Several different monitoring routines may be set by calling
9313:   DMMonitorSet() multiple times; all will be called in the
9314:   order in which they were set.

9316:   Fortran Notes:
9317:   Only a single monitor function can be set for each DM object

9319:   Level: intermediate

9321: .seealso: DMMonitorCancel()
9322: @*/
9323: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9324: {
9325:   PetscInt       m;

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

9333:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9334:     if (identical) return(0);
9335:   }
9336:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9337:   dm->monitor[dm->numbermonitors]          = f;
9338:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9339:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9340:   return(0);
9341: }

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

9346:   Logically Collective on DM

9348:   Input Parameter:
9349: . dm - the DM

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

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

9359:   Level: intermediate

9361: .seealso: DMMonitorSet()
9362: @*/
9363: PetscErrorCode DMMonitorCancel(DM dm)
9364: {
9366:   PetscInt       m;

9370:   for (m = 0; m < dm->numbermonitors; ++m) {
9371:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9372:   }
9373:   dm->numbermonitors = 0;
9374:   return(0);
9375: }

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

9380:   Collective on DM

9382:   Input Parameters:
9383: + dm   - DM object you wish to monitor
9384: . name - the monitor type one is seeking
9385: . help - message indicating what monitoring is done
9386: . manual - manual page for the monitor
9387: . monitor - the monitor function
9388: - 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

9390:   Output Parameter:
9391: . flg - Flag set if the monitor was created

9393:   Level: developer

9395: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9396:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9397:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9398:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9399:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9400:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9401:           PetscOptionsFList(), PetscOptionsEList()
9402: @*/
9403: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9404: {
9405:   PetscViewer       viewer;
9406:   PetscViewerFormat format;
9407:   PetscErrorCode    ierr;

9411:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9412:   if (*flg) {
9413:     PetscViewerAndFormat *vf;

9415:     PetscViewerAndFormatCreate(viewer, format, &vf);
9416:     PetscObjectDereference((PetscObject) viewer);
9417:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9418:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9419:   }
9420:   return(0);
9421: }

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

9426:    Collective on DM

9428:    Input Parameters:
9429: .  dm - The DM

9431:    Level: developer

9433: .seealso: DMMonitorSet()
9434: @*/
9435: PetscErrorCode DMMonitor(DM dm)
9436: {
9437:   PetscInt       m;

9441:   if (!dm) return(0);
9443:   for (m = 0; m < dm->numbermonitors; ++m) {
9444:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9445:   }
9446:   return(0);
9447: }

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

9452:   Collective on DM

9454:   Input Parameters:
9455: + dm     - The DM
9456: . sol    - The solution vector
9457: . errors - An array of length Nf, the number of fields, or NULL for no output
9458: - errorVec - A Vec pointer, or NULL for no output

9460:   Output Parameters:
9461: + errors   - The error in each field
9462: - errorVec - Creates a vector to hold the cellwise error

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

9466:   Level: developer

9468: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9469: @*/
9470: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9471: {
9472:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9473:   void            **ctxs;
9474:   PetscReal         time;
9475:   PetscInt          Nf, f, Nds, s;
9476:   PetscErrorCode    ierr;

9479:   DMGetNumFields(dm, &Nf);
9480:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9481:   DMGetNumDS(dm, &Nds);
9482:   for (s = 0; s < Nds; ++s) {
9483:     PetscDS         ds;
9484:     DMLabel         label;
9485:     IS              fieldIS;
9486:     const PetscInt *fields;
9487:     PetscInt        dsNf;

9489:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9490:     PetscDSGetNumFields(ds, &dsNf);
9491:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
9492:     for (f = 0; f < dsNf; ++f) {
9493:       const PetscInt field = fields[f];
9494:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9495:     }
9496:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
9497:   }
9498:   for (f = 0; f < Nf; ++f) {
9499:     if (!exactSol[f]) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %D", f);
9500:   }
9501:   DMGetOutputSequenceNumber(dm, NULL, &time);
9502:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
9503:   if (errorVec) {
9504:     DM             edm;
9505:     DMPolytopeType ct;
9506:     PetscBool      simplex;
9507:     PetscInt       dim, cStart, Nf;

9509:     DMClone(dm, &edm);
9510:     DMGetDimension(edm, &dim);
9511:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9512:     DMPlexGetCellType(dm, cStart, &ct);
9513:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9514:     DMGetNumFields(dm, &Nf);
9515:     for (f = 0; f < Nf; ++f) {
9516:       PetscFE         fe, efe;
9517:       PetscQuadrature q;
9518:       const char     *name;

9520:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
9521:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9522:       PetscObjectGetName((PetscObject) fe, &name);
9523:       PetscObjectSetName((PetscObject) efe, name);
9524:       PetscFEGetQuadrature(fe, &q);
9525:       PetscFESetQuadrature(efe, q);
9526:       DMSetField(edm, f, NULL, (PetscObject) efe);
9527:       PetscFEDestroy(&efe);
9528:     }
9529:     DMCreateDS(edm);

9531:     DMCreateGlobalVector(edm, errorVec);
9532:     PetscObjectSetName((PetscObject) *errorVec, "Error");
9533:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9534:     DMDestroy(&edm);
9535:   }
9536:   PetscFree2(exactSol, ctxs);
9537:   return(0);
9538: }