Actual source code: dm.c

petsc-master 2020-04-08
Report Typos and Errors
  1:  #include <petsc/private/dmimpl.h>
  2:  #include <petsc/private/dmlabelimpl.h>
  3:  #include <petsc/private/petscdsimpl.h>
  4:  #include <petscdmplex.h>
  5:  #include <petscdmfield.h>
  6:  #include <petscsf.h>
  7:  #include <petscds.h>

  9: PetscClassId  DM_CLASSID;
 10: PetscClassId  DMLABEL_CLASSID;
 11: 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;

 13: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_",0};
 14: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_",0};
 15: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "FV_ghost_cell", "unknown", "DMPolytopeType", "DM_POLYTOPE_", 0};
 16: /*@
 17:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

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

 22:   Collective

 24:   Input Parameter:
 25: . comm - The communicator for the DM object

 27:   Output Parameter:
 28: . dm - The DM object

 30:   Level: beginner

 32: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
 33: @*/
 34: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
 35: {
 36:   DM             v;
 37:   PetscDS        ds;

 42:   *dm = NULL;
 43:   DMInitializePackage();

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

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

 85:   *dm = v;
 86:   return(0);
 87: }

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

 92:   Collective

 94:   Input Parameter:
 95: . dm - The original DM object

 97:   Output Parameter:
 98: . newdm  - The new DM object

100:   Level: beginner

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

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

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

111: @*/
112: PetscErrorCode DMClone(DM dm, DM *newdm)
113: {
114:   PetscSF        sf;
115:   Vec            coords;
116:   void          *ctx;
117:   PetscInt       dim, cdim;

123:   DMCreate(PetscObjectComm((PetscObject) dm), newdm);
124:   DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE);
125:   (*newdm)->leveldown  = dm->leveldown;
126:   (*newdm)->levelup    = dm->levelup;
127:   DMGetDimension(dm, &dim);
128:   DMSetDimension(*newdm, dim);
129:   if (dm->ops->clone) {
130:     (*dm->ops->clone)(dm, newdm);
131:   }
132:   (*newdm)->setupcalled = dm->setupcalled;
133:   DMGetPointSF(dm, &sf);
134:   DMSetPointSF(*newdm, sf);
135:   DMGetApplicationContext(dm, &ctx);
136:   DMSetApplicationContext(*newdm, ctx);
137:   if (dm->coordinateDM) {
138:     DM           ncdm;
139:     PetscSection cs;
140:     PetscInt     pEnd = -1, pEndMax = -1;

142:     DMGetLocalSection(dm->coordinateDM, &cs);
143:     if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
144:     MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
145:     if (pEndMax >= 0) {
146:       DMClone(dm->coordinateDM, &ncdm);
147:       DMCopyDisc(dm->coordinateDM, ncdm);
148:       DMSetLocalSection(ncdm, cs);
149:       DMSetCoordinateDM(*newdm, ncdm);
150:       DMDestroy(&ncdm);
151:     }
152:   }
153:   DMGetCoordinateDim(dm, &cdim);
154:   DMSetCoordinateDim(*newdm, cdim);
155:   DMGetCoordinatesLocal(dm, &coords);
156:   if (coords) {
157:     DMSetCoordinatesLocal(*newdm, coords);
158:   } else {
159:     DMGetCoordinates(dm, &coords);
160:     if (coords) {DMSetCoordinates(*newdm, coords);}
161:   }
162:   {
163:     PetscBool             isper;
164:     const PetscReal      *maxCell, *L;
165:     const DMBoundaryType *bd;
166:     DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
167:     DMSetPeriodicity(*newdm, isper, maxCell,  L,  bd);
168:   }
169:   {
170:     PetscBool useCone, useClosure;

172:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
173:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
174:   }
175:   return(0);
176: }

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

181:    Logically Collective on da

183:    Input Parameter:
184: +  da - initial distributed array
185: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

187:    Options Database:
188: .   -dm_vec_type ctype

190:    Level: intermediate

192: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
193: @*/
194: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
195: {

200:   PetscFree(da->vectype);
201:   PetscStrallocpy(ctype,(char**)&da->vectype);
202:   return(0);
203: }

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

208:    Logically Collective on da

210:    Input Parameter:
211: .  da - initial distributed array

213:    Output Parameter:
214: .  ctype - the vector type

216:    Level: intermediate

218: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
219: @*/
220: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
221: {
224:   *ctype = da->vectype;
225:   return(0);
226: }

228: /*@
229:   VecGetDM - Gets the DM defining the data layout of the vector

231:   Not collective

233:   Input Parameter:
234: . v - The Vec

236:   Output Parameter:
237: . dm - The DM

239:   Level: intermediate

241: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
242: @*/
243: PetscErrorCode VecGetDM(Vec v, DM *dm)
244: {

250:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
251:   return(0);
252: }

254: /*@
255:   VecSetDM - Sets the DM defining the data layout of the vector.

257:   Not collective

259:   Input Parameters:
260: + v - The Vec
261: - dm - The DM

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

265:   Level: intermediate

267: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
268: @*/
269: PetscErrorCode VecSetDM(Vec v, DM dm)
270: {

276:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
277:   return(0);
278: }

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

283:    Logically Collective on dm

285:    Input Parameters:
286: +  dm - the DM context
287: -  ctype - the matrix type

289:    Options Database:
290: .   -dm_is_coloring_type - global or local

292:    Level: intermediate

294: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
295:           DMGetISColoringType()
296: @*/
297: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
298: {
301:   dm->coloringtype = ctype;
302:   return(0);
303: }

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

308:    Logically Collective on dm

310:    Input Parameter:
311: .  dm - the DM context

313:    Output Parameter:
314: .  ctype - the matrix type

316:    Options Database:
317: .   -dm_is_coloring_type - global or local

319:    Level: intermediate

321: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
322:           DMGetISColoringType()
323: @*/
324: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
325: {
328:   *ctype = dm->coloringtype;
329:   return(0);
330: }

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

335:    Logically Collective on dm

337:    Input Parameters:
338: +  dm - the DM context
339: -  ctype - the matrix type

341:    Options Database:
342: .   -dm_mat_type ctype

344:    Level: intermediate

346: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
347: @*/
348: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
349: {

354:   PetscFree(dm->mattype);
355:   PetscStrallocpy(ctype,(char**)&dm->mattype);
356:   return(0);
357: }

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

362:    Logically Collective on dm

364:    Input Parameter:
365: .  dm - the DM context

367:    Output Parameter:
368: .  ctype - the matrix type

370:    Options Database:
371: .   -dm_mat_type ctype

373:    Level: intermediate

375: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
376: @*/
377: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
378: {
381:   *ctype = dm->mattype;
382:   return(0);
383: }

385: /*@
386:   MatGetDM - Gets the DM defining the data layout of the matrix

388:   Not collective

390:   Input Parameter:
391: . A - The Mat

393:   Output Parameter:
394: . dm - The DM

396:   Level: intermediate

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

401: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
402: @*/
403: PetscErrorCode MatGetDM(Mat A, DM *dm)
404: {

410:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
411:   return(0);
412: }

414: /*@
415:   MatSetDM - Sets the DM defining the data layout of the matrix

417:   Not collective

419:   Input Parameters:
420: + A - The Mat
421: - dm - The DM

423:   Level: intermediate

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


429: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
430: @*/
431: PetscErrorCode MatSetDM(Mat A, DM dm)
432: {

438:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
439:   return(0);
440: }

442: /*@C
443:    DMSetOptionsPrefix - Sets the prefix used for searching for all
444:    DM options in the database.

446:    Logically Collective on dm

448:    Input Parameter:
449: +  da - the DM context
450: -  prefix - the prefix to prepend to all option names

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

456:    Level: advanced

458: .seealso: DMSetFromOptions()
459: @*/
460: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
461: {

466:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
467:   if (dm->sf) {
468:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
469:   }
470:   if (dm->sectionSF) {
471:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
472:   }
473:   return(0);
474: }

476: /*@C
477:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
478:    DM options in the database.

480:    Logically Collective on dm

482:    Input Parameters:
483: +  dm - the DM context
484: -  prefix - the prefix string to prepend to all DM option requests

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

490:    Level: advanced

492: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
493: @*/
494: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
495: {

500:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
501:   return(0);
502: }

504: /*@C
505:    DMGetOptionsPrefix - Gets the prefix used for searching for all
506:    DM options in the database.

508:    Not Collective

510:    Input Parameters:
511: .  dm - the DM context

513:    Output Parameters:
514: .  prefix - pointer to the prefix string used is returned

516:    Notes:
517:     On the fortran side, the user should pass in a string 'prefix' of
518:    sufficient length to hold the prefix.

520:    Level: advanced

522: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
523: @*/
524: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
525: {

530:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
531:   return(0);
532: }

534: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
535: {
536:   PetscInt       refct = ((PetscObject) dm)->refct;

540:   *ncrefct = 0;
541:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
542:     refct--;
543:     if (recurseCoarse) {
544:       PetscInt coarseCount;

546:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
547:       refct += coarseCount;
548:     }
549:   }
550:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
551:     refct--;
552:     if (recurseFine) {
553:       PetscInt fineCount;

555:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
556:       refct += fineCount;
557:     }
558:   }
559:   *ncrefct = refct;
560:   return(0);
561: }

563: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
564: {
565:   DMLabelLink    next = dm->labels;

569:   /* destroy the labels */
570:   while (next) {
571:     DMLabelLink tmp = next->next;

573:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
574:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
575:     DMLabelDestroy(&next->label);
576:     PetscFree(next);
577:     next = tmp;
578:   }
579:   dm->labels = NULL;
580:   return(0);
581: }

583: /*@
584:     DMDestroy - Destroys a vector packer or DM.

586:     Collective on dm

588:     Input Parameter:
589: .   dm - the DM object to destroy

591:     Level: developer

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

595: @*/
596: PetscErrorCode  DMDestroy(DM *dm)
597: {
598:   PetscInt       cnt;
599:   DMNamedVecLink nlink,nnext;

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

606:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
607:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
608:   --((PetscObject)(*dm))->refct;
609:   if (--cnt > 0) {*dm = 0; return(0);}
610:   if (((PetscObject)(*dm))->refct < 0) return(0);
611:   ((PetscObject)(*dm))->refct = 0;

613:   DMClearGlobalVectors(*dm);
614:   DMClearLocalVectors(*dm);

616:   nnext=(*dm)->namedglobal;
617:   (*dm)->namedglobal = NULL;
618:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
619:     nnext = nlink->next;
620:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
621:     PetscFree(nlink->name);
622:     VecDestroy(&nlink->X);
623:     PetscFree(nlink);
624:   }
625:   nnext=(*dm)->namedlocal;
626:   (*dm)->namedlocal = NULL;
627:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
628:     nnext = nlink->next;
629:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
630:     PetscFree(nlink->name);
631:     VecDestroy(&nlink->X);
632:     PetscFree(nlink);
633:   }

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

697:       next = b->next;
698:       PetscFree(b);
699:     }
700:   }

702:   PetscObjectDestroy(&(*dm)->dmksp);
703:   PetscObjectDestroy(&(*dm)->dmsnes);
704:   PetscObjectDestroy(&(*dm)->dmts);

706:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
707:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
708:   }
709:   MatFDColoringDestroy(&(*dm)->fd);
710:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
711:   PetscFree((*dm)->vectype);
712:   PetscFree((*dm)->mattype);

714:   PetscSectionDestroy(&(*dm)->localSection);
715:   PetscSectionDestroy(&(*dm)->globalSection);
716:   PetscLayoutDestroy(&(*dm)->map);
717:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
718:   MatDestroy(&(*dm)->defaultConstraintMat);
719:   PetscSFDestroy(&(*dm)->sf);
720:   PetscSFDestroy(&(*dm)->sectionSF);
721:   if ((*dm)->useNatural) {
722:     if ((*dm)->sfNatural) {
723:       PetscSFDestroy(&(*dm)->sfNatural);
724:     }
725:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
726:   }
727:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
728:     DMSetFineDM((*dm)->coarseMesh,NULL);
729:   }

731:   DMDestroy(&(*dm)->coarseMesh);
732:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
733:     DMSetCoarseDM((*dm)->fineMesh,NULL);
734:   }
735:   DMDestroy(&(*dm)->fineMesh);
736:   DMFieldDestroy(&(*dm)->coordinateField);
737:   DMDestroy(&(*dm)->coordinateDM);
738:   VecDestroy(&(*dm)->coordinates);
739:   VecDestroy(&(*dm)->coordinatesLocal);
740:   PetscFree((*dm)->L);
741:   PetscFree((*dm)->maxCell);
742:   PetscFree((*dm)->bdtype);
743:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
744:   DMDestroy(&(*dm)->transformDM);
745:   VecDestroy(&(*dm)->transform);

747:   DMClearDS(*dm);
748:   DMDestroy(&(*dm)->dmBC);
749:   /* if memory was published with SAWs then destroy it */
750:   PetscObjectSAWsViewOff((PetscObject)*dm);

752:   if ((*dm)->ops->destroy) {
753:     (*(*dm)->ops->destroy)(*dm);
754:   }
755:   DMMonitorCancel(*dm);
756:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
757:   PetscHeaderDestroy(dm);
758:   return(0);
759: }

761: /*@
762:     DMSetUp - sets up the data structures inside a DM object

764:     Collective on dm

766:     Input Parameter:
767: .   dm - the DM object to setup

769:     Level: developer

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

773: @*/
774: PetscErrorCode  DMSetUp(DM dm)
775: {

780:   if (dm->setupcalled) return(0);
781:   if (dm->ops->setup) {
782:     (*dm->ops->setup)(dm);
783:   }
784:   dm->setupcalled = PETSC_TRUE;
785:   return(0);
786: }

788: /*@
789:     DMSetFromOptions - sets parameters in a DM from the options database

791:     Collective on dm

793:     Input Parameter:
794: .   dm - the DM object to set options for

796:     Options Database:
797: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
798: .   -dm_vec_type <type>  - type of vector to create inside DM
799: .   -dm_mat_type <type>  - type of matrix to create inside DM
800: -   -dm_is_coloring_type - <global or local>

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

811:     Level: intermediate

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

816: @*/
817: PetscErrorCode DMSetFromOptions(DM dm)
818: {
819:   char           typeName[256];
820:   PetscBool      flg;

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

848: /*@C
849:    DMViewFromOptions - View from Options

851:    Collective on DM

853:    Input Parameters:
854: +  dm - the DM object
855: .  obj - Optional object
856: -  name - command line option

858:    Level: intermediate
859: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
860: @*/
861: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
862: {

867:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
868:   return(0);
869: }

871: /*@C
872:     DMView - Views a DM

874:     Collective on dm

876:     Input Parameter:
877: +   dm - the DM object to view
878: -   v - the viewer

880:     Level: beginner

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

884: @*/
885: PetscErrorCode  DMView(DM dm,PetscViewer v)
886: {
887:   PetscErrorCode    ierr;
888:   PetscBool         isbinary;
889:   PetscMPIInt       size;
890:   PetscViewerFormat format;

894:   if (!v) {
895:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
896:   }
898:   /* Ideally, we would like to have this test on.
899:      However, it currently breaks socket viz via GLVis.
900:      During DMView(parallel_mesh,glvis_viewer), each
901:      process opens a sequential ASCII socket to visualize
902:      the local mesh, and PetscObjectView(dm,local_socket)
903:      is internally called inside VecView_GLVis, incurring
904:      in an error here */
906:   PetscViewerCheckWritable(v);

908:   PetscViewerGetFormat(v,&format);
909:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
910:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
911:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
912:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
913:   if (isbinary) {
914:     PetscInt classid = DM_FILE_CLASSID;
915:     char     type[256];

917:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
918:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
919:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
920:   }
921:   if (dm->ops->view) {
922:     (*dm->ops->view)(dm,v);
923:   }
924:   return(0);
925: }

927: /*@
928:     DMCreateGlobalVector - Creates a global vector from a DM object

930:     Collective on dm

932:     Input Parameter:
933: .   dm - the DM object

935:     Output Parameter:
936: .   vec - the global vector

938:     Level: beginner

940: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

942: @*/
943: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
944: {

950:   if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
951:   (*dm->ops->createglobalvector)(dm,vec);
952: #if defined(PETSC_USE_DEBUG)
953:   {
954:     DM vdm;

956:     VecGetDM(*vec,&vdm);
957:     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);
958:   }
959: #endif
960:   return(0);
961: }

963: /*@
964:     DMCreateLocalVector - Creates a local vector from a DM object

966:     Not Collective

968:     Input Parameter:
969: .   dm - the DM object

971:     Output Parameter:
972: .   vec - the local vector

974:     Level: beginner

976: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()

978: @*/
979: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
980: {

986:   if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
987:   (*dm->ops->createlocalvector)(dm,vec);
988: #if defined(PETSC_USE_DEBUG)
989:   {
990:     DM vdm;

992:     VecGetDM(*vec,&vdm);
993:     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);
994:   }
995: #endif
996:   return(0);
997: }

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

1002:    Collective on dm

1004:    Input Parameter:
1005: .  dm - the DM that provides the mapping

1007:    Output Parameter:
1008: .  ltog - the mapping

1010:    Level: intermediate

1012:    Notes:
1013:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1014:    MatSetLocalToGlobalMapping().

1016: .seealso: DMCreateLocalVector()
1017: @*/
1018: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1019: {
1020:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1026:   if (!dm->ltogmap) {
1027:     PetscSection section, sectionGlobal;

1029:     DMGetLocalSection(dm, &section);
1030:     if (section) {
1031:       const PetscInt *cdofs;
1032:       PetscInt       *ltog;
1033:       PetscInt        pStart, pEnd, n, p, k, l;

1035:       DMGetGlobalSection(dm, &sectionGlobal);
1036:       PetscSectionGetChart(section, &pStart, &pEnd);
1037:       PetscSectionGetStorageSize(section, &n);
1038:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1039:       for (p = pStart, l = 0; p < pEnd; ++p) {
1040:         PetscInt bdof, cdof, dof, off, c, cind = 0;

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

1080: /*@
1081:    DMGetBlockSize - Gets the inherent block size associated with a DM

1083:    Not Collective

1085:    Input Parameter:
1086: .  dm - the DM with block structure

1088:    Output Parameter:
1089: .  bs - the block size, 1 implies no exploitable block structure

1091:    Level: intermediate

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

1105: /*@
1106:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1108:     Collective on dmc

1110:     Input Parameter:
1111: +   dmc - the DM object
1112: -   dmf - the second, finer DM object

1114:     Output Parameter:
1115: +  mat - the interpolation
1116: -  vec - the scaling (optional)

1118:     Level: developer

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

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


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

1130: @*/
1131: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1132: {

1139:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
1140:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1141:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1142:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1143:   return(0);
1144: }

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

1149:   Input Parameters:
1150: +      dac - DM that defines a coarse mesh
1151: .      daf - DM that defines a fine mesh
1152: -      mat - the restriction (or interpolation operator) from fine to coarse

1154:   Output Parameter:
1155: .    scale - the scaled vector

1157:   Level: developer

1159: .seealso: DMCreateInterpolation()

1161: @*/
1162: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1163: {
1165:   Vec            fine;
1166:   PetscScalar    one = 1.0;

1169:   DMCreateGlobalVector(daf,&fine);
1170:   DMCreateGlobalVector(dac,scale);
1171:   VecSet(fine,one);
1172:   MatRestrict(mat,fine,*scale);
1173:   VecDestroy(&fine);
1174:   VecReciprocal(*scale);
1175:   return(0);
1176: }

1178: /*@
1179:     DMCreateRestriction - Gets restriction matrix between two DM objects

1181:     Collective on dmc

1183:     Input Parameter:
1184: +   dmc - the DM object
1185: -   dmf - the second, finer DM object

1187:     Output Parameter:
1188: .  mat - the restriction


1191:     Level: developer

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


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

1200: @*/
1201: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1202: {

1209:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
1210:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1211:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1212:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1213:   return(0);
1214: }

1216: /*@
1217:     DMCreateInjection - Gets injection matrix between two DM objects

1219:     Collective on dac

1221:     Input Parameter:
1222: +   dac - the DM object
1223: -   daf - the second, finer DM object

1225:     Output Parameter:
1226: .   mat - the injection

1228:     Level: developer

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

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

1236: @*/
1237: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1238: {

1245:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
1246:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1247:   (*dac->ops->createinjection)(dac,daf,mat);
1248:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1249:   return(0);
1250: }

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

1255:   Collective on dac

1257:   Input Parameter:
1258: + dac - the DM object
1259: - daf - the second, finer DM object

1261:   Output Parameter:
1262: . mat - the interpolation

1264:   Level: developer

1266: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1267: @*/
1268: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
1269: {

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

1281: /*@
1282:     DMCreateColoring - Gets coloring for a DM

1284:     Collective on dm

1286:     Input Parameter:
1287: +   dm - the DM object
1288: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1290:     Output Parameter:
1291: .   coloring - the coloring

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

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

1299:     Level: developer

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

1303: @*/
1304: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1305: {

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

1316: /*@
1317:     DMCreateMatrix - Gets empty Jacobian for a DM

1319:     Collective on dm

1321:     Input Parameter:
1322: .   dm - the DM object

1324:     Output Parameter:
1325: .   mat - the empty Jacobian

1327:     Level: beginner

1329:     Notes:
1330:     This properly preallocates the number of nonzeros in the sparse matrix so you
1331:        do not need to do it yourself.

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

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

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

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

1344: @*/
1345: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1346: {

1352:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1353:   MatInitializePackage();
1354:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1355:   (*dm->ops->creatematrix)(dm,mat);
1356: #if defined(PETSC_USE_DEBUG)
1357:   {
1358:     DM mdm;

1360:     MatGetDM(*mat,&mdm);
1361:     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);
1362:   }
1363: #endif
1364:   /* Handle nullspace and near nullspace */
1365:   if (dm->Nf) {
1366:     MatNullSpace nullSpace;
1367:     PetscInt     Nf;

1369:     DMGetNumFields(dm, &Nf);
1370:     if (Nf == 1) {
1371:       if (dm->nullspaceConstructors[0]) {
1372:         (*dm->nullspaceConstructors[0])(dm, 0, &nullSpace);
1373:         MatSetNullSpace(*mat, nullSpace);
1374:         MatNullSpaceDestroy(&nullSpace);
1375:       }
1376:       if (dm->nearnullspaceConstructors[0]) {
1377:         (*dm->nearnullspaceConstructors[0])(dm, 0, &nullSpace);
1378:         MatSetNearNullSpace(*mat, nullSpace);
1379:         MatNullSpaceDestroy(&nullSpace);
1380:       }
1381:     }
1382:   }
1383:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1384:   return(0);
1385: }

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

1391:   Logically Collective on dm

1393:   Input Parameter:
1394: + dm - the DM
1395: - only - PETSC_TRUE if only want preallocation

1397:   Level: developer
1398: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1399: @*/
1400: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1401: {
1404:   dm->prealloc_only = only;
1405:   return(0);
1406: }

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

1412:   Logically Collective on dm

1414:   Input Parameter:
1415: + dm - the DM
1416: - only - PETSC_TRUE if only want matrix stucture

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

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

1432:   Not Collective

1434:   Input Parameters:
1435: + dm - the DM object
1436: . count - The minium size
1437: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1439:   Output Parameter:
1440: . array - the work array

1442:   Level: developer

1444: .seealso DMDestroy(), DMCreate()
1445: @*/
1446: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1447: {
1449:   DMWorkLink     link;
1450:   PetscMPIInt    dsize;

1455:   if (dm->workin) {
1456:     link       = dm->workin;
1457:     dm->workin = dm->workin->next;
1458:   } else {
1459:     PetscNewLog(dm,&link);
1460:   }
1461:   MPI_Type_size(dtype,&dsize);
1462:   if (((size_t)dsize*count) > link->bytes) {
1463:     PetscFree(link->mem);
1464:     PetscMalloc(dsize*count,&link->mem);
1465:     link->bytes = dsize*count;
1466:   }
1467:   link->next   = dm->workout;
1468:   dm->workout  = link;
1469:   *(void**)mem = link->mem;
1470:   return(0);
1471: }

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

1476:   Not Collective

1478:   Input Parameters:
1479: + dm - the DM object
1480: . count - The minium size
1481: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1483:   Output Parameter:
1484: . array - the work array

1486:   Level: developer

1488:   Developer Notes:
1489:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1490: .seealso DMDestroy(), DMCreate()
1491: @*/
1492: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1493: {
1494:   DMWorkLink *p,link;

1499:   for (p=&dm->workout; (link=*p); p=&link->next) {
1500:     if (link->mem == *(void**)mem) {
1501:       *p           = link->next;
1502:       link->next   = dm->workin;
1503:       dm->workin   = link;
1504:       *(void**)mem = NULL;
1505:       return(0);
1506:     }
1507:   }
1508:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1509: }

1511: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1512: {
1515:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1516:   dm->nullspaceConstructors[field] = nullsp;
1517:   return(0);
1518: }

1520: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1521: {
1525:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1526:   *nullsp = dm->nullspaceConstructors[field];
1527:   return(0);
1528: }

1530: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1531: {
1534:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1535:   dm->nearnullspaceConstructors[field] = nullsp;
1536:   return(0);
1537: }

1539: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1540: {
1544:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1545:   *nullsp = dm->nearnullspaceConstructors[field];
1546:   return(0);
1547: }

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

1552:   Not collective

1554:   Input Parameter:
1555: . dm - the DM object

1557:   Output Parameters:
1558: + numFields  - The number of fields (or NULL if not requested)
1559: . fieldNames - The name for each field (or NULL if not requested)
1560: - fields     - The global indices for each field (or NULL if not requested)

1562:   Level: intermediate

1564:   Notes:
1565:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1566:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1567:   PetscFree().

1569: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1570: @*/
1571: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1572: {
1573:   PetscSection   section, sectionGlobal;

1578:   if (numFields) {
1580:     *numFields = 0;
1581:   }
1582:   if (fieldNames) {
1584:     *fieldNames = NULL;
1585:   }
1586:   if (fields) {
1588:     *fields = NULL;
1589:   }
1590:   DMGetLocalSection(dm, &section);
1591:   if (section) {
1592:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1593:     PetscInt nF, f, pStart, pEnd, p;

1595:     DMGetGlobalSection(dm, &sectionGlobal);
1596:     PetscSectionGetNumFields(section, &nF);
1597:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1598:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1599:     for (f = 0; f < nF; ++f) {
1600:       fieldSizes[f] = 0;
1601:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1602:     }
1603:     for (p = pStart; p < pEnd; ++p) {
1604:       PetscInt gdof;

1606:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1607:       if (gdof > 0) {
1608:         for (f = 0; f < nF; ++f) {
1609:           PetscInt fdof, fcdof, fpdof;

1611:           PetscSectionGetFieldDof(section, p, f, &fdof);
1612:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1613:           fpdof = fdof-fcdof;
1614:           if (fpdof && fpdof != fieldNc[f]) {
1615:             /* Layout does not admit a pointwise block size */
1616:             fieldNc[f] = 1;
1617:           }
1618:           fieldSizes[f] += fpdof;
1619:         }
1620:       }
1621:     }
1622:     for (f = 0; f < nF; ++f) {
1623:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1624:       fieldSizes[f] = 0;
1625:     }
1626:     for (p = pStart; p < pEnd; ++p) {
1627:       PetscInt gdof, goff;

1629:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1630:       if (gdof > 0) {
1631:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1632:         for (f = 0; f < nF; ++f) {
1633:           PetscInt fdof, fcdof, fc;

1635:           PetscSectionGetFieldDof(section, p, f, &fdof);
1636:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1637:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1638:             fieldIndices[f][fieldSizes[f]] = goff++;
1639:           }
1640:         }
1641:       }
1642:     }
1643:     if (numFields) *numFields = nF;
1644:     if (fieldNames) {
1645:       PetscMalloc1(nF, fieldNames);
1646:       for (f = 0; f < nF; ++f) {
1647:         const char *fieldName;

1649:         PetscSectionGetFieldName(section, f, &fieldName);
1650:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1651:       }
1652:     }
1653:     if (fields) {
1654:       PetscMalloc1(nF, fields);
1655:       for (f = 0; f < nF; ++f) {
1656:         PetscInt bs, in[2], out[2];

1658:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1659:         in[0] = -fieldNc[f];
1660:         in[1] = fieldNc[f];
1661:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1662:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1663:         ISSetBlockSize((*fields)[f], bs);
1664:       }
1665:     }
1666:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1667:   } else if (dm->ops->createfieldis) {
1668:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1669:   }
1670:   return(0);
1671: }


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

1680:   Not collective

1682:   Input Parameter:
1683: . dm - the DM object

1685:   Output Parameters:
1686: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1687: . namelist  - The name for each field (or NULL if not requested)
1688: . islist    - The global indices for each field (or NULL if not requested)
1689: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1691:   Level: intermediate

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

1698: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1699: @*/
1700: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1701: {

1706:   if (len) {
1708:     *len = 0;
1709:   }
1710:   if (namelist) {
1712:     *namelist = 0;
1713:   }
1714:   if (islist) {
1716:     *islist = 0;
1717:   }
1718:   if (dmlist) {
1720:     *dmlist = 0;
1721:   }
1722:   /*
1723:    Is it a good idea to apply the following check across all impls?
1724:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1725:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1726:    */
1727:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1728:   if (!dm->ops->createfielddecomposition) {
1729:     PetscSection section;
1730:     PetscInt     numFields, f;

1732:     DMGetLocalSection(dm, &section);
1733:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1734:     if (section && numFields && dm->ops->createsubdm) {
1735:       if (len) *len = numFields;
1736:       if (namelist) {PetscMalloc1(numFields,namelist);}
1737:       if (islist)   {PetscMalloc1(numFields,islist);}
1738:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1739:       for (f = 0; f < numFields; ++f) {
1740:         const char *fieldName;

1742:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1743:         if (namelist) {
1744:           PetscSectionGetFieldName(section, f, &fieldName);
1745:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1746:         }
1747:       }
1748:     } else {
1749:       DMCreateFieldIS(dm, len, namelist, islist);
1750:       /* By default there are no DMs associated with subproblems. */
1751:       if (dmlist) *dmlist = NULL;
1752:     }
1753:   } else {
1754:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1755:   }
1756:   return(0);
1757: }

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

1763:   Not collective

1765:   Input Parameters:
1766: + dm        - The DM object
1767: . numFields - The number of fields in this subproblem
1768: - fields    - The field numbers of the selected fields

1770:   Output Parameters:
1771: + is - The global indices for the subproblem
1772: - subdm - The DM for the subproblem

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

1776:   Level: intermediate

1778: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1779: @*/
1780: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1781: {

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

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

1797:   Not collective

1799:   Input Parameter:
1800: + dms - The DM objects
1801: - len - The number of DMs

1803:   Output Parameters:
1804: + is - The global indices for the subproblem, or NULL
1805: - superdm - The DM for the superproblem

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

1809:   Level: intermediate

1811: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1812: @*/
1813: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1814: {
1815:   PetscInt       i;

1823:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1824:   if (len) {
1825:     DM dm = dms[0];
1826:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1827:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1828:   }
1829:   return(0);
1830: }


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

1840:   Not collective

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

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

1852:   Level: intermediate

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

1859: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1860: @*/
1861: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1862: {
1863:   PetscErrorCode      ierr;
1864:   DMSubDomainHookLink link;
1865:   PetscInt            i,l;

1874:   /*
1875:    Is it a good idea to apply the following check across all impls?
1876:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1877:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1878:    */
1879:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1880:   if (dm->ops->createdomaindecomposition) {
1881:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1882:     /* copy subdomain hooks and context over to the subdomain DMs */
1883:     if (dmlist && *dmlist) {
1884:       for (i = 0; i < l; i++) {
1885:         for (link=dm->subdomainhook; link; link=link->next) {
1886:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1887:         }
1888:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1889:       }
1890:     }
1891:     if (len) *len = l;
1892:   }
1893:   return(0);
1894: }


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

1900:   Not collective

1902:   Input Parameters:
1903: + dm - the DM object
1904: . n  - the number of subdomain scatters
1905: - subdms - the local subdomains

1907:   Output Parameters:
1908: + n     - the number of scatters returned
1909: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1910: . oscat - scatter from global vector to overlapping global vector entries on subdomain
1911: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

1919:   Level: developer

1921: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1922: @*/
1923: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1924: {

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

1935: /*@
1936:   DMRefine - Refines a DM object

1938:   Collective on dm

1940:   Input Parameter:
1941: + dm   - the DM object
1942: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

1944:   Output Parameter:
1945: . dmf - the refined DM, or NULL

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

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

1952:   Level: developer

1954: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1955: @*/
1956: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1957: {
1958:   PetscErrorCode   ierr;
1959:   DMRefineHookLink link;

1963:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
1964:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
1965:   (*dm->ops->refine)(dm,comm,dmf);
1966:   if (*dmf) {
1967:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

1971:     (*dmf)->ctx       = dm->ctx;
1972:     (*dmf)->leveldown = dm->leveldown;
1973:     (*dmf)->levelup   = dm->levelup + 1;

1975:     DMSetMatType(*dmf,dm->mattype);
1976:     for (link=dm->refinehook; link; link=link->next) {
1977:       if (link->refinehook) {
1978:         (*link->refinehook)(dm,*dmf,link->ctx);
1979:       }
1980:     }
1981:   }
1982:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
1983:   return(0);
1984: }

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

1989:    Logically Collective

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

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

2000: +  coarse - coarse level DM
2001: .  fine - fine level DM to interpolate problem to
2002: -  ctx - optional user-defined function context

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

2007: +  coarse - coarse level DM
2008: .  interp - matrix interpolating a coarse-level solution to the finer grid
2009: .  fine - fine level DM to update
2010: -  ctx - optional user-defined function context

2012:    Level: advanced

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

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

2019:    This function is currently not available from Fortran.

2021: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2022: @*/
2023: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2024: {
2025:   PetscErrorCode   ierr;
2026:   DMRefineHookLink link,*p;

2030:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2031:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2032:   }
2033:   PetscNew(&link);
2034:   link->refinehook = refinehook;
2035:   link->interphook = interphook;
2036:   link->ctx        = ctx;
2037:   link->next       = NULL;
2038:   *p               = link;
2039:   return(0);
2040: }

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

2045:    Logically Collective

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

2053:    Level: advanced

2055:    Notes:
2056:    This function does nothing if the hook is not in the list.

2058:    This function is currently not available from Fortran.

2060: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2061: @*/
2062: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2063: {
2064:   PetscErrorCode   ierr;
2065:   DMRefineHookLink link,*p;

2069:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2070:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2071:       link = *p;
2072:       *p = link->next;
2073:       PetscFree(link);
2074:       break;
2075:     }
2076:   }
2077:   return(0);
2078: }

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

2083:    Collective if any hooks are

2085:    Input Arguments:
2086: +  coarse - coarser DM to use as a base
2087: .  interp - interpolation matrix, apply using MatInterpolate()
2088: -  fine - finer DM to update

2090:    Level: developer

2092: .seealso: DMRefineHookAdd(), MatInterpolate()
2093: @*/
2094: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2095: {
2096:   PetscErrorCode   ierr;
2097:   DMRefineHookLink link;

2100:   for (link=fine->refinehook; link; link=link->next) {
2101:     if (link->interphook) {
2102:       (*link->interphook)(coarse,interp,fine,link->ctx);
2103:     }
2104:   }
2105:   return(0);
2106: }

2108: /*@
2109:     DMGetRefineLevel - Get's the number of refinements that have generated this DM.

2111:     Not Collective

2113:     Input Parameter:
2114: .   dm - the DM object

2116:     Output Parameter:
2117: .   level - number of refinements

2119:     Level: developer

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

2123: @*/
2124: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2125: {
2128:   *level = dm->levelup;
2129:   return(0);
2130: }

2132: /*@
2133:     DMSetRefineLevel - Set's the number of refinements that have generated this DM.

2135:     Not Collective

2137:     Input Parameter:
2138: +   dm - the DM object
2139: -   level - number of refinements

2141:     Level: advanced

2143:     Notes:
2144:     This value is used by PCMG to determine how many multigrid levels to use

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

2148: @*/
2149: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2150: {
2153:   dm->levelup = level;
2154:   return(0);
2155: }

2157: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2158: {
2162:   *tdm = dm->transformDM;
2163:   return(0);
2164: }

2166: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2167: {
2171:   *tv = dm->transform;
2172:   return(0);
2173: }

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

2178:   Input Parameter:
2179: . dm - The DM

2181:   Output Parameter:
2182: . flg - PETSC_TRUE if a basis transformation should be done

2184:   Level: developer

2186: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()()
2187: @*/
2188: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2189: {
2190:   Vec            tv;

2196:   DMGetBasisTransformVec_Internal(dm, &tv);
2197:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2198:   return(0);
2199: }

2201: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2202: {
2203:   PetscSection   s, ts;
2204:   PetscScalar   *ta;
2205:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2209:   DMGetCoordinateDim(dm, &cdim);
2210:   DMGetLocalSection(dm, &s);
2211:   PetscSectionGetChart(s, &pStart, &pEnd);
2212:   PetscSectionGetNumFields(s, &Nf);
2213:   DMClone(dm, &dm->transformDM);
2214:   DMGetLocalSection(dm->transformDM, &ts);
2215:   PetscSectionSetNumFields(ts, Nf);
2216:   PetscSectionSetChart(ts, pStart, pEnd);
2217:   for (f = 0; f < Nf; ++f) {
2218:     PetscSectionGetFieldComponents(s, f, &Nc);
2219:     /* We could start to label fields by their transformation properties */
2220:     if (Nc != cdim) continue;
2221:     for (p = pStart; p < pEnd; ++p) {
2222:       PetscSectionGetFieldDof(s, p, f, &dof);
2223:       if (!dof) continue;
2224:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2225:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2226:     }
2227:   }
2228:   PetscSectionSetUp(ts);
2229:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2230:   VecGetArray(dm->transform, &ta);
2231:   for (p = pStart; p < pEnd; ++p) {
2232:     for (f = 0; f < Nf; ++f) {
2233:       PetscSectionGetFieldDof(ts, p, f, &dof);
2234:       if (dof) {
2235:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2236:         PetscScalar       *tva;
2237:         const PetscScalar *A;

2239:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2240:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2241:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2242:         PetscArraycpy(tva, A, PetscSqr(cdim));
2243:       }
2244:     }
2245:   }
2246:   VecRestoreArray(dm->transform, &ta);
2247:   return(0);
2248: }

2250: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2251: {

2257:   newdm->transformCtx       = dm->transformCtx;
2258:   newdm->transformSetUp     = dm->transformSetUp;
2259:   newdm->transformDestroy   = NULL;
2260:   newdm->transformGetMatrix = dm->transformGetMatrix;
2261:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2262:   return(0);
2263: }

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

2268:    Logically Collective

2270:    Input Arguments:
2271: +  dm - the DM
2272: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2273: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2274: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2279: +  dm - global DM
2280: .  g - global vector
2281: .  mode - mode
2282: .  l - local vector
2283: -  ctx - optional user-defined function context


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

2289: +  global - global DM
2290: -  ctx - optional user-defined function context

2292:    Level: advanced

2294: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2295: @*/
2296: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2297: {
2298:   PetscErrorCode          ierr;
2299:   DMGlobalToLocalHookLink link,*p;

2303:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2304:   PetscNew(&link);
2305:   link->beginhook = beginhook;
2306:   link->endhook   = endhook;
2307:   link->ctx       = ctx;
2308:   link->next      = NULL;
2309:   *p              = link;
2310:   return(0);
2311: }

2313: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2314: {
2315:   Mat cMat;
2316:   Vec cVec;
2317:   PetscSection section, cSec;
2318:   PetscInt pStart, pEnd, p, dof;

2323:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2324:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2325:     PetscInt nRows;

2327:     MatGetSize(cMat,&nRows,NULL);
2328:     if (nRows <= 0) return(0);
2329:     DMGetLocalSection(dm,&section);
2330:     MatCreateVecs(cMat,NULL,&cVec);
2331:     MatMult(cMat,l,cVec);
2332:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2333:     for (p = pStart; p < pEnd; p++) {
2334:       PetscSectionGetDof(cSec,p,&dof);
2335:       if (dof) {
2336:         PetscScalar *vals;
2337:         VecGetValuesSection(cVec,cSec,p,&vals);
2338:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2339:       }
2340:     }
2341:     VecDestroy(&cVec);
2342:   }
2343:   return(0);
2344: }

2346: /*@
2347:     DMGlobalToLocal - update local vectors from global vector

2349:     Neighbor-wise Collective on dm

2351:     Input Parameters:
2352: +   dm - the DM object
2353: .   g - the global vector
2354: .   mode - INSERT_VALUES or ADD_VALUES
2355: -   l - the local vector

2357:     Notes:
2358:     The communication involved in this update can be overlapped with computation by using
2359:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2361:     Level: beginner

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

2365: @*/
2366: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2367: {

2371:   DMGlobalToLocalBegin(dm,g,mode,l);
2372:   DMGlobalToLocalEnd(dm,g,mode,l);
2373:   return(0);
2374: }

2376: /*@
2377:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2379:     Neighbor-wise Collective on dm

2381:     Input Parameters:
2382: +   dm - the DM object
2383: .   g - the global vector
2384: .   mode - INSERT_VALUES or ADD_VALUES
2385: -   l - the local vector

2387:     Level: intermediate

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

2391: @*/
2392: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2393: {
2394:   PetscSF                 sf;
2395:   PetscErrorCode          ierr;
2396:   DMGlobalToLocalHookLink link;

2400:   for (link=dm->gtolhook; link; link=link->next) {
2401:     if (link->beginhook) {
2402:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2403:     }
2404:   }
2405:   DMGetSectionSF(dm, &sf);
2406:   if (sf) {
2407:     const PetscScalar *gArray;
2408:     PetscScalar       *lArray;

2410:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2411:     VecGetArrayInPlace(l, &lArray);
2412:     VecGetArrayReadInPlace(g, &gArray);
2413:     PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
2414:     VecRestoreArrayInPlace(l, &lArray);
2415:     VecRestoreArrayReadInPlace(g, &gArray);
2416:   } else {
2417:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2418:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2419:   }
2420:   return(0);
2421: }

2423: /*@
2424:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2426:     Neighbor-wise Collective on dm

2428:     Input Parameters:
2429: +   dm - the DM object
2430: .   g - the global vector
2431: .   mode - INSERT_VALUES or ADD_VALUES
2432: -   l - the local vector

2434:     Level: intermediate

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

2438: @*/
2439: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2440: {
2441:   PetscSF                 sf;
2442:   PetscErrorCode          ierr;
2443:   const PetscScalar      *gArray;
2444:   PetscScalar            *lArray;
2445:   PetscBool               transform;
2446:   DMGlobalToLocalHookLink link;

2450:   DMGetSectionSF(dm, &sf);
2451:   DMHasBasisTransform(dm, &transform);
2452:   if (sf) {
2453:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2455:     VecGetArrayInPlace(l, &lArray);
2456:     VecGetArrayReadInPlace(g, &gArray);
2457:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2458:     VecRestoreArrayInPlace(l, &lArray);
2459:     VecRestoreArrayReadInPlace(g, &gArray);
2460:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2461:   } else {
2462:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2463:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2464:   }
2465:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2466:   for (link=dm->gtolhook; link; link=link->next) {
2467:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2468:   }
2469:   return(0);
2470: }

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

2475:    Logically Collective

2477:    Input Arguments:
2478: +  dm - the DM
2479: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2480: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2481: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2486: +  dm - global DM
2487: .  l - local vector
2488: .  mode - mode
2489: .  g - global vector
2490: -  ctx - optional user-defined function context


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

2496: +  global - global DM
2497: .  l - local vector
2498: .  mode - mode
2499: .  g - global vector
2500: -  ctx - optional user-defined function context

2502:    Level: advanced

2504: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2505: @*/
2506: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2507: {
2508:   PetscErrorCode          ierr;
2509:   DMLocalToGlobalHookLink link,*p;

2513:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2514:   PetscNew(&link);
2515:   link->beginhook = beginhook;
2516:   link->endhook   = endhook;
2517:   link->ctx       = ctx;
2518:   link->next      = NULL;
2519:   *p              = link;
2520:   return(0);
2521: }

2523: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2524: {
2525:   Mat cMat;
2526:   Vec cVec;
2527:   PetscSection section, cSec;
2528:   PetscInt pStart, pEnd, p, dof;

2533:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2534:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2535:     PetscInt nRows;

2537:     MatGetSize(cMat,&nRows,NULL);
2538:     if (nRows <= 0) return(0);
2539:     DMGetLocalSection(dm,&section);
2540:     MatCreateVecs(cMat,NULL,&cVec);
2541:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2542:     for (p = pStart; p < pEnd; p++) {
2543:       PetscSectionGetDof(cSec,p,&dof);
2544:       if (dof) {
2545:         PetscInt d;
2546:         PetscScalar *vals;
2547:         VecGetValuesSection(l,section,p,&vals);
2548:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2549:         /* for this to be the true transpose, we have to zero the values that
2550:          * we just extracted */
2551:         for (d = 0; d < dof; d++) {
2552:           vals[d] = 0.;
2553:         }
2554:       }
2555:     }
2556:     MatMultTransposeAdd(cMat,cVec,l,l);
2557:     VecDestroy(&cVec);
2558:   }
2559:   return(0);
2560: }
2561: /*@
2562:     DMLocalToGlobal - updates global vectors from local vectors

2564:     Neighbor-wise Collective on dm

2566:     Input Parameters:
2567: +   dm - the DM object
2568: .   l - the local vector
2569: .   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.
2570: -   g - the global vector

2572:     Notes:
2573:     The communication involved in this update can be overlapped with computation by using
2574:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2579:     Level: beginner

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

2583: @*/
2584: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2585: {

2589:   DMLocalToGlobalBegin(dm,l,mode,g);
2590:   DMLocalToGlobalEnd(dm,l,mode,g);
2591:   return(0);
2592: }

2594: /*@
2595:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2597:     Neighbor-wise Collective on dm

2599:     Input Parameters:
2600: +   dm - the DM object
2601: .   l - the local vector
2602: .   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.
2603: -   g - the global vector

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

2609:     Level: intermediate

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

2613: @*/
2614: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2615: {
2616:   PetscSF                 sf;
2617:   PetscSection            s, gs;
2618:   DMLocalToGlobalHookLink link;
2619:   Vec                     tmpl;
2620:   const PetscScalar      *lArray;
2621:   PetscScalar            *gArray;
2622:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2623:   PetscErrorCode          ierr;

2627:   for (link=dm->ltoghook; link; link=link->next) {
2628:     if (link->beginhook) {
2629:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2630:     }
2631:   }
2632:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2633:   DMGetSectionSF(dm, &sf);
2634:   DMGetLocalSection(dm, &s);
2635:   switch (mode) {
2636:   case INSERT_VALUES:
2637:   case INSERT_ALL_VALUES:
2638:   case INSERT_BC_VALUES:
2639:     isInsert = PETSC_TRUE; break;
2640:   case ADD_VALUES:
2641:   case ADD_ALL_VALUES:
2642:   case ADD_BC_VALUES:
2643:     isInsert = PETSC_FALSE; break;
2644:   default:
2645:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2646:   }
2647:   if ((sf && !isInsert) || (s && isInsert)) {
2648:     DMHasBasisTransform(dm, &transform);
2649:     if (transform) {
2650:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2651:       VecCopy(l, tmpl);
2652:       DMPlexLocalToGlobalBasis(dm, tmpl);
2653:       VecGetArrayRead(tmpl, &lArray);
2654:     } else if (isInsert) {
2655:       VecGetArrayRead(l, &lArray);
2656:     } else {
2657:       VecGetArrayReadInPlace(l, &lArray);
2658:       l_inplace = PETSC_TRUE;
2659:     }
2660:     if (s && isInsert) {
2661:       VecGetArray(g, &gArray);
2662:     } else {
2663:       VecGetArrayInPlace(g, &gArray);
2664:       g_inplace = PETSC_TRUE;
2665:     }
2666:     if (sf && !isInsert) {
2667:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2668:     } else if (s && isInsert) {
2669:       PetscInt gStart, pStart, pEnd, p;

2671:       DMGetGlobalSection(dm, &gs);
2672:       PetscSectionGetChart(s, &pStart, &pEnd);
2673:       VecGetOwnershipRange(g, &gStart, NULL);
2674:       for (p = pStart; p < pEnd; ++p) {
2675:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2677:         PetscSectionGetDof(s, p, &dof);
2678:         PetscSectionGetDof(gs, p, &gdof);
2679:         PetscSectionGetConstraintDof(s, p, &cdof);
2680:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2681:         PetscSectionGetOffset(s, p, &off);
2682:         PetscSectionGetOffset(gs, p, &goff);
2683:         /* Ignore off-process data and points with no global data */
2684:         if (!gdof || goff < 0) continue;
2685:         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);
2686:         /* If no constraints are enforced in the global vector */
2687:         if (!gcdof) {
2688:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2689:           /* If constraints are enforced in the global vector */
2690:         } else if (cdof == gcdof) {
2691:           const PetscInt *cdofs;
2692:           PetscInt        cind = 0;

2694:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2695:           for (d = 0, e = 0; d < dof; ++d) {
2696:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2697:             gArray[goff-gStart+e++] = lArray[off+d];
2698:           }
2699:         } 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);
2700:       }
2701:     }
2702:     if (g_inplace) {
2703:       VecRestoreArrayInPlace(g, &gArray);
2704:     } else {
2705:       VecRestoreArray(g, &gArray);
2706:     }
2707:     if (transform) {
2708:       VecRestoreArrayRead(tmpl, &lArray);
2709:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2710:     } else if (l_inplace) {
2711:       VecRestoreArrayReadInPlace(l, &lArray);
2712:     } else {
2713:       VecRestoreArrayRead(l, &lArray);
2714:     }
2715:   } else {
2716:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2717:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2718:   }
2719:   return(0);
2720: }

2722: /*@
2723:     DMLocalToGlobalEnd - 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 - INSERT_VALUES or ADD_VALUES
2731: -   g - the global vector

2733:     Level: intermediate

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

2737: @*/
2738: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2739: {
2740:   PetscSF                 sf;
2741:   PetscSection            s;
2742:   DMLocalToGlobalHookLink link;
2743:   PetscBool               isInsert, transform;
2744:   PetscErrorCode          ierr;

2748:   DMGetSectionSF(dm, &sf);
2749:   DMGetLocalSection(dm, &s);
2750:   switch (mode) {
2751:   case INSERT_VALUES:
2752:   case INSERT_ALL_VALUES:
2753:     isInsert = PETSC_TRUE; break;
2754:   case ADD_VALUES:
2755:   case ADD_ALL_VALUES:
2756:     isInsert = PETSC_FALSE; break;
2757:   default:
2758:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2759:   }
2760:   if (sf && !isInsert) {
2761:     const PetscScalar *lArray;
2762:     PetscScalar       *gArray;
2763:     Vec                tmpl;

2765:     DMHasBasisTransform(dm, &transform);
2766:     if (transform) {
2767:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2768:       VecGetArrayRead(tmpl, &lArray);
2769:     } else {
2770:       VecGetArrayReadInPlace(l, &lArray);
2771:     }
2772:     VecGetArrayInPlace(g, &gArray);
2773:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2774:     if (transform) {
2775:       VecRestoreArrayRead(tmpl, &lArray);
2776:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2777:     } else {
2778:       VecRestoreArrayReadInPlace(l, &lArray);
2779:     }
2780:     VecRestoreArrayInPlace(g, &gArray);
2781:   } else if (s && isInsert) {
2782:   } else {
2783:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2784:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2785:   }
2786:   for (link=dm->ltoghook; link; link=link->next) {
2787:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2788:   }
2789:   return(0);
2790: }

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

2797:    Neighbor-wise Collective on dm

2799:    Input Parameters:
2800: +  dm - the DM object
2801: .  g - the original local vector
2802: -  mode - one of INSERT_VALUES or ADD_VALUES

2804:    Output Parameter:
2805: .  l  - the local vector with correct ghost values

2807:    Level: intermediate

2809:    Notes:
2810:    The local vectors used here need not be the same as those
2811:    obtained from DMCreateLocalVector(), BUT they
2812:    must have the same parallel data layout; they could, for example, be
2813:    obtained with VecDuplicate() from the DM originating vectors.

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

2817: @*/
2818: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2819: {
2820:   PetscErrorCode          ierr;

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

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

2834:    Neighbor-wise Collective on dm

2836:    Input Parameters:
2837: +  da - the DM object
2838: .  g - the original local vector
2839: -  mode - one of INSERT_VALUES or ADD_VALUES

2841:    Output Parameter:
2842: .  l  - the local vector with correct ghost values

2844:    Level: intermediate

2846:    Notes:
2847:    The local vectors used here need not be the same as those
2848:    obtained from DMCreateLocalVector(), BUT they
2849:    must have the same parallel data layout; they could, for example, be
2850:    obtained with VecDuplicate() from the DM originating vectors.

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

2854: @*/
2855: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2856: {
2857:   PetscErrorCode          ierr;

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


2867: /*@
2868:     DMCoarsen - Coarsens a DM object

2870:     Collective on dm

2872:     Input Parameter:
2873: +   dm - the DM object
2874: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2876:     Output Parameter:
2877: .   dmc - the coarsened DM

2879:     Level: developer

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

2883: @*/
2884: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2885: {
2886:   PetscErrorCode    ierr;
2887:   DMCoarsenHookLink link;

2891:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
2892:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2893:   (*dm->ops->coarsen)(dm, comm, dmc);
2894:   if (*dmc) {
2895:     DMSetCoarseDM(dm,*dmc);
2896:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2897:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2898:     (*dmc)->ctx               = dm->ctx;
2899:     (*dmc)->levelup           = dm->levelup;
2900:     (*dmc)->leveldown         = dm->leveldown + 1;
2901:     DMSetMatType(*dmc,dm->mattype);
2902:     for (link=dm->coarsenhook; link; link=link->next) {
2903:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2904:     }
2905:   }
2906:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
2907:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2908:   return(0);
2909: }

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

2914:    Logically Collective

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

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

2925: +  fine - fine level DM
2926: .  coarse - coarse level DM to restrict problem to
2927: -  ctx - optional user-defined function context

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

2932: +  fine - fine level DM
2933: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2934: .  rscale - scaling vector for restriction
2935: .  inject - matrix restricting by injection
2936: .  coarse - coarse level DM to update
2937: -  ctx - optional user-defined function context

2939:    Level: advanced

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

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

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

2949:    This function is currently not available from Fortran.

2951: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2952: @*/
2953: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2954: {
2955:   PetscErrorCode    ierr;
2956:   DMCoarsenHookLink link,*p;

2960:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2961:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2962:   }
2963:   PetscNew(&link);
2964:   link->coarsenhook  = coarsenhook;
2965:   link->restricthook = restricthook;
2966:   link->ctx          = ctx;
2967:   link->next         = NULL;
2968:   *p                 = link;
2969:   return(0);
2970: }

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

2975:    Logically Collective

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

2983:    Level: advanced

2985:    Notes:
2986:    This function does nothing if the hook is not in the list.

2988:    This function is currently not available from Fortran.

2990: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2991: @*/
2992: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2993: {
2994:   PetscErrorCode    ierr;
2995:   DMCoarsenHookLink link,*p;

2999:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3000:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3001:       link = *p;
3002:       *p = link->next;
3003:       PetscFree(link);
3004:       break;
3005:     }
3006:   }
3007:   return(0);
3008: }


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

3014:    Collective if any hooks are

3016:    Input Arguments:
3017: +  fine - finer DM to use as a base
3018: .  restrct - restriction matrix, apply using MatRestrict()
3019: .  rscale - scaling vector for restriction
3020: .  inject - injection matrix, also use MatRestrict()
3021: -  coarse - coarser DM to update

3023:    Level: developer

3025: .seealso: DMCoarsenHookAdd(), MatRestrict()
3026: @*/
3027: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3028: {
3029:   PetscErrorCode    ierr;
3030:   DMCoarsenHookLink link;

3033:   for (link=fine->coarsenhook; link; link=link->next) {
3034:     if (link->restricthook) {
3035:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3036:     }
3037:   }
3038:   return(0);
3039: }

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

3044:    Logically Collective on global

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


3053:    Calling sequence for ddhook:
3054: $    ddhook(DM global,DM block,void *ctx)

3056: +  global - global DM
3057: .  block  - block DM
3058: -  ctx - optional user-defined function context

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

3063: +  global - global DM
3064: .  out    - scatter to the outer (with ghost and overlap points) block vector
3065: .  in     - scatter to block vector values only owned locally
3066: .  block  - block DM
3067: -  ctx - optional user-defined function context

3069:    Level: advanced

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

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

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

3079:    This function is currently not available from Fortran.

3081: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3082: @*/
3083: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3084: {
3085:   PetscErrorCode      ierr;
3086:   DMSubDomainHookLink link,*p;

3090:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3091:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3092:   }
3093:   PetscNew(&link);
3094:   link->restricthook = restricthook;
3095:   link->ddhook       = ddhook;
3096:   link->ctx          = ctx;
3097:   link->next         = NULL;
3098:   *p                 = link;
3099:   return(0);
3100: }

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

3105:    Logically Collective

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

3113:    Level: advanced

3115:    Notes:

3117:    This function is currently not available from Fortran.

3119: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3120: @*/
3121: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3122: {
3123:   PetscErrorCode      ierr;
3124:   DMSubDomainHookLink link,*p;

3128:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3129:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3130:       link = *p;
3131:       *p = link->next;
3132:       PetscFree(link);
3133:       break;
3134:     }
3135:   }
3136:   return(0);
3137: }

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

3142:    Collective if any hooks are

3144:    Input Arguments:
3145: +  fine - finer DM to use as a base
3146: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3147: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3148: -  coarse - coarer DM to update

3150:    Level: developer

3152: .seealso: DMCoarsenHookAdd(), MatRestrict()
3153: @*/
3154: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3155: {
3156:   PetscErrorCode      ierr;
3157:   DMSubDomainHookLink link;

3160:   for (link=global->subdomainhook; link; link=link->next) {
3161:     if (link->restricthook) {
3162:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3163:     }
3164:   }
3165:   return(0);
3166: }

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

3171:     Not Collective

3173:     Input Parameter:
3174: .   dm - the DM object

3176:     Output Parameter:
3177: .   level - number of coarsenings

3179:     Level: developer

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

3183: @*/
3184: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3185: {
3189:   *level = dm->leveldown;
3190:   return(0);
3191: }

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

3196:     Not Collective

3198:     Input Parameters:
3199: +   dm - the DM object
3200: -   level - number of coarsenings

3202:     Level: developer

3204: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3205: @*/
3206: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3207: {
3210:   dm->leveldown = level;
3211:   return(0);
3212: }



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

3219:     Collective on dm

3221:     Input Parameter:
3222: +   dm - the DM object
3223: -   nlevels - the number of levels of refinement

3225:     Output Parameter:
3226: .   dmf - the refined DM hierarchy

3228:     Level: developer

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

3232: @*/
3233: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3234: {

3239:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3240:   if (nlevels == 0) return(0);
3242:   if (dm->ops->refinehierarchy) {
3243:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3244:   } else if (dm->ops->refine) {
3245:     PetscInt i;

3247:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3248:     for (i=1; i<nlevels; i++) {
3249:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3250:     }
3251:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3252:   return(0);
3253: }

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

3258:     Collective on dm

3260:     Input Parameter:
3261: +   dm - the DM object
3262: -   nlevels - the number of levels of coarsening

3264:     Output Parameter:
3265: .   dmc - the coarsened DM hierarchy

3267:     Level: developer

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

3271: @*/
3272: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3273: {

3278:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3279:   if (nlevels == 0) return(0);
3281:   if (dm->ops->coarsenhierarchy) {
3282:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3283:   } else if (dm->ops->coarsen) {
3284:     PetscInt i;

3286:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3287:     for (i=1; i<nlevels; i++) {
3288:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3289:     }
3290:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3291:   return(0);
3292: }

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

3297:     Not Collective

3299:     Input Parameters:
3300: +   dm - the DM object
3301: -   destroy - the destroy function

3303:     Level: intermediate

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

3307: @*/
3308: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3309: {
3312:   dm->ctxdestroy = destroy;
3313:   return(0);
3314: }

3316: /*@
3317:     DMSetApplicationContext - Set a user context into a DM object

3319:     Not Collective

3321:     Input Parameters:
3322: +   dm - the DM object
3323: -   ctx - the user context

3325:     Level: intermediate

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

3329: @*/
3330: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3331: {
3334:   dm->ctx = ctx;
3335:   return(0);
3336: }

3338: /*@
3339:     DMGetApplicationContext - Gets a user context from a DM object

3341:     Not Collective

3343:     Input Parameter:
3344: .   dm - the DM object

3346:     Output Parameter:
3347: .   ctx - the user context

3349:     Level: intermediate

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

3353: @*/
3354: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3355: {
3358:   *(void**)ctx = dm->ctx;
3359:   return(0);
3360: }

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

3365:     Logically Collective on dm

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

3371:     Level: intermediate

3373: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3374:          DMSetJacobian()

3376: @*/
3377: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3378: {
3381:   dm->ops->computevariablebounds = f;
3382:   return(0);
3383: }

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

3388:     Not Collective

3390:     Input Parameter:
3391: .   dm - the DM object to destroy

3393:     Output Parameter:
3394: .   flg - PETSC_TRUE if the variable bounds function exists

3396:     Level: developer

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

3400: @*/
3401: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3402: {
3406:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3407:   return(0);
3408: }

3410: /*@C
3411:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3413:     Logically Collective on dm

3415:     Input Parameters:
3416: .   dm - the DM object

3418:     Output parameters:
3419: +   xl - lower bound
3420: -   xu - upper bound

3422:     Level: advanced

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

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

3429: @*/
3430: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3431: {

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

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

3446:     Not Collective

3448:     Input Parameter:
3449: .   dm - the DM object

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

3454:     Level: developer

3456: .seealso DMCreateColoring()

3458: @*/
3459: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3460: {
3464:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3465:   return(0);
3466: }

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

3471:     Not Collective

3473:     Input Parameter:
3474: .   dm - the DM object

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

3479:     Level: developer

3481: .seealso DMCreateRestriction()

3483: @*/
3484: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3485: {
3489:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3490:   return(0);
3491: }


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

3497:     Not Collective

3499:     Input Parameter:
3500: .   dm - the DM object

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

3505:     Level: developer

3507: .seealso DMCreateInjection()

3509: @*/
3510: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3511: {

3517:   if (dm->ops->hascreateinjection) {
3518:     (*dm->ops->hascreateinjection)(dm,flg);
3519:   } else {
3520:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3521:   }
3522:   return(0);
3523: }

3525: PetscFunctionList DMList              = NULL;
3526: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3528: /*@C
3529:   DMSetType - Builds a DM, for a particular DM implementation.

3531:   Collective on dm

3533:   Input Parameters:
3534: + dm     - The DM object
3535: - method - The name of the DM type

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

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

3543:   Level: intermediate

3545: .seealso: DMGetType(), DMCreate()
3546: @*/
3547: PetscErrorCode  DMSetType(DM dm, DMType method)
3548: {
3549:   PetscErrorCode (*r)(DM);
3550:   PetscBool      match;

3555:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3556:   if (match) return(0);

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

3562:   if (dm->ops->destroy) {
3563:     (*dm->ops->destroy)(dm);
3564:   }
3565:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3566:   PetscObjectChangeTypeName((PetscObject)dm,method);
3567:   (*r)(dm);
3568:   return(0);
3569: }

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

3574:   Not Collective

3576:   Input Parameter:
3577: . dm  - The DM

3579:   Output Parameter:
3580: . type - The DM type name

3582:   Level: intermediate

3584: .seealso: DMSetType(), DMCreate()
3585: @*/
3586: PetscErrorCode  DMGetType(DM dm, DMType *type)
3587: {

3593:   DMRegisterAll();
3594:   *type = ((PetscObject)dm)->type_name;
3595:   return(0);
3596: }

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

3601:   Collective on dm

3603:   Input Parameters:
3604: + dm - the DM
3605: - newtype - new DM type (use "same" for the same type)

3607:   Output Parameter:
3608: . M - pointer to new DM

3610:   Notes:
3611:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3612:   the MPI communicator of the generated DM is always the same as the communicator
3613:   of the input DM.

3615:   Level: intermediate

3617: .seealso: DMCreate()
3618: @*/
3619: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3620: {
3621:   DM             B;
3622:   char           convname[256];
3623:   PetscBool      sametype/*, issame */;

3630:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3631:   /* PetscStrcmp(newtype, "same", &issame); */
3632:   if (sametype) {
3633:     *M   = dm;
3634:     PetscObjectReference((PetscObject) dm);
3635:     return(0);
3636:   } else {
3637:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3639:     /*
3640:        Order of precedence:
3641:        1) See if a specialized converter is known to the current DM.
3642:        2) See if a specialized converter is known to the desired DM class.
3643:        3) See if a good general converter is registered for the desired class
3644:        4) See if a good general converter is known for the current matrix.
3645:        5) Use a really basic converter.
3646:     */

3648:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3649:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3650:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3651:     PetscStrlcat(convname,"_",sizeof(convname));
3652:     PetscStrlcat(convname,newtype,sizeof(convname));
3653:     PetscStrlcat(convname,"_C",sizeof(convname));
3654:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3655:     if (conv) goto foundconv;

3657:     /* 2)  See if a specialized converter is known to the desired DM class. */
3658:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3659:     DMSetType(B, newtype);
3660:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3661:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3662:     PetscStrlcat(convname,"_",sizeof(convname));
3663:     PetscStrlcat(convname,newtype,sizeof(convname));
3664:     PetscStrlcat(convname,"_C",sizeof(convname));
3665:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3666:     if (conv) {
3667:       DMDestroy(&B);
3668:       goto foundconv;
3669:     }

3671: #if 0
3672:     /* 3) See if a good general converter is registered for the desired class */
3673:     conv = B->ops->convertfrom;
3674:     DMDestroy(&B);
3675:     if (conv) goto foundconv;

3677:     /* 4) See if a good general converter is known for the current matrix */
3678:     if (dm->ops->convert) {
3679:       conv = dm->ops->convert;
3680:     }
3681:     if (conv) goto foundconv;
3682: #endif

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

3687: foundconv:
3688:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3689:     (*conv)(dm,newtype,M);
3690:     /* Things that are independent of DM type: We should consult DMClone() here */
3691:     {
3692:       PetscBool             isper;
3693:       const PetscReal      *maxCell, *L;
3694:       const DMBoundaryType *bd;
3695:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3696:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3697:     }
3698:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3699:   }
3700:   PetscObjectStateIncrease((PetscObject) *M);
3701:   return(0);
3702: }

3704: /*--------------------------------------------------------------------------------------------------------------------*/

3706: /*@C
3707:   DMRegister -  Adds a new DM component implementation

3709:   Not Collective

3711:   Input Parameters:
3712: + name        - The name of a new user-defined creation routine
3713: - create_func - The creation routine itself

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


3719:   Sample usage:
3720: .vb
3721:     DMRegister("my_da", MyDMCreate);
3722: .ve

3724:   Then, your DM type can be chosen with the procedural interface via
3725: .vb
3726:     DMCreate(MPI_Comm, DM *);
3727:     DMSetType(DM,"my_da");
3728: .ve
3729:    or at runtime via the option
3730: .vb
3731:     -da_type my_da
3732: .ve

3734:   Level: advanced

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

3738: @*/
3739: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3740: {

3744:   DMInitializePackage();
3745:   PetscFunctionListAdd(&DMList,sname,function);
3746:   return(0);
3747: }

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

3752:   Collective on viewer

3754:   Input Parameters:
3755: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3756:            some related function before a call to DMLoad().
3757: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3758:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3760:    Level: intermediate

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

3765:   Notes for advanced users:
3766:   Most users should not need to know the details of the binary storage
3767:   format, since DMLoad() and DMView() completely hide these details.
3768:   But for anyone who's interested, the standard binary matrix storage
3769:   format is
3770: .vb
3771:      has not yet been determined
3772: .ve

3774: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3775: @*/
3776: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3777: {
3778:   PetscBool      isbinary, ishdf5;

3784:   PetscViewerCheckReadable(viewer);
3785:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3786:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3787:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3788:   if (isbinary) {
3789:     PetscInt classid;
3790:     char     type[256];

3792:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3793:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3794:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3795:     DMSetType(newdm, type);
3796:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3797:   } else if (ishdf5) {
3798:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3799:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3800:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3801:   return(0);
3802: }

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

3807:   Not collective

3809:   Input Parameter:
3810: . dm - the DM

3812:   Output Parameters:
3813: + lmin - local minimum coordinates (length coord dim, optional)
3814: - lmax - local maximim coordinates (length coord dim, optional)

3816:   Level: beginner

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


3821: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3822: @*/
3823: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3824: {
3825:   Vec                coords = NULL;
3826:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3827:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3828:   const PetscScalar *local_coords;
3829:   PetscInt           N, Ni;
3830:   PetscInt           cdim, i, j;
3831:   PetscErrorCode     ierr;

3835:   DMGetCoordinateDim(dm, &cdim);
3836:   DMGetCoordinates(dm, &coords);
3837:   if (coords) {
3838:     VecGetArrayRead(coords, &local_coords);
3839:     VecGetLocalSize(coords, &N);
3840:     Ni   = N/cdim;
3841:     for (i = 0; i < Ni; ++i) {
3842:       for (j = 0; j < 3; ++j) {
3843:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3844:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3845:       }
3846:     }
3847:     VecRestoreArrayRead(coords, &local_coords);
3848:   } else {
3849:     PetscBool isda;

3851:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3852:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3853:   }
3854:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
3855:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
3856:   return(0);
3857: }

3859: /*@
3860:   DMGetBoundingBox - Returns the global bounding box for the DM.

3862:   Collective

3864:   Input Parameter:
3865: . dm - the DM

3867:   Output Parameters:
3868: + gmin - global minimum coordinates (length coord dim, optional)
3869: - gmax - global maximim coordinates (length coord dim, optional)

3871:   Level: beginner

3873: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3874: @*/
3875: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3876: {
3877:   PetscReal      lmin[3], lmax[3];
3878:   PetscInt       cdim;
3879:   PetscMPIInt    count;

3884:   DMGetCoordinateDim(dm, &cdim);
3885:   PetscMPIIntCast(cdim, &count);
3886:   DMGetLocalBoundingBox(dm, lmin, lmax);
3887:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3888:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3889:   return(0);
3890: }

3892: /******************************** FEM Support **********************************/

3894: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3895: {
3896:   PetscInt       f;

3900:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3901:   for (f = 0; f < len; ++f) {
3902:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
3903:   }
3904:   return(0);
3905: }

3907: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3908: {
3909:   PetscInt       f, g;

3913:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3914:   for (f = 0; f < rows; ++f) {
3915:     PetscPrintf(PETSC_COMM_SELF, "  |");
3916:     for (g = 0; g < cols; ++g) {
3917:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
3918:     }
3919:     PetscPrintf(PETSC_COMM_SELF, " |\n");
3920:   }
3921:   return(0);
3922: }

3924: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3925: {
3926:   PetscInt          localSize, bs;
3927:   PetscMPIInt       size;
3928:   Vec               x, xglob;
3929:   const PetscScalar *xarray;
3930:   PetscErrorCode    ierr;

3933:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
3934:   VecDuplicate(X, &x);
3935:   VecCopy(X, x);
3936:   VecChop(x, tol);
3937:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
3938:   if (size > 1) {
3939:     VecGetLocalSize(x,&localSize);
3940:     VecGetArrayRead(x,&xarray);
3941:     VecGetBlockSize(x,&bs);
3942:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
3943:   } else {
3944:     xglob = x;
3945:   }
3946:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
3947:   if (size > 1) {
3948:     VecDestroy(&xglob);
3949:     VecRestoreArrayRead(x,&xarray);
3950:   }
3951:   VecDestroy(&x);
3952:   return(0);
3953: }

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

3958:   Input Parameter:
3959: . dm - The DM

3961:   Output Parameter:
3962: . section - The PetscSection

3964:   Options Database Keys:
3965: . -dm_petscsection_view - View the Section created by the DM

3967:   Level: advanced

3969:   Notes:
3970:   Use DMGetLocalSection() in new code.

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

3974: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
3975: @*/
3976: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3977: {

3981:   DMGetLocalSection(dm,section);
3982:   return(0);
3983: }

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

3988:   Input Parameter:
3989: . dm - The DM

3991:   Output Parameter:
3992: . section - The PetscSection

3994:   Options Database Keys:
3995: . -dm_petscsection_view - View the Section created by the DM

3997:   Level: intermediate

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

4001: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4002: @*/
4003: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4004: {

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

4013:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4014:     (*dm->ops->createlocalsection)(dm);
4015:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4016:   }
4017:   *section = dm->localSection;
4018:   return(0);
4019: }

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

4024:   Input Parameters:
4025: + dm - The DM
4026: - section - The PetscSection

4028:   Level: advanced

4030:   Notes:
4031:   Use DMSetLocalSection() in new code.

4033:   Any existing Section will be destroyed

4035: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4036: @*/
4037: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4038: {

4042:   DMSetLocalSection(dm,section);
4043:   return(0);
4044: }

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

4049:   Input Parameters:
4050: + dm - The DM
4051: - section - The PetscSection

4053:   Level: intermediate

4055:   Note: Any existing Section will be destroyed

4057: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4058: @*/
4059: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4060: {
4061:   PetscInt       numFields = 0;
4062:   PetscInt       f;

4068:   PetscObjectReference((PetscObject)section);
4069:   PetscSectionDestroy(&dm->localSection);
4070:   dm->localSection = section;
4071:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4072:   if (numFields) {
4073:     DMSetNumFields(dm, numFields);
4074:     for (f = 0; f < numFields; ++f) {
4075:       PetscObject disc;
4076:       const char *name;

4078:       PetscSectionGetFieldName(dm->localSection, f, &name);
4079:       DMGetField(dm, f, NULL, &disc);
4080:       PetscObjectSetName(disc, name);
4081:     }
4082:   }
4083:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4084:   PetscSectionDestroy(&dm->globalSection);
4085:   return(0);
4086: }

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

4091:   not collective

4093:   Input Parameter:
4094: . dm - The DM

4096:   Output Parameter:
4097: + 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.
4098: - 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.

4100:   Level: advanced

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

4104: .seealso: DMSetDefaultConstraints()
4105: @*/
4106: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4107: {

4112:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4113:   if (section) {*section = dm->defaultConstraintSection;}
4114:   if (mat) {*mat = dm->defaultConstraintMat;}
4115:   return(0);
4116: }

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

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

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

4125:   collective on dm

4127:   Input Parameters:
4128: + dm - The DM
4129: + 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).
4130: - 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).

4132:   Level: advanced

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

4136: .seealso: DMGetDefaultConstraints()
4137: @*/
4138: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4139: {
4140:   PetscMPIInt result;

4145:   if (section) {
4147:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4148:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4149:   }
4150:   if (mat) {
4152:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4153:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4154:   }
4155:   PetscObjectReference((PetscObject)section);
4156:   PetscSectionDestroy(&dm->defaultConstraintSection);
4157:   dm->defaultConstraintSection = section;
4158:   PetscObjectReference((PetscObject)mat);
4159:   MatDestroy(&dm->defaultConstraintMat);
4160:   dm->defaultConstraintMat = mat;
4161:   return(0);
4162: }

4164: #if defined(PETSC_USE_DEBUG)
4165: /*
4166:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4168:   Input Parameters:
4169: + dm - The DM
4170: . localSection - PetscSection describing the local data layout
4171: - globalSection - PetscSection describing the global data layout

4173:   Level: intermediate

4175: .seealso: DMGetSectionSF(), DMSetSectionSF()
4176: */
4177: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4178: {
4179:   MPI_Comm        comm;
4180:   PetscLayout     layout;
4181:   const PetscInt *ranges;
4182:   PetscInt        pStart, pEnd, p, nroots;
4183:   PetscMPIInt     size, rank;
4184:   PetscBool       valid = PETSC_TRUE, gvalid;
4185:   PetscErrorCode  ierr;

4188:   PetscObjectGetComm((PetscObject)dm,&comm);
4190:   MPI_Comm_size(comm, &size);
4191:   MPI_Comm_rank(comm, &rank);
4192:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4193:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4194:   PetscLayoutCreate(comm, &layout);
4195:   PetscLayoutSetBlockSize(layout, 1);
4196:   PetscLayoutSetLocalSize(layout, nroots);
4197:   PetscLayoutSetUp(layout);
4198:   PetscLayoutGetRanges(layout, &ranges);
4199:   for (p = pStart; p < pEnd; ++p) {
4200:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4202:     PetscSectionGetDof(localSection, p, &dof);
4203:     PetscSectionGetOffset(localSection, p, &off);
4204:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4205:     PetscSectionGetDof(globalSection, p, &gdof);
4206:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4207:     PetscSectionGetOffset(globalSection, p, &goff);
4208:     if (!gdof) continue; /* Censored point */
4209:     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;}
4210:     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;}
4211:     if (gdof < 0) {
4212:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4213:       for (d = 0; d < gsize; ++d) {
4214:         PetscInt offset = -(goff+1) + d, r;

4216:         PetscFindInt(offset,size+1,ranges,&r);
4217:         if (r < 0) r = -(r+2);
4218:         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;}
4219:       }
4220:     }
4221:   }
4222:   PetscLayoutDestroy(&layout);
4223:   PetscSynchronizedFlush(comm, NULL);
4224:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4225:   if (!gvalid) {
4226:     DMView(dm, NULL);
4227:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4228:   }
4229:   return(0);
4230: }
4231: #endif

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

4236:   Collective on dm

4238:   Input Parameter:
4239: . dm - The DM

4241:   Output Parameter:
4242: . section - The PetscSection

4244:   Level: intermediate

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

4248: .seealso: DMSetLocalSection(), DMGetLocalSection()
4249: @*/
4250: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4251: {

4257:   if (!dm->globalSection) {
4258:     PetscSection s;

4260:     DMGetLocalSection(dm, &s);
4261:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4262:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4263:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4264:     PetscLayoutDestroy(&dm->map);
4265:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4266:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4267:   }
4268:   *section = dm->globalSection;
4269:   return(0);
4270: }

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

4275:   Input Parameters:
4276: + dm - The DM
4277: - section - The PetscSection, or NULL

4279:   Level: intermediate

4281:   Note: Any existing Section will be destroyed

4283: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4284: @*/
4285: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4286: {

4292:   PetscObjectReference((PetscObject)section);
4293:   PetscSectionDestroy(&dm->globalSection);
4294:   dm->globalSection = section;
4295: #if defined(PETSC_USE_DEBUG)
4296:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4297: #endif
4298:   return(0);
4299: }

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

4305:   Input Parameter:
4306: . dm - The DM

4308:   Output Parameter:
4309: . sf - The PetscSF

4311:   Level: intermediate

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

4315: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4316: @*/
4317: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4318: {
4319:   PetscInt       nroots;

4325:   if (!dm->sectionSF) {
4326:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4327:   }
4328:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4329:   if (nroots < 0) {
4330:     PetscSection section, gSection;

4332:     DMGetLocalSection(dm, &section);
4333:     if (section) {
4334:       DMGetGlobalSection(dm, &gSection);
4335:       DMCreateSectionSF(dm, section, gSection);
4336:     } else {
4337:       *sf = NULL;
4338:       return(0);
4339:     }
4340:   }
4341:   *sf = dm->sectionSF;
4342:   return(0);
4343: }

4345: /*@
4346:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4348:   Input Parameters:
4349: + dm - The DM
4350: - sf - The PetscSF

4352:   Level: intermediate

4354:   Note: Any previous SF is destroyed

4356: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4357: @*/
4358: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4359: {

4365:   PetscObjectReference((PetscObject) sf);
4366:   PetscSFDestroy(&dm->sectionSF);
4367:   dm->sectionSF = sf;
4368:   return(0);
4369: }

4371: /*@C
4372:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4373:   describing the data layout.

4375:   Input Parameters:
4376: + dm - The DM
4377: . localSection - PetscSection describing the local data layout
4378: - globalSection - PetscSection describing the global data layout

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

4382:   Level: developer

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

4388: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4389: @*/
4390: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4391: {
4392:   MPI_Comm       comm;
4393:   PetscLayout    layout;
4394:   const PetscInt *ranges;
4395:   PetscInt       *local;
4396:   PetscSFNode    *remote;
4397:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4398:   PetscMPIInt    size, rank;

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

4416:     PetscSectionGetDof(globalSection, p, &gdof);
4417:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4418:     if (gcdof > (gdof < 0 ? -(gdof+1) : gdof)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d has %d constraints > %d dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
4419:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4420:   }
4421:   PetscMalloc1(nleaves, &local);
4422:   PetscMalloc1(nleaves, &remote);
4423:   for (p = pStart, l = 0; p < pEnd; ++p) {
4424:     const PetscInt *cind;
4425:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4427:     PetscSectionGetDof(localSection, p, &dof);
4428:     PetscSectionGetOffset(localSection, p, &off);
4429:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4430:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4431:     PetscSectionGetDof(globalSection, p, &gdof);
4432:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4433:     PetscSectionGetOffset(globalSection, p, &goff);
4434:     if (!gdof) continue; /* Censored point */
4435:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4436:     if (gsize != dof-cdof) {
4437:       if (gsize != dof) SETERRQ4(comm, PETSC_ERR_ARG_WRONG, "Global dof %d for point %d is neither the constrained size %d, nor the unconstrained %d", gsize, p, dof-cdof, dof);
4438:       cdof = 0; /* Ignore constraints */
4439:     }
4440:     for (d = 0, c = 0; d < dof; ++d) {
4441:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4442:       local[l+d-c] = off+d;
4443:     }
4444:     if (gdof < 0) {
4445:       for (d = 0; d < gsize; ++d, ++l) {
4446:         PetscInt offset = -(goff+1) + d, r;

4448:         PetscFindInt(offset,size+1,ranges,&r);
4449:         if (r < 0) r = -(r+2);
4450:         if ((r < 0) || (r >= size)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d mapped to invalid process %d (%d, %d)", p, r, gdof, goff);
4451:         remote[l].rank  = r;
4452:         remote[l].index = offset - ranges[r];
4453:       }
4454:     } else {
4455:       for (d = 0; d < gsize; ++d, ++l) {
4456:         remote[l].rank  = rank;
4457:         remote[l].index = goff+d - ranges[rank];
4458:       }
4459:     }
4460:   }
4461:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4462:   PetscLayoutDestroy(&layout);
4463:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4464:   return(0);
4465: }

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

4470:   Input Parameter:
4471: . dm - The DM

4473:   Output Parameter:
4474: . sf - The PetscSF

4476:   Level: intermediate

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

4480: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4481: @*/
4482: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4483: {
4487:   *sf = dm->sf;
4488:   return(0);
4489: }

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

4494:   Input Parameters:
4495: + dm - The DM
4496: - sf - The PetscSF

4498:   Level: intermediate

4500: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4501: @*/
4502: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4503: {

4509:   PetscObjectReference((PetscObject) sf);
4510:   PetscSFDestroy(&dm->sf);
4511:   dm->sf = sf;
4512:   return(0);
4513: }

4515: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4516: {
4517:   PetscClassId   id;

4521:   PetscObjectGetClassId(disc, &id);
4522:   if (id == PETSCFE_CLASSID) {
4523:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4524:   } else if (id == PETSCFV_CLASSID) {
4525:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4526:   } else {
4527:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4528:   }
4529:   return(0);
4530: }

4532: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4533: {
4534:   RegionField   *tmpr;
4535:   PetscInt       Nf = dm->Nf, f;

4539:   if (Nf >= NfNew) return(0);
4540:   PetscMalloc1(NfNew, &tmpr);
4541:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4542:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4543:   PetscFree(dm->fields);
4544:   dm->Nf     = NfNew;
4545:   dm->fields = tmpr;
4546:   return(0);
4547: }

4549: /*@
4550:   DMClearFields - Remove all fields from the DM

4552:   Logically collective on dm

4554:   Input Parameter:
4555: . dm - The DM

4557:   Level: intermediate

4559: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4560: @*/
4561: PetscErrorCode DMClearFields(DM dm)
4562: {
4563:   PetscInt       f;

4568:   for (f = 0; f < dm->Nf; ++f) {
4569:     PetscObjectDestroy(&dm->fields[f].disc);
4570:     DMLabelDestroy(&dm->fields[f].label);
4571:   }
4572:   PetscFree(dm->fields);
4573:   dm->fields = NULL;
4574:   dm->Nf     = 0;
4575:   return(0);
4576: }

4578: /*@
4579:   DMGetNumFields - Get the number of fields in the DM

4581:   Not collective

4583:   Input Parameter:
4584: . dm - The DM

4586:   Output Parameter:
4587: . Nf - The number of fields

4589:   Level: intermediate

4591: .seealso: DMSetNumFields(), DMSetField()
4592: @*/
4593: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4594: {
4598:   *numFields = dm->Nf;
4599:   return(0);
4600: }

4602: /*@
4603:   DMSetNumFields - Set the number of fields in the DM

4605:   Logically collective on dm

4607:   Input Parameters:
4608: + dm - The DM
4609: - Nf - The number of fields

4611:   Level: intermediate

4613: .seealso: DMGetNumFields(), DMSetField()
4614: @*/
4615: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4616: {
4617:   PetscInt       Nf, f;

4622:   DMGetNumFields(dm, &Nf);
4623:   for (f = Nf; f < numFields; ++f) {
4624:     PetscContainer obj;

4626:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4627:     DMAddField(dm, NULL, (PetscObject) obj);
4628:     PetscContainerDestroy(&obj);
4629:   }
4630:   return(0);
4631: }

4633: /*@
4634:   DMGetField - Return the discretization object for a given DM field

4636:   Not collective

4638:   Input Parameters:
4639: + dm - The DM
4640: - f  - The field number

4642:   Output Parameters:
4643: + label - The label indicating the support of the field, or NULL for the entire mesh
4644: - field - The discretization object

4646:   Level: intermediate

4648: .seealso: DMAddField(), DMSetField()
4649: @*/
4650: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4651: {
4655:   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);
4656:   if (label) *label = dm->fields[f].label;
4657:   if (field) *field = dm->fields[f].disc;
4658:   return(0);
4659: }

4661: /*@
4662:   DMSetField - Set the discretization object for a given DM field

4664:   Logically collective on dm

4666:   Input Parameters:
4667: + dm    - The DM
4668: . f     - The field number
4669: . label - The label indicating the support of the field, or NULL for the entire mesh
4670: - field - The discretization object

4672:   Level: intermediate

4674: .seealso: DMAddField(), DMGetField()
4675: @*/
4676: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4677: {

4684:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4685:   DMFieldEnlarge_Static(dm, f+1);
4686:   DMLabelDestroy(&dm->fields[f].label);
4687:   PetscObjectDestroy(&dm->fields[f].disc);
4688:   dm->fields[f].label = label;
4689:   dm->fields[f].disc  = field;
4690:   PetscObjectReference((PetscObject) label);
4691:   PetscObjectReference((PetscObject) field);
4692:   DMSetDefaultAdjacency_Private(dm, f, field);
4693:   DMClearDS(dm);
4694:   return(0);
4695: }

4697: /*@
4698:   DMAddField - Add the discretization object for the given DM field

4700:   Logically collective on dm

4702:   Input Parameters:
4703: + dm    - The DM
4704: . label - The label indicating the support of the field, or NULL for the entire mesh
4705: - field - The discretization object

4707:   Level: intermediate

4709: .seealso: DMSetField(), DMGetField()
4710: @*/
4711: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4712: {
4713:   PetscInt       Nf = dm->Nf;

4720:   DMFieldEnlarge_Static(dm, Nf+1);
4721:   dm->fields[Nf].label = label;
4722:   dm->fields[Nf].disc  = field;
4723:   PetscObjectReference((PetscObject) label);
4724:   PetscObjectReference((PetscObject) field);
4725:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4726:   DMClearDS(dm);
4727:   return(0);
4728: }

4730: /*@
4731:   DMCopyFields - Copy the discretizations for the DM into another DM

4733:   Collective on dm

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

4738:   Output Parameter:
4739: . newdm - The DM

4741:   Level: advanced

4743: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4744: @*/
4745: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4746: {
4747:   PetscInt       Nf, f;

4751:   if (dm == newdm) return(0);
4752:   DMGetNumFields(dm, &Nf);
4753:   DMClearFields(newdm);
4754:   for (f = 0; f < Nf; ++f) {
4755:     DMLabel     label;
4756:     PetscObject field;
4757:     PetscBool   useCone, useClosure;

4759:     DMGetField(dm, f, &label, &field);
4760:     DMSetField(newdm, f, label, field);
4761:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4762:     DMSetAdjacency(newdm, f, useCone, useClosure);
4763:   }
4764:   return(0);
4765: }

4767: /*@
4768:   DMGetAdjacency - Returns the flags for determining variable influence

4770:   Not collective

4772:   Input Parameters:
4773: + dm - The DM object
4774: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4776:   Output Parameter:
4777: + useCone    - Flag for variable influence starting with the cone operation
4778: - useClosure - Flag for variable influence using transitive closure

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

4786:   Level: developer

4788: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4789: @*/
4790: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4791: {
4796:   if (f < 0) {
4797:     if (useCone)    *useCone    = dm->adjacency[0];
4798:     if (useClosure) *useClosure = dm->adjacency[1];
4799:   } else {
4800:     PetscInt       Nf;

4803:     DMGetNumFields(dm, &Nf);
4804:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4805:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4806:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4807:   }
4808:   return(0);
4809: }

4811: /*@
4812:   DMSetAdjacency - Set the flags for determining variable influence

4814:   Not collective

4816:   Input Parameters:
4817: + dm         - The DM object
4818: . f          - The field number
4819: . useCone    - Flag for variable influence starting with the cone operation
4820: - useClosure - Flag for variable influence using transitive closure

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

4828:   Level: developer

4830: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4831: @*/
4832: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4833: {
4836:   if (f < 0) {
4837:     dm->adjacency[0] = useCone;
4838:     dm->adjacency[1] = useClosure;
4839:   } else {
4840:     PetscInt       Nf;

4843:     DMGetNumFields(dm, &Nf);
4844:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4845:     dm->fields[f].adjacency[0] = useCone;
4846:     dm->fields[f].adjacency[1] = useClosure;
4847:   }
4848:   return(0);
4849: }

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

4854:   Not collective

4856:   Input Parameters:
4857: . dm - The DM object

4859:   Output Parameter:
4860: + useCone    - Flag for variable influence starting with the cone operation
4861: - useClosure - Flag for variable influence using transitive closure

4863:   Notes:
4864: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4865: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4866: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4868:   Level: developer

4870: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4871: @*/
4872: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4873: {
4874:   PetscInt       Nf;

4881:   DMGetNumFields(dm, &Nf);
4882:   if (!Nf) {
4883:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4884:   } else {
4885:     DMGetAdjacency(dm, 0, useCone, useClosure);
4886:   }
4887:   return(0);
4888: }

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

4893:   Not collective

4895:   Input Parameters:
4896: + dm         - The DM object
4897: . useCone    - Flag for variable influence starting with the cone operation
4898: - useClosure - Flag for variable influence using transitive closure

4900:   Notes:
4901: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4902: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4903: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4905:   Level: developer

4907: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
4908: @*/
4909: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
4910: {
4911:   PetscInt       Nf;

4916:   DMGetNumFields(dm, &Nf);
4917:   if (!Nf) {
4918:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4919:   } else {
4920:     DMSetAdjacency(dm, 0, useCone, useClosure);
4921:   }
4922:   return(0);
4923: }

4925: /* Complete labels that are being used for FEM BC */
4926: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
4927: {
4928:   DMLabel        label;
4929:   PetscObject    obj;
4930:   PetscClassId   id;
4931:   PetscInt       Nbd, bd;
4932:   PetscBool      isFE      = PETSC_FALSE;
4933:   PetscBool      duplicate = PETSC_FALSE;

4937:   DMGetField(dm, field, NULL, &obj);
4938:   PetscObjectGetClassId(obj, &id);
4939:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
4940:   DMGetLabel(dm, labelname, &label);
4941:   if (isFE && label) {
4942:     /* Only want to modify label once */
4943:     PetscDSGetNumBoundary(ds, &Nbd);
4944:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
4945:       const char *lname;

4947:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
4948:       PetscStrcmp(lname, labelname, &duplicate);
4949:       if (duplicate) break;
4950:     }
4951:     if (!duplicate) {
4952:       DM plex;

4954:       DMConvert(dm, DMPLEX, &plex);
4955:       if (plex) {DMPlexLabelComplete(plex, label);}
4956:       DMDestroy(&plex);
4957:     }
4958:   }
4959:   return(0);
4960: }

4962: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4963: {
4964:   DMSpace       *tmpd;
4965:   PetscInt       Nds = dm->Nds, s;

4969:   if (Nds >= NdsNew) return(0);
4970:   PetscMalloc1(NdsNew, &tmpd);
4971:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4972:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
4973:   PetscFree(dm->probs);
4974:   dm->Nds   = NdsNew;
4975:   dm->probs = tmpd;
4976:   return(0);
4977: }

4979: /*@
4980:   DMGetNumDS - Get the number of discrete systems in the DM

4982:   Not collective

4984:   Input Parameter:
4985: . dm - The DM

4987:   Output Parameter:
4988: . Nds - The number of PetscDS objects

4990:   Level: intermediate

4992: .seealso: DMGetDS(), DMGetCellDS()
4993: @*/
4994: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4995: {
4999:   *Nds = dm->Nds;
5000:   return(0);
5001: }

5003: /*@
5004:   DMClearDS - Remove all discrete systems from the DM

5006:   Logically collective on dm

5008:   Input Parameter:
5009: . dm - The DM

5011:   Level: intermediate

5013: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5014: @*/
5015: PetscErrorCode DMClearDS(DM dm)
5016: {
5017:   PetscInt       s;

5022:   for (s = 0; s < dm->Nds; ++s) {
5023:     PetscDSDestroy(&dm->probs[s].ds);
5024:     DMLabelDestroy(&dm->probs[s].label);
5025:     ISDestroy(&dm->probs[s].fields);
5026:   }
5027:   PetscFree(dm->probs);
5028:   dm->probs = NULL;
5029:   dm->Nds   = 0;
5030:   return(0);
5031: }

5033: /*@
5034:   DMGetDS - Get the default PetscDS

5036:   Not collective

5038:   Input Parameter:
5039: . dm    - The DM

5041:   Output Parameter:
5042: . prob - The default PetscDS

5044:   Level: intermediate

5046: .seealso: DMGetCellDS(), DMGetRegionDS()
5047: @*/
5048: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5049: {

5055:   if (dm->Nds <= 0) {
5056:     PetscDS ds;

5058:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5059:     DMSetRegionDS(dm, NULL, NULL, ds);
5060:     PetscDSDestroy(&ds);
5061:   }
5062:   *prob = dm->probs[0].ds;
5063:   return(0);
5064: }

5066: /*@
5067:   DMGetCellDS - Get the PetscDS defined on a given cell

5069:   Not collective

5071:   Input Parameters:
5072: + dm    - The DM
5073: - point - Cell for the DS

5075:   Output Parameter:
5076: . prob - The PetscDS defined on the given cell

5078:   Level: developer

5080: .seealso: DMGetDS(), DMSetRegionDS()
5081: @*/
5082: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5083: {
5084:   PetscDS        probDef = NULL;
5085:   PetscInt       s;

5091:   *prob = NULL;
5092:   for (s = 0; s < dm->Nds; ++s) {
5093:     PetscInt val;

5095:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5096:     else {
5097:       DMLabelGetValue(dm->probs[s].label, point, &val);
5098:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5099:     }
5100:   }
5101:   if (!*prob) *prob = probDef;
5102:   return(0);
5103: }

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

5108:   Not collective

5110:   Input Parameters:
5111: + dm    - The DM
5112: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5120:   Level: advanced

5122: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5123: @*/
5124: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5125: {
5126:   PetscInt Nds = dm->Nds, s;

5133:   for (s = 0; s < Nds; ++s) {
5134:     if (dm->probs[s].label == label) {
5135:       if (fields) *fields = dm->probs[s].fields;
5136:       if (ds)     *ds     = dm->probs[s].ds;
5137:       return(0);
5138:     }
5139:   }
5140:   return(0);
5141: }

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

5146:   Not collective

5148:   Input Parameters:
5149: + dm  - The DM
5150: - num - The region number, in [0, Nds)

5152:   Output Parameters:
5153: + label  - The region label, or NULL
5154: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5155: - prob   - The PetscDS defined on the given region, or NULL

5157:   Level: advanced

5159: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5160: @*/
5161: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5162: {
5163:   PetscInt       Nds;

5168:   DMGetNumDS(dm, &Nds);
5169:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5170:   if (label) {
5172:     *label = dm->probs[num].label;
5173:   }
5174:   if (fields) {
5176:     *fields = dm->probs[num].fields;
5177:   }
5178:   if (ds) {
5180:     *ds = dm->probs[num].ds;
5181:   }
5182:   return(0);
5183: }

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

5188:   Collective on dm

5190:   Input Parameters:
5191: + dm     - The DM
5192: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5193: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5194: - prob   - The PetscDS defined on the given cell

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

5199:   Level: advanced

5201: .seealso: DMGetRegionDS(), DMGetDS(), DMGetCellDS()
5202: @*/
5203: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5204: {
5205:   PetscInt       Nds = dm->Nds, s;

5212:   for (s = 0; s < Nds; ++s) {
5213:     if (dm->probs[s].label == label) {
5214:       PetscDSDestroy(&dm->probs[s].ds);
5215:       dm->probs[s].ds = ds;
5216:       return(0);
5217:     }
5218:   }
5219:   DMDSEnlarge_Static(dm, Nds+1);
5220:   PetscObjectReference((PetscObject) label);
5221:   PetscObjectReference((PetscObject) fields);
5222:   PetscObjectReference((PetscObject) ds);
5223:   if (!label) {
5224:     /* Put the NULL label at the front, so it is returned as the default */
5225:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5226:     Nds = 0;
5227:   }
5228:   dm->probs[Nds].label  = label;
5229:   dm->probs[Nds].fields = fields;
5230:   dm->probs[Nds].ds     = ds;
5231:   return(0);
5232: }

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

5237:   Collective on dm

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

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

5244:   Level: intermediate

5246: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5247: @*/
5248: PetscErrorCode DMCreateDS(DM dm)
5249: {
5250:   MPI_Comm       comm;
5251:   PetscDS        prob, probh = NULL;
5252:   PetscInt       dimEmbed, Nf = dm->Nf, f, s, field = 0, fieldh = 0;
5253:   PetscBool      doSetup = PETSC_TRUE;

5258:   if (!dm->fields) return(0);
5259:   /* Can only handle two label cases right now:
5260:    1) NULL
5261:    2) Hybrid cells
5262:   */
5263:   PetscObjectGetComm((PetscObject) dm, &comm);
5264:   DMGetCoordinateDim(dm, &dimEmbed);
5265:   /* Create default DS */
5266:   DMGetRegionDS(dm, NULL, NULL, &prob);
5267:   if (!prob) {
5268:     IS        fields;
5269:     PetscInt *fld, nf;

5271:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5272:     PetscMalloc1(nf, &fld);
5273:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5274:     ISCreate(PETSC_COMM_SELF, &fields);
5275:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5276:     ISSetType(fields, ISGENERAL);
5277:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5279:     PetscDSCreate(comm, &prob);
5280:     DMSetRegionDS(dm, NULL, fields, prob);
5281:     PetscDSDestroy(&prob);
5282:     ISDestroy(&fields);
5283:     DMGetRegionDS(dm, NULL, NULL, &prob);
5284:   }
5285:   PetscDSSetCoordinateDimension(prob, dimEmbed);
5286:   /* Optionally create hybrid DS */
5287:   for (f = 0; f < Nf; ++f) {
5288:     DMLabel  label = dm->fields[f].label;
5289:     PetscInt lStart, lEnd;

5291:     if (label) {
5292:       DM             plex;
5293:       DMPolytopeType ct;
5294:       IS             fields;
5295:       PetscInt      *fld;
5296:       PetscInt       depth;

5298:       DMConvert(dm, DMPLEX, &plex);
5299:       DMPlexGetDepth(plex, &depth);
5300:       DMDestroy(&plex);

5302:       DMLabelGetBounds(label, &lStart, &lEnd);
5303:       DMPlexGetCellType(dm, lStart, &ct);
5304:       switch (ct) {
5305:         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5306:         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5307:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5308:         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5309:           break;
5310:         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over tensor prism cells right now");
5311:       }
5312:       PetscDSCreate(comm, &probh);
5313:       PetscMalloc1(1, &fld);
5314:       fld[0] = f;
5315:       ISCreate(PETSC_COMM_SELF, &fields);
5316:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5317:       ISSetType(fields, ISGENERAL);
5318:       ISGeneralSetIndices(fields, 1, fld, PETSC_OWN_POINTER);
5319:       DMSetRegionDS(dm, label, fields, probh);
5320:       ISDestroy(&fields);
5321:       PetscDSSetHybrid(probh, PETSC_TRUE);
5322:       PetscDSSetCoordinateDimension(probh, dimEmbed);
5323:       break;
5324:     }
5325:   }
5326:   /* Set fields in DSes */
5327:   for (f = 0; f < Nf; ++f) {
5328:     DMLabel     label = dm->fields[f].label;
5329:     PetscObject disc  = dm->fields[f].disc;

5331:     if (!label) {
5332:       PetscDSSetDiscretization(prob,  field++,  disc);
5333:       if (probh) {
5334:         PetscFE subfe;

5336:         PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);
5337:         PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);
5338:       }
5339:     } else {
5340:       PetscDSSetDiscretization(probh, fieldh++, disc);
5341:     }
5342:     /* We allow people to have placeholder fields and construct the Section by hand */
5343:     {
5344:       PetscClassId id;

5346:       PetscObjectGetClassId(disc, &id);
5347:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5348:     }
5349:   }
5350:   PetscDSDestroy(&probh);
5351:   /* Setup DSes */
5352:   if (doSetup) {
5353:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5354:   }
5355:   return(0);
5356: }

5358: /*@
5359:   DMCopyDS - Copy the discrete systems for the DM into another DM

5361:   Collective on dm

5363:   Input Parameter:
5364: . dm - The DM

5366:   Output Parameter:
5367: . newdm - The DM

5369:   Level: advanced

5371: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5372: @*/
5373: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5374: {
5375:   PetscInt       Nds, s;

5379:   if (dm == newdm) return(0);
5380:   DMGetNumDS(dm, &Nds);
5381:   DMClearDS(newdm);
5382:   for (s = 0; s < Nds; ++s) {
5383:     DMLabel  label;
5384:     IS       fields;
5385:     PetscDS  ds;
5386:     PetscInt Nbd, bd;

5388:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5389:     DMSetRegionDS(newdm, label, fields, ds);
5390:     PetscDSGetNumBoundary(ds, &Nbd);
5391:     for (bd = 0; bd < Nbd; ++bd) {
5392:       const char *labelname, *name;
5393:       PetscInt    field;

5395:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5396:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL);
5397:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5398:     }
5399:   }
5400:   return(0);
5401: }

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

5406:   Collective on dm

5408:   Input Parameter:
5409: . dm - The DM

5411:   Output Parameter:
5412: . newdm - The DM

5414:   Level: advanced

5416: .seealso: DMCopyFields(), DMCopyDS()
5417: @*/
5418: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5419: {

5423:   DMCopyFields(dm, newdm);
5424:   DMCopyDS(dm, newdm);
5425:   return(0);
5426: }

5428: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5429: {
5430:   DM dm_coord,dmc_coord;
5432:   Vec coords,ccoords;
5433:   Mat inject;
5435:   DMGetCoordinateDM(dm,&dm_coord);
5436:   DMGetCoordinateDM(dmc,&dmc_coord);
5437:   DMGetCoordinates(dm,&coords);
5438:   DMGetCoordinates(dmc,&ccoords);
5439:   if (coords && !ccoords) {
5440:     DMCreateGlobalVector(dmc_coord,&ccoords);
5441:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5442:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5443:     MatRestrict(inject,coords,ccoords);
5444:     MatDestroy(&inject);
5445:     DMSetCoordinates(dmc,ccoords);
5446:     VecDestroy(&ccoords);
5447:   }
5448:   return(0);
5449: }

5451: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5452: {
5453:   DM dm_coord,subdm_coord;
5455:   Vec coords,ccoords,clcoords;
5456:   VecScatter *scat_i,*scat_g;
5458:   DMGetCoordinateDM(dm,&dm_coord);
5459:   DMGetCoordinateDM(subdm,&subdm_coord);
5460:   DMGetCoordinates(dm,&coords);
5461:   DMGetCoordinates(subdm,&ccoords);
5462:   if (coords && !ccoords) {
5463:     DMCreateGlobalVector(subdm_coord,&ccoords);
5464:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5465:     DMCreateLocalVector(subdm_coord,&clcoords);
5466:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5467:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5468:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5469:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5470:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5471:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5472:     DMSetCoordinates(subdm,ccoords);
5473:     DMSetCoordinatesLocal(subdm,clcoords);
5474:     VecScatterDestroy(&scat_i[0]);
5475:     VecScatterDestroy(&scat_g[0]);
5476:     VecDestroy(&ccoords);
5477:     VecDestroy(&clcoords);
5478:     PetscFree(scat_i);
5479:     PetscFree(scat_g);
5480:   }
5481:   return(0);
5482: }

5484: /*@
5485:   DMGetDimension - Return the topological dimension of the DM

5487:   Not collective

5489:   Input Parameter:
5490: . dm - The DM

5492:   Output Parameter:
5493: . dim - The topological dimension

5495:   Level: beginner

5497: .seealso: DMSetDimension(), DMCreate()
5498: @*/
5499: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5500: {
5504:   *dim = dm->dim;
5505:   return(0);
5506: }

5508: /*@
5509:   DMSetDimension - Set the topological dimension of the DM

5511:   Collective on dm

5513:   Input Parameters:
5514: + dm - The DM
5515: - dim - The topological dimension

5517:   Level: beginner

5519: .seealso: DMGetDimension(), DMCreate()
5520: @*/
5521: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5522: {
5523:   PetscDS        ds;

5529:   dm->dim = dim;
5530:   DMGetDS(dm, &ds);
5531:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5532:   return(0);
5533: }

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

5538:   Collective on dm

5540:   Input Parameters:
5541: + dm - the DM
5542: - dim - the dimension

5544:   Output Parameters:
5545: + pStart - The first point of the given dimension
5546: - pEnd - The first point following points of the given dimension

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

5553:   Level: intermediate

5555: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5556: @*/
5557: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5558: {
5559:   PetscInt       d;

5564:   DMGetDimension(dm, &d);
5565:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5566:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5567:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5568:   return(0);
5569: }

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

5574:   Collective on dm

5576:   Input Parameters:
5577: + dm - the DM
5578: - c - coordinate vector

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

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

5585:   Level: intermediate

5587: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5588: @*/
5589: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5590: {

5596:   PetscObjectReference((PetscObject) c);
5597:   VecDestroy(&dm->coordinates);
5598:   dm->coordinates = c;
5599:   VecDestroy(&dm->coordinatesLocal);
5600:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5601:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5602:   return(0);
5603: }

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

5608:   Not collective

5610:    Input Parameters:
5611: +  dm - the DM
5612: -  c - coordinate vector

5614:   Notes:
5615:   The coordinates of ghost points can be set using DMSetCoordinates()
5616:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5617:   setting of ghost coordinates outside of the domain.

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

5621:   Level: intermediate

5623: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5624: @*/
5625: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5626: {

5632:   PetscObjectReference((PetscObject) c);
5633:   VecDestroy(&dm->coordinatesLocal);

5635:   dm->coordinatesLocal = c;

5637:   VecDestroy(&dm->coordinates);
5638:   return(0);
5639: }

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

5644:   Collective on dm

5646:   Input Parameter:
5647: . dm - the DM

5649:   Output Parameter:
5650: . c - global coordinate vector

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

5655:   Each process has only the local coordinates (does NOT have the ghost coordinates).

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

5660:   Level: intermediate

5662: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5663: @*/
5664: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5665: {

5671:   if (!dm->coordinates && dm->coordinatesLocal) {
5672:     DM        cdm = NULL;
5673:     PetscBool localized;

5675:     DMGetCoordinateDM(dm, &cdm);
5676:     DMCreateGlobalVector(cdm, &dm->coordinates);
5677:     DMGetCoordinatesLocalized(dm, &localized);
5678:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5679:     if (localized) {
5680:       PetscInt cdim;

5682:       DMGetCoordinateDim(dm, &cdim);
5683:       VecSetBlockSize(dm->coordinates, cdim);
5684:     }
5685:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
5686:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5687:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5688:   }
5689:   *c = dm->coordinates;
5690:   return(0);
5691: }

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

5696:   Collective on dm

5698:   Input Parameter:
5699: . dm - the DM

5701:   Level: advanced

5703: .seealso: DMGetCoordinatesLocalNoncollective()
5704: @*/
5705: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5706: {

5711:   if (!dm->coordinatesLocal && dm->coordinates) {
5712:     DM        cdm = NULL;
5713:     PetscBool localized;

5715:     DMGetCoordinateDM(dm, &cdm);
5716:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
5717:     DMGetCoordinatesLocalized(dm, &localized);
5718:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5719:     if (localized) {
5720:       PetscInt cdim;

5722:       DMGetCoordinateDim(dm, &cdim);
5723:       VecSetBlockSize(dm->coordinates, cdim);
5724:     }
5725:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
5726:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5727:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5728:   }
5729:   return(0);
5730: }

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

5735:   Collective on dm

5737:   Input Parameter:
5738: . dm - the DM

5740:   Output Parameter:
5741: . c - coordinate vector

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

5746:   Each process has the local and ghost coordinates

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

5751:   Level: intermediate

5753: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5754: @*/
5755: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5756: {

5762:   DMGetCoordinatesLocalSetUp(dm);
5763:   *c = dm->coordinatesLocal;
5764:   return(0);
5765: }

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

5770:   Not collective

5772:   Input Parameter:
5773: . dm - the DM

5775:   Output Parameter:
5776: . c - coordinate vector

5778:   Level: advanced

5780: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5781: @*/
5782: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5783: {
5787:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5788:   *c = dm->coordinatesLocal;
5789:   return(0);
5790: }

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

5795:   Not collective

5797:   Input Parameter:
5798: + dm - the DM
5799: - p - the IS of points whose coordinates will be returned

5801:   Output Parameter:
5802: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5803: - pCoord - the Vec with coordinates of points in p

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

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

5810:   Each process has the local and ghost coordinates

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

5815:   Level: advanced

5817: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5818: @*/
5819: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5820: {
5821:   PetscSection        cs, newcs;
5822:   Vec                 coords;
5823:   const PetscScalar   *arr;
5824:   PetscScalar         *newarr=NULL;
5825:   PetscInt            n;
5826:   PetscErrorCode      ierr;

5833:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5834:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5835:   cs = dm->coordinateDM->localSection;
5836:   coords = dm->coordinatesLocal;
5837:   VecGetArrayRead(coords, &arr);
5838:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
5839:   VecRestoreArrayRead(coords, &arr);
5840:   if (pCoord) {
5841:     PetscSectionGetStorageSize(newcs, &n);
5842:     /* set array in two steps to mimic PETSC_OWN_POINTER */
5843:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
5844:     VecReplaceArray(*pCoord, newarr);
5845:   } else {
5846:     PetscFree(newarr);
5847:   }
5848:   if (pCoordSection) {*pCoordSection = newcs;}
5849:   else               {PetscSectionDestroy(&newcs);}
5850:   return(0);
5851: }

5853: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5854: {

5860:   if (!dm->coordinateField) {
5861:     if (dm->ops->createcoordinatefield) {
5862:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
5863:     }
5864:   }
5865:   *field = dm->coordinateField;
5866:   return(0);
5867: }

5869: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5870: {

5876:   PetscObjectReference((PetscObject)field);
5877:   DMFieldDestroy(&dm->coordinateField);
5878:   dm->coordinateField = field;
5879:   return(0);
5880: }

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

5885:   Collective on dm

5887:   Input Parameter:
5888: . dm - the DM

5890:   Output Parameter:
5891: . cdm - coordinate DM

5893:   Level: intermediate

5895: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5896: @*/
5897: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5898: {

5904:   if (!dm->coordinateDM) {
5905:     DM cdm;

5907:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5908:     (*dm->ops->createcoordinatedm)(dm, &cdm);
5909:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5910:      * until the call to CreateCoordinateDM) */
5911:     DMDestroy(&dm->coordinateDM);
5912:     dm->coordinateDM = cdm;
5913:   }
5914:   *cdm = dm->coordinateDM;
5915:   return(0);
5916: }

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

5921:   Logically Collective on dm

5923:   Input Parameters:
5924: + dm - the DM
5925: - cdm - coordinate DM

5927:   Level: intermediate

5929: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5930: @*/
5931: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5932: {

5938:   PetscObjectReference((PetscObject)cdm);
5939:   DMDestroy(&dm->coordinateDM);
5940:   dm->coordinateDM = cdm;
5941:   return(0);
5942: }

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

5947:   Not Collective

5949:   Input Parameter:
5950: . dm - The DM object

5952:   Output Parameter:
5953: . dim - The embedding dimension

5955:   Level: intermediate

5957: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5958: @*/
5959: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5960: {
5964:   if (dm->dimEmbed == PETSC_DEFAULT) {
5965:     dm->dimEmbed = dm->dim;
5966:   }
5967:   *dim = dm->dimEmbed;
5968:   return(0);
5969: }

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

5974:   Not Collective

5976:   Input Parameters:
5977: + dm  - The DM object
5978: - dim - The embedding dimension

5980:   Level: intermediate

5982: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5983: @*/
5984: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5985: {
5986:   PetscDS        ds;

5991:   dm->dimEmbed = dim;
5992:   DMGetDS(dm, &ds);
5993:   PetscDSSetCoordinateDimension(ds, dim);
5994:   return(0);
5995: }

5997: /*@
5998:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6000:   Collective on dm

6002:   Input Parameter:
6003: . dm - The DM object

6005:   Output Parameter:
6006: . section - The PetscSection object

6008:   Level: intermediate

6010: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6011: @*/
6012: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6013: {
6014:   DM             cdm;

6020:   DMGetCoordinateDM(dm, &cdm);
6021:   DMGetLocalSection(cdm, section);
6022:   return(0);
6023: }

6025: /*@
6026:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6028:   Not Collective

6030:   Input Parameters:
6031: + dm      - The DM object
6032: . dim     - The embedding dimension, or PETSC_DETERMINE
6033: - section - The PetscSection object

6035:   Level: intermediate

6037: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6038: @*/
6039: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6040: {
6041:   DM             cdm;

6047:   DMGetCoordinateDM(dm, &cdm);
6048:   DMSetLocalSection(cdm, section);
6049:   if (dim == PETSC_DETERMINE) {
6050:     PetscInt d = PETSC_DEFAULT;
6051:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6053:     PetscSectionGetChart(section, &pStart, &pEnd);
6054:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6055:     pStart = PetscMax(vStart, pStart);
6056:     pEnd   = PetscMin(vEnd, pEnd);
6057:     for (v = pStart; v < pEnd; ++v) {
6058:       PetscSectionGetDof(section, v, &dd);
6059:       if (dd) {d = dd; break;}
6060:     }
6061:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6062:   }
6063:   return(0);
6064: }

6066: /*@C
6067:   DMGetPeriodicity - Get the description of mesh periodicity

6069:   Input Parameters:
6070: . dm      - The DM object

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

6078:   Level: developer

6080: .seealso: DMGetPeriodicity()
6081: @*/
6082: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6083: {
6086:   if (per)     *per     = dm->periodic;
6087:   if (L)       *L       = dm->L;
6088:   if (maxCell) *maxCell = dm->maxCell;
6089:   if (bd)      *bd      = dm->bdtype;
6090:   return(0);
6091: }

6093: /*@C
6094:   DMSetPeriodicity - Set the description of mesh periodicity

6096:   Input Parameters:
6097: + dm      - The DM object
6098: . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6099: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6100: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6101: - bd      - This describes the type of periodicity in each topological dimension

6103:   Level: developer

6105: .seealso: DMGetPeriodicity()
6106: @*/
6107: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6108: {
6109:   PetscInt       dim, d;

6118:   DMGetDimension(dm, &dim);
6119:   if (maxCell) {
6120:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6121:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6122:   }
6123:   if (L) {
6124:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6125:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6126:   }
6127:   if (bd) {
6128:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6129:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6130:   }
6131:   dm->periodic = per;
6132:   return(0);
6133: }

6135: /*@
6136:   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.

6138:   Input Parameters:
6139: + dm     - The DM
6140: . in     - The input coordinate point (dim numbers)
6141: - endpoint - Include the endpoint L_i

6143:   Output Parameter:
6144: . out - The localized coordinate point

6146:   Level: developer

6148: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6149: @*/
6150: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6151: {
6152:   PetscInt       dim, d;

6156:   DMGetCoordinateDim(dm, &dim);
6157:   if (!dm->maxCell) {
6158:     for (d = 0; d < dim; ++d) out[d] = in[d];
6159:   } else {
6160:     if (endpoint) {
6161:       for (d = 0; d < dim; ++d) {
6162:         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)) {
6163:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6164:         } else {
6165:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6166:         }
6167:       }
6168:     } else {
6169:       for (d = 0; d < dim; ++d) {
6170:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6171:       }
6172:     }
6173:   }
6174:   return(0);
6175: }

6177: /*
6178:   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.

6180:   Input Parameters:
6181: + dm     - The DM
6182: . dim    - The spatial dimension
6183: . anchor - The anchor point, the input point can be no more than maxCell away from it
6184: - in     - The input coordinate point (dim numbers)

6186:   Output Parameter:
6187: . out - The localized coordinate point

6189:   Level: developer

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

6193: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6194: */
6195: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6196: {
6197:   PetscInt d;

6200:   if (!dm->maxCell) {
6201:     for (d = 0; d < dim; ++d) out[d] = in[d];
6202:   } else {
6203:     for (d = 0; d < dim; ++d) {
6204:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6205:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6206:       } else {
6207:         out[d] = in[d];
6208:       }
6209:     }
6210:   }
6211:   return(0);
6212: }
6213: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6214: {
6215:   PetscInt d;

6218:   if (!dm->maxCell) {
6219:     for (d = 0; d < dim; ++d) out[d] = in[d];
6220:   } else {
6221:     for (d = 0; d < dim; ++d) {
6222:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6223:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6224:       } else {
6225:         out[d] = in[d];
6226:       }
6227:     }
6228:   }
6229:   return(0);
6230: }

6232: /*
6233:   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.

6235:   Input Parameters:
6236: + dm     - The DM
6237: . dim    - The spatial dimension
6238: . anchor - The anchor point, the input point can be no more than maxCell away from it
6239: . in     - The input coordinate delta (dim numbers)
6240: - out    - The input coordinate point (dim numbers)

6242:   Output Parameter:
6243: . out    - The localized coordinate in + out

6245:   Level: developer

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

6249: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6250: */
6251: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6252: {
6253:   PetscInt d;

6256:   if (!dm->maxCell) {
6257:     for (d = 0; d < dim; ++d) out[d] += in[d];
6258:   } else {
6259:     for (d = 0; d < dim; ++d) {
6260:       const PetscReal maxC = dm->maxCell[d];

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

6265:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6266:           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]));
6267:         out[d] += newCoord;
6268:       } else {
6269:         out[d] += in[d];
6270:       }
6271:     }
6272:   }
6273:   return(0);
6274: }

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

6279:   Not collective

6281:   Input Parameter:
6282: . dm - The DM

6284:   Output Parameter:
6285:   areLocalized - True if localized

6287:   Level: developer

6289: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6290: @*/
6291: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6292: {
6293:   DM             cdm;
6294:   PetscSection   coordSection;
6295:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6296:   PetscBool      isPlex, alreadyLocalized;

6302:   *areLocalized = PETSC_FALSE;

6304:   /* We need some generic way of refering to cells/vertices */
6305:   DMGetCoordinateDM(dm, &cdm);
6306:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6307:   if (!isPlex) return(0);

6309:   DMGetCoordinateSection(dm, &coordSection);
6310:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6311:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6312:   alreadyLocalized = PETSC_FALSE;
6313:   for (c = cStart; c < cEnd; ++c) {
6314:     if (c < sStart || c >= sEnd) continue;
6315:     PetscSectionGetDof(coordSection, c, &dof);
6316:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6317:   }
6318:   *areLocalized = alreadyLocalized;
6319:   return(0);
6320: }

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

6325:   Collective on dm

6327:   Input Parameter:
6328: . dm - The DM

6330:   Output Parameter:
6331:   areLocalized - True if localized

6333:   Level: developer

6335: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6336: @*/
6337: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6338: {
6339:   PetscBool      localized;

6345:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6346:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6347:   return(0);
6348: }

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

6353:   Collective on dm

6355:   Input Parameter:
6356: . dm - The DM

6358:   Level: developer

6360: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6361: @*/
6362: PetscErrorCode DMLocalizeCoordinates(DM dm)
6363: {
6364:   DM             cdm;
6365:   PetscSection   coordSection, cSection;
6366:   Vec            coordinates,  cVec;
6367:   PetscScalar   *coords, *coords2, *anchor, *localized;
6368:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6369:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6370:   PetscInt       maxHeight = 0, h;
6371:   PetscInt       *pStart = NULL, *pEnd = NULL;

6376:   if (!dm->periodic) return(0);
6377:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6378:   if (alreadyLocalized) return(0);

6380:   /* We need some generic way of refering to cells/vertices */
6381:   DMGetCoordinateDM(dm, &cdm);
6382:   {
6383:     PetscBool isplex;

6385:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6386:     if (isplex) {
6387:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6388:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6389:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6390:       pEnd = &pStart[maxHeight + 1];
6391:       newStart = vStart;
6392:       newEnd   = vEnd;
6393:       for (h = 0; h <= maxHeight; h++) {
6394:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6395:         newStart = PetscMin(newStart,pStart[h]);
6396:         newEnd   = PetscMax(newEnd,pEnd[h]);
6397:       }
6398:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6399:   }
6400:   DMGetCoordinatesLocal(dm, &coordinates);
6401:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6402:   DMGetCoordinateSection(dm, &coordSection);
6403:   VecGetBlockSize(coordinates, &bs);
6404:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6406:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6407:   PetscSectionSetNumFields(cSection, 1);
6408:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6409:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6410:   PetscSectionSetChart(cSection, newStart, newEnd);

6412:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6413:   localized = &anchor[bs];
6414:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6415:   for (h = 0; h <= maxHeight; h++) {
6416:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6418:     for (c = cStart; c < cEnd; ++c) {
6419:       PetscScalar *cellCoords = NULL;
6420:       PetscInt     b;

6422:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6423:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6424:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6425:       for (d = 0; d < dof/bs; ++d) {
6426:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6427:         for (b = 0; b < bs; b++) {
6428:           if (cellCoords[d*bs + b] != localized[b]) break;
6429:         }
6430:         if (b < bs) break;
6431:       }
6432:       if (d < dof/bs) {
6433:         if (c >= sStart && c < sEnd) {
6434:           PetscInt cdof;

6436:           PetscSectionGetDof(coordSection, c, &cdof);
6437:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6438:         }
6439:         PetscSectionSetDof(cSection, c, dof);
6440:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6441:       }
6442:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6443:     }
6444:   }
6445:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6446:   if (alreadyLocalizedGlobal) {
6447:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6448:     PetscSectionDestroy(&cSection);
6449:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6450:     return(0);
6451:   }
6452:   for (v = vStart; v < vEnd; ++v) {
6453:     PetscSectionGetDof(coordSection, v, &dof);
6454:     PetscSectionSetDof(cSection, v, dof);
6455:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6456:   }
6457:   PetscSectionSetUp(cSection);
6458:   PetscSectionGetStorageSize(cSection, &coordSize);
6459:   VecCreate(PETSC_COMM_SELF, &cVec);
6460:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6461:   VecSetBlockSize(cVec, bs);
6462:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6463:   VecSetType(cVec, VECSTANDARD);
6464:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6465:   VecGetArray(cVec, &coords2);
6466:   for (v = vStart; v < vEnd; ++v) {
6467:     PetscSectionGetDof(coordSection, v, &dof);
6468:     PetscSectionGetOffset(coordSection, v, &off);
6469:     PetscSectionGetOffset(cSection,     v, &off2);
6470:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6471:   }
6472:   for (h = 0; h <= maxHeight; h++) {
6473:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6475:     for (c = cStart; c < cEnd; ++c) {
6476:       PetscScalar *cellCoords = NULL;
6477:       PetscInt     b, cdof;

6479:       PetscSectionGetDof(cSection,c,&cdof);
6480:       if (!cdof) continue;
6481:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6482:       PetscSectionGetOffset(cSection, c, &off2);
6483:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6484:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6485:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6486:     }
6487:   }
6488:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6489:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6490:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6491:   VecRestoreArray(cVec, &coords2);
6492:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6493:   DMSetCoordinatesLocal(dm, cVec);
6494:   VecDestroy(&cVec);
6495:   PetscSectionDestroy(&cSection);
6496:   return(0);
6497: }

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

6502:   Collective on v (see explanation below)

6504:   Input Parameters:
6505: + dm - The DM
6506: . v - The Vec of points
6507: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6508: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6510:   Output Parameter:
6511: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6512: - cells - The PetscSF containing the ranks and local indices of the containing points.


6515:   Level: developer

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

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

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

6526: $    const PetscSFNode *cells;
6527: $    PetscInt           nFound;
6528: $    const PetscInt    *found;
6529: $
6530: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

6535: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6536: @*/
6537: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6538: {

6545:   if (*cellSF) {
6546:     PetscMPIInt result;

6549:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6550:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6551:   } else {
6552:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6553:   }
6554:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6555:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6556:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6557:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6558:   return(0);
6559: }

6561: /*@
6562:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6564:   Collective on dm

6566:   Input Parameter:
6567: . dm - The original DM

6569:   Output Parameter:
6570: . odm - The DM which provides the layout for output

6572:   Level: intermediate

6574: .seealso: VecView(), DMGetGlobalSection()
6575: @*/
6576: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6577: {
6578:   PetscSection   section;
6579:   PetscBool      hasConstraints, ghasConstraints;

6585:   DMGetLocalSection(dm, &section);
6586:   PetscSectionHasConstraints(section, &hasConstraints);
6587:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6588:   if (!ghasConstraints) {
6589:     *odm = dm;
6590:     return(0);
6591:   }
6592:   if (!dm->dmBC) {
6593:     PetscSection newSection, gsection;
6594:     PetscSF      sf;

6596:     DMClone(dm, &dm->dmBC);
6597:     DMCopyDisc(dm, dm->dmBC);
6598:     PetscSectionClone(section, &newSection);
6599:     DMSetLocalSection(dm->dmBC, newSection);
6600:     PetscSectionDestroy(&newSection);
6601:     DMGetPointSF(dm->dmBC, &sf);
6602:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6603:     DMSetGlobalSection(dm->dmBC, gsection);
6604:     PetscSectionDestroy(&gsection);
6605:   }
6606:   *odm = dm->dmBC;
6607:   return(0);
6608: }

6610: /*@
6611:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6613:   Input Parameter:
6614: . dm - The original DM

6616:   Output Parameters:
6617: + num - The output sequence number
6618: - val - The output sequence value

6620:   Level: intermediate

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

6625: .seealso: VecView()
6626: @*/
6627: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6628: {
6633:   return(0);
6634: }

6636: /*@
6637:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6639:   Input Parameters:
6640: + dm - The original DM
6641: . num - The output sequence number
6642: - val - The output sequence value

6644:   Level: intermediate

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

6649: .seealso: VecView()
6650: @*/
6651: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6652: {
6655:   dm->outputSequenceNum = num;
6656:   dm->outputSequenceVal = val;
6657:   return(0);
6658: }

6660: /*@C
6661:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

6663:   Input Parameters:
6664: + dm   - The original DM
6665: . name - The sequence name
6666: - num  - The output sequence number

6668:   Output Parameter:
6669: . val  - The output sequence value

6671:   Level: intermediate

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

6676: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6677: @*/
6678: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6679: {
6680:   PetscBool      ishdf5;

6687:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
6688:   if (ishdf5) {
6689: #if defined(PETSC_HAVE_HDF5)
6690:     PetscScalar value;

6692:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6693:     *val = PetscRealPart(value);
6694: #endif
6695:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6696:   return(0);
6697: }

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

6702:   Not collective

6704:   Input Parameter:
6705: . dm - The DM

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

6710:   Level: beginner

6712: .seealso: DMSetUseNatural(), DMCreate()
6713: @*/
6714: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6715: {
6719:   *useNatural = dm->useNatural;
6720:   return(0);
6721: }

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

6726:   Collective on dm

6728:   Input Parameters:
6729: + dm - The DM
6730: - useNatural - The flag to build the mapping to a natural order during distribution

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

6734:   Level: beginner

6736: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6737: @*/
6738: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6739: {
6743:   dm->useNatural = useNatural;
6744:   return(0);
6745: }


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

6751:   Not Collective

6753:   Input Parameters:
6754: + dm   - The DM object
6755: - name - The label name

6757:   Level: intermediate

6759: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6760: @*/
6761: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6762: {
6763:   PetscBool      flg;
6764:   DMLabel        label;

6770:   DMHasLabel(dm, name, &flg);
6771:   if (!flg) {
6772:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6773:     DMAddLabel(dm, label);
6774:     DMLabelDestroy(&label);
6775:   }
6776:   return(0);
6777: }

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

6782:   Not Collective

6784:   Input Parameters:
6785: + dm   - The DM object
6786: . name - The label name
6787: - point - The mesh point

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

6792:   Level: beginner

6794: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6795: @*/
6796: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6797: {
6798:   DMLabel        label;

6804:   DMGetLabel(dm, name, &label);
6805:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6806:   DMLabelGetValue(label, point, value);
6807:   return(0);
6808: }

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

6813:   Not Collective

6815:   Input Parameters:
6816: + dm   - The DM object
6817: . name - The label name
6818: . point - The mesh point
6819: - value - The label value for this point

6821:   Output Parameter:

6823:   Level: beginner

6825: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6826: @*/
6827: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6828: {
6829:   DMLabel        label;

6835:   DMGetLabel(dm, name, &label);
6836:   if (!label) {
6837:     DMCreateLabel(dm, name);
6838:     DMGetLabel(dm, name, &label);
6839:   }
6840:   DMLabelSetValue(label, point, value);
6841:   return(0);
6842: }

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

6847:   Not Collective

6849:   Input Parameters:
6850: + dm   - The DM object
6851: . name - The label name
6852: . point - The mesh point
6853: - value - The label value for this point

6855:   Output Parameter:

6857:   Level: beginner

6859: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6860: @*/
6861: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6862: {
6863:   DMLabel        label;

6869:   DMGetLabel(dm, name, &label);
6870:   if (!label) return(0);
6871:   DMLabelClearValue(label, point, value);
6872:   return(0);
6873: }

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

6878:   Not Collective

6880:   Input Parameters:
6881: + dm   - The DM object
6882: - name - The label name

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

6887:   Level: beginner

6889: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6890: @*/
6891: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6892: {
6893:   DMLabel        label;

6900:   DMGetLabel(dm, name, &label);
6901:   *size = 0;
6902:   if (!label) return(0);
6903:   DMLabelGetNumValues(label, size);
6904:   return(0);
6905: }

6907: /*@C
6908:   DMGetLabelIdIS - Get the integer ids in a label

6910:   Not Collective

6912:   Input Parameters:
6913: + mesh - The DM object
6914: - name - The label name

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

6919:   Level: beginner

6921: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6922: @*/
6923: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6924: {
6925:   DMLabel        label;

6932:   DMGetLabel(dm, name, &label);
6933:   *ids = NULL;
6934:  if (label) {
6935:     DMLabelGetValueIS(label, ids);
6936:   } else {
6937:     /* returning an empty IS */
6938:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
6939:   }
6940:   return(0);
6941: }

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

6946:   Not Collective

6948:   Input Parameters:
6949: + dm - The DM object
6950: . name - The label name
6951: - value - The stratum value

6953:   Output Parameter:
6954: . size - The stratum size

6956:   Level: beginner

6958: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6959: @*/
6960: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6961: {
6962:   DMLabel        label;

6969:   DMGetLabel(dm, name, &label);
6970:   *size = 0;
6971:   if (!label) return(0);
6972:   DMLabelGetStratumSize(label, value, size);
6973:   return(0);
6974: }

6976: /*@C
6977:   DMGetStratumIS - Get the points in a label stratum

6979:   Not Collective

6981:   Input Parameters:
6982: + dm - The DM object
6983: . name - The label name
6984: - value - The stratum value

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

6989:   Level: beginner

6991: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6992: @*/
6993: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6994: {
6995:   DMLabel        label;

7002:   DMGetLabel(dm, name, &label);
7003:   *points = NULL;
7004:   if (!label) return(0);
7005:   DMLabelGetStratumIS(label, value, points);
7006:   return(0);
7007: }

7009: /*@C
7010:   DMSetStratumIS - Set the points in a label stratum

7012:   Not Collective

7014:   Input Parameters:
7015: + dm - The DM object
7016: . name - The label name
7017: . value - The stratum value
7018: - points - The stratum points

7020:   Level: beginner

7022: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7023: @*/
7024: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7025: {
7026:   DMLabel        label;

7033:   DMGetLabel(dm, name, &label);
7034:   if (!label) return(0);
7035:   DMLabelSetStratumIS(label, value, points);
7036:   return(0);
7037: }

7039: /*@C
7040:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7042:   Not Collective

7044:   Input Parameters:
7045: + dm   - The DM object
7046: . name - The label name
7047: - value - The label value for this point

7049:   Output Parameter:

7051:   Level: beginner

7053: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7054: @*/
7055: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7056: {
7057:   DMLabel        label;

7063:   DMGetLabel(dm, name, &label);
7064:   if (!label) return(0);
7065:   DMLabelClearStratum(label, value);
7066:   return(0);
7067: }

7069: /*@
7070:   DMGetNumLabels - Return the number of labels defined by the mesh

7072:   Not Collective

7074:   Input Parameter:
7075: . dm   - The DM object

7077:   Output Parameter:
7078: . numLabels - the number of Labels

7080:   Level: intermediate

7082: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7083: @*/
7084: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7085: {
7086:   DMLabelLink next = dm->labels;
7087:   PetscInt  n    = 0;

7092:   while (next) {++n; next = next->next;}
7093:   *numLabels = n;
7094:   return(0);
7095: }

7097: /*@C
7098:   DMGetLabelName - Return the name of nth label

7100:   Not Collective

7102:   Input Parameters:
7103: + dm - The DM object
7104: - n  - the label number

7106:   Output Parameter:
7107: . name - the label name

7109:   Level: intermediate

7111: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7112: @*/
7113: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7114: {
7115:   DMLabelLink    next = dm->labels;
7116:   PetscInt       l    = 0;

7122:   while (next) {
7123:     if (l == n) {
7124:       PetscObjectGetName((PetscObject) next->label, name);
7125:       return(0);
7126:     }
7127:     ++l;
7128:     next = next->next;
7129:   }
7130:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7131: }

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

7136:   Not Collective

7138:   Input Parameters:
7139: + dm   - The DM object
7140: - name - The label name

7142:   Output Parameter:
7143: . hasLabel - PETSC_TRUE if the label is present

7145:   Level: intermediate

7147: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7148: @*/
7149: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7150: {
7151:   DMLabelLink    next = dm->labels;
7152:   const char    *lname;

7159:   *hasLabel = PETSC_FALSE;
7160:   while (next) {
7161:     PetscObjectGetName((PetscObject) next->label, &lname);
7162:     PetscStrcmp(name, lname, hasLabel);
7163:     if (*hasLabel) break;
7164:     next = next->next;
7165:   }
7166:   return(0);
7167: }

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

7172:   Not Collective

7174:   Input Parameters:
7175: + dm   - The DM object
7176: - name - The label name

7178:   Output Parameter:
7179: . label - The DMLabel, or NULL if the label is absent

7181:   Level: intermediate

7183: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7184: @*/
7185: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7186: {
7187:   DMLabelLink    next = dm->labels;
7188:   PetscBool      hasLabel;
7189:   const char    *lname;

7196:   *label = NULL;
7197:   while (next) {
7198:     PetscObjectGetName((PetscObject) next->label, &lname);
7199:     PetscStrcmp(name, lname, &hasLabel);
7200:     if (hasLabel) {
7201:       *label = next->label;
7202:       break;
7203:     }
7204:     next = next->next;
7205:   }
7206:   return(0);
7207: }

7209: /*@C
7210:   DMGetLabelByNum - Return the nth label

7212:   Not Collective

7214:   Input Parameters:
7215: + dm - The DM object
7216: - n  - the label number

7218:   Output Parameter:
7219: . label - the label

7221:   Level: intermediate

7223: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7224: @*/
7225: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7226: {
7227:   DMLabelLink next = dm->labels;
7228:   PetscInt    l    = 0;

7233:   while (next) {
7234:     if (l == n) {
7235:       *label = next->label;
7236:       return(0);
7237:     }
7238:     ++l;
7239:     next = next->next;
7240:   }
7241:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7242: }

7244: /*@C
7245:   DMAddLabel - Add the label to this mesh

7247:   Not Collective

7249:   Input Parameters:
7250: + dm   - The DM object
7251: - label - The DMLabel

7253:   Level: developer

7255: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7256: @*/
7257: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7258: {
7259:   DMLabelLink    l, *p, tmpLabel;
7260:   PetscBool      hasLabel;
7261:   const char    *lname;
7262:   PetscBool      flg;

7267:   PetscObjectGetName((PetscObject) label, &lname);
7268:   DMHasLabel(dm, lname, &hasLabel);
7269:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7270:   PetscCalloc1(1, &tmpLabel);
7271:   tmpLabel->label  = label;
7272:   tmpLabel->output = PETSC_TRUE;
7273:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7274:   *p = tmpLabel;
7275:   PetscObjectReference((PetscObject)label);
7276:   PetscStrcmp(lname, "depth", &flg);
7277:   if (flg) dm->depthLabel = label;
7278:   PetscStrcmp(lname, "celltype", &flg);
7279:   if (flg) dm->celltypeLabel = label;
7280:   return(0);
7281: }

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

7286:   Not Collective

7288:   Input Parameters:
7289: + dm   - The DM object
7290: - name - The label name

7292:   Output Parameter:
7293: . label - The DMLabel, or NULL if the label is absent

7295:   Level: developer

7297:   Notes:
7298:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7299:   DMLabelDestroy() on the label.

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

7305: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7306: @*/
7307: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7308: {
7309:   DMLabelLink    link, *pnext;
7310:   PetscBool      hasLabel;
7311:   const char    *lname;

7317:   if (label) {
7319:     *label = NULL;
7320:   }
7321:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7322:     PetscObjectGetName((PetscObject) link->label, &lname);
7323:     PetscStrcmp(name, lname, &hasLabel);
7324:     if (hasLabel) {
7325:       *pnext = link->next; /* Remove from list */
7326:       PetscStrcmp(name, "depth", &hasLabel);
7327:       if (hasLabel) dm->depthLabel = NULL;
7328:       PetscStrcmp(name, "celltype", &hasLabel);
7329:       if (hasLabel) dm->celltypeLabel = NULL;
7330:       if (label) *label = link->label;
7331:       else       {DMLabelDestroy(&link->label);}
7332:       PetscFree(link);
7333:       break;
7334:     }
7335:   }
7336:   return(0);
7337: }

7339: /*@
7340:   DMRemoveLabelBySelf - Remove the label from this mesh

7342:   Not Collective

7344:   Input Parameters:
7345: + dm   - The DM object
7346: . label - (Optional) The DMLabel to be removed from the DM
7347: - failNotFound - Should it fail if the label is not found in the DM?

7349:   Level: developer

7351:   Notes:
7352:   Only exactly the same instance is removed if found, name match is ignored.
7353:   If the DM has an exclusive reference to the label, it gets destroyed and
7354:   *label nullified.

7356: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7357: @*/
7358: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7359: {
7360:   DMLabelLink    link, *pnext;
7361:   PetscBool      hasLabel = PETSC_FALSE;

7367:   if (!*label && !failNotFound) return(0);
7370:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7371:     if (*label == link->label) {
7372:       hasLabel = PETSC_TRUE;
7373:       *pnext = link->next; /* Remove from list */
7374:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7375:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7376:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7377:       DMLabelDestroy(&link->label);
7378:       PetscFree(link);
7379:       break;
7380:     }
7381:   }
7382:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7383:   return(0);
7384: }

7386: /*@C
7387:   DMGetLabelOutput - Get the output flag for a given label

7389:   Not Collective

7391:   Input Parameters:
7392: + dm   - The DM object
7393: - name - The label name

7395:   Output Parameter:
7396: . output - The flag for output

7398:   Level: developer

7400: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7401: @*/
7402: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7403: {
7404:   DMLabelLink    next = dm->labels;
7405:   const char    *lname;

7412:   while (next) {
7413:     PetscBool flg;

7415:     PetscObjectGetName((PetscObject) next->label, &lname);
7416:     PetscStrcmp(name, lname, &flg);
7417:     if (flg) {*output = next->output; return(0);}
7418:     next = next->next;
7419:   }
7420:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7421: }

7423: /*@C
7424:   DMSetLabelOutput - Set the output flag for a given label

7426:   Not Collective

7428:   Input Parameters:
7429: + dm     - The DM object
7430: . name   - The label name
7431: - output - The flag for output

7433:   Level: developer

7435: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7436: @*/
7437: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7438: {
7439:   DMLabelLink    next = dm->labels;
7440:   const char    *lname;

7446:   while (next) {
7447:     PetscBool flg;

7449:     PetscObjectGetName((PetscObject) next->label, &lname);
7450:     PetscStrcmp(name, lname, &flg);
7451:     if (flg) {next->output = output; return(0);}
7452:     next = next->next;
7453:   }
7454:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7455: }

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

7460:   Collective on dmA

7462:   Input Parameter:
7463: + dmA - The DM object with initial labels
7464: . dmB - The DM object with copied labels
7465: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7466: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7468:   Level: intermediate

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

7472: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7473: @*/
7474: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7475: {
7476:   DMLabel        label, labelNew;
7477:   const char    *name;
7478:   PetscBool      flg;
7479:   DMLabelLink    link;

7487:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7488:   if (dmA == dmB) return(0);
7489:   for (link=dmA->labels; link; link=link->next) {
7490:     label=link->label;
7491:     PetscObjectGetName((PetscObject)label, &name);
7492:     if (!all) {
7493:       PetscStrcmp(name, "depth", &flg);
7494:       if (flg) continue;
7495:       PetscStrcmp(name, "dim", &flg);
7496:       if (flg) continue;
7497:       PetscStrcmp(name, "celltype", &flg);
7498:       if (flg) continue;
7499:     }
7500:     if (mode==PETSC_COPY_VALUES) {
7501:       DMLabelDuplicate(label, &labelNew);
7502:     } else {
7503:       labelNew = label;
7504:     }
7505:     DMAddLabel(dmB, labelNew);
7506:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7507:   }
7508:   return(0);
7509: }

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

7514:   Input Parameter:
7515: . dm - The DM object

7517:   Output Parameter:
7518: . cdm - The coarse DM

7520:   Level: intermediate

7522: .seealso: DMSetCoarseDM()
7523: @*/
7524: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7525: {
7529:   *cdm = dm->coarseMesh;
7530:   return(0);
7531: }

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

7536:   Input Parameters:
7537: + dm - The DM object
7538: - cdm - The coarse DM

7540:   Level: intermediate

7542: .seealso: DMGetCoarseDM()
7543: @*/
7544: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7545: {

7551:   PetscObjectReference((PetscObject)cdm);
7552:   DMDestroy(&dm->coarseMesh);
7553:   dm->coarseMesh = cdm;
7554:   return(0);
7555: }

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

7560:   Input Parameter:
7561: . dm - The DM object

7563:   Output Parameter:
7564: . fdm - The fine DM

7566:   Level: intermediate

7568: .seealso: DMSetFineDM()
7569: @*/
7570: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7571: {
7575:   *fdm = dm->fineMesh;
7576:   return(0);
7577: }

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

7582:   Input Parameters:
7583: + dm - The DM object
7584: - fdm - The fine DM

7586:   Level: intermediate

7588: .seealso: DMGetFineDM()
7589: @*/
7590: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7591: {

7597:   PetscObjectReference((PetscObject)fdm);
7598:   DMDestroy(&dm->fineMesh);
7599:   dm->fineMesh = fdm;
7600:   return(0);
7601: }

7603: /*=== DMBoundary code ===*/

7605: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7606: {
7607:   PetscInt       d;

7611:   for (d = 0; d < dm->Nds; ++d) {
7612:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7613:   }
7614:   return(0);
7615: }

7617: /*@C
7618:   DMAddBoundary - Add a boundary condition to the model

7620:   Collective on dm

7622:   Input Parameters:
7623: + dm          - The DM, with a PetscDS that matches the problem being constrained
7624: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7625: . name        - The BC name
7626: . labelname   - The label defining constrained points
7627: . field       - The field to constrain
7628: . numcomps    - The number of constrained field components (0 will constrain all fields)
7629: . comps       - An array of constrained component numbers
7630: . bcFunc      - A pointwise function giving boundary values
7631: . numids      - The number of DMLabel ids for constrained points
7632: . ids         - An array of ids for constrained points
7633: - ctx         - An optional user context for bcFunc

7635:   Options Database Keys:
7636: + -bc_<boundary name> <num> - Overrides the boundary ids
7637: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7639:   Level: developer

7641: .seealso: DMGetBoundary()
7642: @*/
7643: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
7644: {
7645:   PetscDS        ds;

7654:   DMGetDS(dm, &ds);
7655:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
7656:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);
7657:   return(0);
7658: }

7660: /*@
7661:   DMGetNumBoundary - Get the number of registered BC

7663:   Input Parameters:
7664: . dm - The mesh object

7666:   Output Parameters:
7667: . numBd - The number of BC

7669:   Level: intermediate

7671: .seealso: DMAddBoundary(), DMGetBoundary()
7672: @*/
7673: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7674: {
7675:   PetscDS        ds;

7680:   DMGetDS(dm, &ds);
7681:   PetscDSGetNumBoundary(ds, numBd);
7682:   return(0);
7683: }

7685: /*@C
7686:   DMGetBoundary - Get a model boundary condition

7688:   Input Parameters:
7689: + dm          - The mesh object
7690: - bd          - The BC number

7692:   Output Parameters:
7693: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7694: . name        - The BC name
7695: . labelname   - The label defining constrained points
7696: . field       - The field to constrain
7697: . numcomps    - The number of constrained field components
7698: . comps       - An array of constrained component numbers
7699: . bcFunc      - A pointwise function giving boundary values
7700: . numids      - The number of DMLabel ids for constrained points
7701: . ids         - An array of ids for constrained points
7702: - ctx         - An optional user context for bcFunc

7704:   Options Database Keys:
7705: + -bc_<boundary name> <num> - Overrides the boundary ids
7706: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7708:   Level: developer

7710: .seealso: DMAddBoundary()
7711: @*/
7712: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
7713: {
7714:   PetscDS        ds;

7719:   DMGetDS(dm, &ds);
7720:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);
7721:   return(0);
7722: }

7724: static PetscErrorCode DMPopulateBoundary(DM dm)
7725: {
7726:   PetscDS        ds;
7727:   DMBoundary    *lastnext;
7728:   DSBoundary     dsbound;

7732:   DMGetDS(dm, &ds);
7733:   dsbound = ds->boundary;
7734:   if (dm->boundary) {
7735:     DMBoundary next = dm->boundary;

7737:     /* quick check to see if the PetscDS has changed */
7738:     if (next->dsboundary == dsbound) return(0);
7739:     /* the PetscDS has changed: tear down and rebuild */
7740:     while (next) {
7741:       DMBoundary b = next;

7743:       next = b->next;
7744:       PetscFree(b);
7745:     }
7746:     dm->boundary = NULL;
7747:   }

7749:   lastnext = &(dm->boundary);
7750:   while (dsbound) {
7751:     DMBoundary dmbound;

7753:     PetscNew(&dmbound);
7754:     dmbound->dsboundary = dsbound;
7755:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
7756:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
7757:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7758:     *lastnext = dmbound;
7759:     lastnext = &(dmbound->next);
7760:     dsbound = dsbound->next;
7761:   }
7762:   return(0);
7763: }

7765: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7766: {
7767:   DMBoundary     b;

7773:   *isBd = PETSC_FALSE;
7774:   DMPopulateBoundary(dm);
7775:   b = dm->boundary;
7776:   while (b && !(*isBd)) {
7777:     DMLabel    label = b->label;
7778:     DSBoundary dsb = b->dsboundary;

7780:     if (label) {
7781:       PetscInt i;

7783:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7784:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
7785:       }
7786:     }
7787:     b = b->next;
7788:   }
7789:   return(0);
7790: }

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

7795:   Collective on DM

7797:   Input Parameters:
7798: + dm      - The DM
7799: . time    - The time
7800: . funcs   - The coordinate functions to evaluate, one per field
7801: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7802: - mode    - The insertion mode for values

7804:   Output Parameter:
7805: . X - vector

7807:    Calling sequence of func:
7808: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7810: +  dim - The spatial dimension
7811: .  x   - The coordinates
7812: .  Nf  - The number of fields
7813: .  u   - The output field values
7814: -  ctx - optional user-defined function context

7816:   Level: developer

7818: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7819: @*/
7820: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7821: {
7822:   Vec            localX;

7827:   DMGetLocalVector(dm, &localX);
7828:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7829:   DMLocalToGlobalBegin(dm, localX, mode, X);
7830:   DMLocalToGlobalEnd(dm, localX, mode, X);
7831:   DMRestoreLocalVector(dm, &localX);
7832:   return(0);
7833: }

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

7838:   Not collective

7840:   Input Parameters:
7841: + dm      - The DM
7842: . time    - The time
7843: . funcs   - The coordinate functions to evaluate, one per field
7844: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7845: - mode    - The insertion mode for values

7847:   Output Parameter:
7848: . localX - vector

7850:    Calling sequence of func:
7851: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7853: +  dim - The spatial dimension
7854: .  x   - The coordinates
7855: .  Nf  - The number of fields
7856: .  u   - The output field values
7857: -  ctx - optional user-defined function context

7859:   Level: developer

7861: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7862: @*/
7863: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7864: {

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

7875: /*@C
7876:   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.

7878:   Collective on DM

7880:   Input Parameters:
7881: + dm      - The DM
7882: . time    - The time
7883: . label   - The DMLabel selecting the portion of the mesh for projection
7884: . funcs   - The coordinate functions to evaluate, one per field
7885: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7886: - mode    - The insertion mode for values

7888:   Output Parameter:
7889: . X - vector

7891:    Calling sequence of func:
7892: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7894: +  dim - The spatial dimension
7895: .  x   - The coordinates
7896: .  Nf  - The number of fields
7897: .  u   - The output field values
7898: -  ctx - optional user-defined function context

7900:   Level: developer

7902: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
7903: @*/
7904: 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)
7905: {
7906:   Vec            localX;

7911:   DMGetLocalVector(dm, &localX);
7912:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7913:   DMLocalToGlobalBegin(dm, localX, mode, X);
7914:   DMLocalToGlobalEnd(dm, localX, mode, X);
7915:   DMRestoreLocalVector(dm, &localX);
7916:   return(0);
7917: }

7919: /*@C
7920:   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.

7922:   Not collective

7924:   Input Parameters:
7925: + dm      - The DM
7926: . time    - The time
7927: . label   - The DMLabel selecting the portion of the mesh for projection
7928: . funcs   - The coordinate functions to evaluate, one per field
7929: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7930: - mode    - The insertion mode for values

7932:   Output Parameter:
7933: . localX - vector

7935:    Calling sequence of func:
7936: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7938: +  dim - The spatial dimension
7939: .  x   - The coordinates
7940: .  Nf  - The number of fields
7941: .  u   - The output field values
7942: -  ctx - optional user-defined function context

7944:   Level: developer

7946: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7947: @*/
7948: 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)
7949: {

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

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

7963:   Not collective

7965:   Input Parameters:
7966: + dm      - The DM
7967: . time    - The time
7968: . localU  - The input field vector
7969: . funcs   - The functions to evaluate, one per field
7970: - mode    - The insertion mode for values

7972:   Output Parameter:
7973: . localX  - The output vector

7975:    Calling sequence of func:
7976: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7977: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7978: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7979: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7981: +  dim          - The spatial dimension
7982: .  Nf           - The number of input fields
7983: .  NfAux        - The number of input auxiliary fields
7984: .  uOff         - The offset of each field in u[]
7985: .  uOff_x       - The offset of each field in u_x[]
7986: .  u            - The field values at this point in space
7987: .  u_t          - The field time derivative at this point in space (or NULL)
7988: .  u_x          - The field derivatives at this point in space
7989: .  aOff         - The offset of each auxiliary field in u[]
7990: .  aOff_x       - The offset of each auxiliary field in u_x[]
7991: .  a            - The auxiliary field values at this point in space
7992: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7993: .  a_x          - The auxiliary field derivatives at this point in space
7994: .  t            - The current time
7995: .  x            - The coordinates of this point
7996: .  numConstants - The number of constants
7997: .  constants    - The value of each constant
7998: -  f            - The value of the function at this point in space

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

8005:   Level: intermediate

8007: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8008: @*/
8009: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8010:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8011:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8012:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8013:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8014:                                    InsertMode mode, Vec localX)
8015: {

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

8027: /*@C
8028:   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.

8030:   Not collective

8032:   Input Parameters:
8033: + dm      - The DM
8034: . time    - The time
8035: . label   - The DMLabel marking the portion of the domain to output
8036: . numIds  - The number of label ids to use
8037: . ids     - The label ids to use for marking
8038: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8039: . comps   - The components to set in the output, or NULL for all components
8040: . localU  - The input field vector
8041: . funcs   - The functions to evaluate, one per field
8042: - mode    - The insertion mode for values

8044:   Output Parameter:
8045: . localX  - The output vector

8047:    Calling sequence of func:
8048: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8049: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8050: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8051: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8053: +  dim          - The spatial dimension
8054: .  Nf           - The number of input fields
8055: .  NfAux        - The number of input auxiliary fields
8056: .  uOff         - The offset of each field in u[]
8057: .  uOff_x       - The offset of each field in u_x[]
8058: .  u            - The field values at this point in space
8059: .  u_t          - The field time derivative at this point in space (or NULL)
8060: .  u_x          - The field derivatives at this point in space
8061: .  aOff         - The offset of each auxiliary field in u[]
8062: .  aOff_x       - The offset of each auxiliary field in u_x[]
8063: .  a            - The auxiliary field values at this point in space
8064: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8065: .  a_x          - The auxiliary field derivatives at this point in space
8066: .  t            - The current time
8067: .  x            - The coordinates of this point
8068: .  numConstants - The number of constants
8069: .  constants    - The value of each constant
8070: -  f            - The value of the function at this point in space

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

8077:   Level: intermediate

8079: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8080: @*/
8081: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8082:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8083:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8084:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8085:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8086:                                         InsertMode mode, Vec localX)
8087: {

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

8099: /*@C
8100:   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.

8102:   Not collective

8104:   Input Parameters:
8105: + dm      - The DM
8106: . time    - The time
8107: . label   - The DMLabel marking the portion of the domain boundary to output
8108: . numIds  - The number of label ids to use
8109: . ids     - The label ids to use for marking
8110: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8111: . comps   - The components to set in the output, or NULL for all components
8112: . localU  - The input field vector
8113: . funcs   - The functions to evaluate, one per field
8114: - mode    - The insertion mode for values

8116:   Output Parameter:
8117: . localX  - The output vector

8119:    Calling sequence of func:
8120: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8121: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8122: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8123: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8125: +  dim          - The spatial dimension
8126: .  Nf           - The number of input fields
8127: .  NfAux        - The number of input auxiliary fields
8128: .  uOff         - The offset of each field in u[]
8129: .  uOff_x       - The offset of each field in u_x[]
8130: .  u            - The field values at this point in space
8131: .  u_t          - The field time derivative at this point in space (or NULL)
8132: .  u_x          - The field derivatives at this point in space
8133: .  aOff         - The offset of each auxiliary field in u[]
8134: .  aOff_x       - The offset of each auxiliary field in u_x[]
8135: .  a            - The auxiliary field values at this point in space
8136: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8137: .  a_x          - The auxiliary field derivatives at this point in space
8138: .  t            - The current time
8139: .  x            - The coordinates of this point
8140: .  n            - The face normal
8141: .  numConstants - The number of constants
8142: .  constants    - The value of each constant
8143: -  f            - The value of the function at this point in space

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

8151:   Level: intermediate

8153: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8154: @*/
8155: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8156:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8157:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8158:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8159:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8160:                                           InsertMode mode, Vec localX)
8161: {

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

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

8176:   Input Parameters:
8177: + dm    - The DM
8178: . time  - The time
8179: . funcs - The functions to evaluate for each field component
8180: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8181: - X     - The coefficient vector u_h, a global vector

8183:   Output Parameter:
8184: . diff - The diff ||u - u_h||_2

8186:   Level: developer

8188: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8189: @*/
8190: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8191: {

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

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

8205:   Collective on dm

8207:   Input Parameters:
8208: + dm    - The DM
8209: , time  - The time
8210: . funcs - The gradient functions to evaluate for each field component
8211: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8212: . X     - The coefficient vector u_h, a global vector
8213: - n     - The vector to project along

8215:   Output Parameter:
8216: . diff - The diff ||(grad u - grad u_h) . n||_2

8218:   Level: developer

8220: .seealso: DMProjectFunction(), DMComputeL2Diff()
8221: @*/
8222: 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)
8223: {

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

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

8237:   Collective on dm

8239:   Input Parameters:
8240: + dm    - The DM
8241: . time  - The time
8242: . funcs - The functions to evaluate for each field component
8243: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8244: - X     - The coefficient vector u_h, a global vector

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

8249:   Level: developer

8251: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8252: @*/
8253: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8254: {

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

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

8269:   Collective on dm

8271:   Input parameters:
8272: + dm - the pre-adaptation DM object
8273: - label - label with the flags

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

8278:   Level: intermediate

8280: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8281: @*/
8282: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8283: {

8290:   *dmAdapt = NULL;
8291:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8292:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8293:   return(0);
8294: }

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

8299:   Input Parameters:
8300: + dm - The DM object
8301: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8302: - 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_".

8304:   Output Parameter:
8305: . dmAdapt  - Pointer to the DM object containing the adapted mesh

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

8309:   Level: advanced

8311: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8312: @*/
8313: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8314: {

8322:   *dmAdapt = NULL;
8323:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8324:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8325:   return(0);
8326: }

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

8331:  Not Collective

8333:  Input Parameter:
8334:  . dm    - The DM

8336:  Output Parameter:
8337:  . nranks - the number of neighbours
8338:  . ranks - the neighbors ranks

8340:  Notes:
8341:  Do not free the array, it is freed when the DM is destroyed.

8343:  Level: beginner

8345:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8346: @*/
8347: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8348: {

8353:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8354:   (dm->ops->getneighbors)(dm,nranks,ranks);
8355:   return(0);
8356: }

8358: #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */

8360: /*
8361:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8362:     This has be a different function because it requires DM which is not defined in the Mat library
8363: */
8364: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8365: {

8369:   if (coloring->ctype == IS_COLORING_LOCAL) {
8370:     Vec x1local;
8371:     DM  dm;
8372:     MatGetDM(J,&dm);
8373:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8374:     DMGetLocalVector(dm,&x1local);
8375:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8376:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8377:     x1   = x1local;
8378:   }
8379:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8380:   if (coloring->ctype == IS_COLORING_LOCAL) {
8381:     DM  dm;
8382:     MatGetDM(J,&dm);
8383:     DMRestoreLocalVector(dm,&x1);
8384:   }
8385:   return(0);
8386: }

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

8391:     Input Parameter:
8392: .    coloring - the MatFDColoring object

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

8397:     Level: advanced

8399: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8400: @*/
8401: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8402: {
8404:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8405:   return(0);
8406: }

8408: /*@
8409:     DMGetCompatibility - determine if two DMs are compatible

8411:     Collective

8413:     Input Parameters:
8414: +    dm1 - the first DM
8415: -    dm2 - the second DM

8417:     Output Parameters:
8418: +    compatible - whether or not the two DMs are compatible
8419: -    set - whether or not the compatible value was set

8421:     Notes:
8422:     Two DMs are deemed compatible if they represent the same parallel decomposition
8423:     of the same topology. This implies that the section (field data) on one
8424:     "makes sense" with respect to the topology and parallel decomposition of the other.
8425:     Loosely speaking, compatible DMs represent the same domain and parallel
8426:     decomposition, but hold different data.

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

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

8436:     Consider the operation of summing data living on a 2-dof DMDA to data living
8437:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8438: .vb
8439:   ...
8440:   DMGetCompatibility(da1,da2,&compatible,&set);
8441:   if (set && compatible)  {
8442:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8443:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8444:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8445:     for (j=y; j<y+n; ++j) {
8446:       for (i=x; i<x+m, ++i) {
8447:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8448:       }
8449:     }
8450:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8451:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8452:   } else {
8453:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8454:   }
8455:   ...
8456: .ve

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

8463:     A DM is always compatible with itself.

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

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

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

8482:     Level: advanced

8484: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8485: @*/

8487: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8488: {
8490:   PetscMPIInt    compareResult;
8491:   DMType         type,type2;
8492:   PetscBool      sameType;


8498:   /* Declare a DM compatible with itself */
8499:   if (dm1 == dm2) {
8500:     *set = PETSC_TRUE;
8501:     *compatible = PETSC_TRUE;
8502:     return(0);
8503:   }

8505:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8506:      communicator. Note that this does not preclude compatibility with
8507:      DMs living on "congruent" or "similar" communicators, but this must be
8508:      determined by the implementation-specific logic */
8509:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
8510:   if (compareResult == MPI_UNEQUAL) {
8511:     *set = PETSC_TRUE;
8512:     *compatible = PETSC_FALSE;
8513:     return(0);
8514:   }

8516:   /* Pass to the implementation-specific routine, if one exists. */
8517:   if (dm1->ops->getcompatibility) {
8518:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
8519:     if (*set) return(0);
8520:   }

8522:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8523:      with an implementation of this function from dm2 */
8524:   DMGetType(dm1,&type);
8525:   DMGetType(dm2,&type2);
8526:   PetscStrcmp(type,type2,&sameType);
8527:   if (!sameType && dm2->ops->getcompatibility) {
8528:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
8529:   } else {
8530:     *set = PETSC_FALSE;
8531:   }
8532:   return(0);
8533: }

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

8538:   Logically Collective on DM

8540:   Input Parameters:
8541: + DM - the DM
8542: . f - the monitor function
8543: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8544: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

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

8550:   Notes:
8551:   Several different monitoring routines may be set by calling
8552:   DMMonitorSet() multiple times; all will be called in the
8553:   order in which they were set.

8555:   Fortran Notes:
8556:   Only a single monitor function can be set for each DM object

8558:   Level: intermediate

8560: .seealso: DMMonitorCancel()
8561: @*/
8562: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8563: {
8564:   PetscInt       m;

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

8572:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8573:     if (identical) return(0);
8574:   }
8575:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8576:   dm->monitor[dm->numbermonitors]          = f;
8577:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8578:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8579:   return(0);
8580: }

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

8585:   Logically Collective on DM

8587:   Input Parameter:
8588: . dm - the DM

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

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

8598:   Level: intermediate

8600: .seealso: DMMonitorSet()
8601: @*/
8602: PetscErrorCode DMMonitorCancel(DM dm)
8603: {
8605:   PetscInt       m;

8609:   for (m = 0; m < dm->numbermonitors; ++m) {
8610:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
8611:   }
8612:   dm->numbermonitors = 0;
8613:   return(0);
8614: }

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

8619:   Collective on DM

8621:   Input Parameters:
8622: + dm   - DM object you wish to monitor
8623: . name - the monitor type one is seeking
8624: . help - message indicating what monitoring is done
8625: . manual - manual page for the monitor
8626: . monitor - the monitor function
8627: - 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

8629:   Output Parameter:
8630: . flg - Flag set if the monitor was created

8632:   Level: developer

8634: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8635:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8636:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8637:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8638:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8639:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8640:           PetscOptionsFList(), PetscOptionsEList()
8641: @*/
8642: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8643: {
8644:   PetscViewer       viewer;
8645:   PetscViewerFormat format;
8646:   PetscErrorCode    ierr;

8650:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
8651:   if (*flg) {
8652:     PetscViewerAndFormat *vf;

8654:     PetscViewerAndFormatCreate(viewer, format, &vf);
8655:     PetscObjectDereference((PetscObject) viewer);
8656:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
8657:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
8658:   }
8659:   return(0);
8660: }

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

8665:    Collective on DM

8667:    Input Parameters:
8668: .  dm - The DM

8670:    Level: developer

8672: .seealso: DMMonitorSet()
8673: @*/
8674: PetscErrorCode DMMonitor(DM dm)
8675: {
8676:   PetscInt       m;

8680:   if (!dm) return(0);
8682:   for (m = 0; m < dm->numbermonitors; ++m) {
8683:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8684:   }
8685:   return(0);
8686: }