Actual source code: dm.c

petsc-master 2020-07-01
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: #if defined(PETSC_HAVE_VALGRIND)
 10: #  include <valgrind/memcheck.h>
 11: #endif

 13: PetscClassId  DM_CLASSID;
 14: PetscClassId  DMLABEL_CLASSID;
 15: 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;

 17: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_",0};
 18: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_",0};
 19: 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};
 20: /*@
 21:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

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

 26:   Collective

 28:   Input Parameter:
 29: . comm - The communicator for the DM object

 31:   Output Parameter:
 32: . dm - The DM object

 34:   Level: beginner

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

 46:   *dm = NULL;
 47:   DMInitializePackage();

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

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

 89:   *dm = v;
 90:   return(0);
 91: }

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

 96:   Collective

 98:   Input Parameter:
 99: . dm - The original DM object

101:   Output Parameter:
102: . newdm  - The new DM object

104:   Level: beginner

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

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

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

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

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

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

176:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
177:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
178:   }
179:   return(0);
180: }

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

185:    Logically Collective on da

187:    Input Parameter:
188: +  da - initial distributed array
189: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

191:    Options Database:
192: .   -dm_vec_type ctype

194:    Level: intermediate

196: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
197: @*/
198: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
199: {

204:   PetscFree(da->vectype);
205:   PetscStrallocpy(ctype,(char**)&da->vectype);
206:   return(0);
207: }

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

212:    Logically Collective on da

214:    Input Parameter:
215: .  da - initial distributed array

217:    Output Parameter:
218: .  ctype - the vector type

220:    Level: intermediate

222: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
223: @*/
224: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
225: {
228:   *ctype = da->vectype;
229:   return(0);
230: }

232: /*@
233:   VecGetDM - Gets the DM defining the data layout of the vector

235:   Not collective

237:   Input Parameter:
238: . v - The Vec

240:   Output Parameter:
241: . dm - The DM

243:   Level: intermediate

245: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
246: @*/
247: PetscErrorCode VecGetDM(Vec v, DM *dm)
248: {

254:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
255:   return(0);
256: }

258: /*@
259:   VecSetDM - Sets the DM defining the data layout of the vector.

261:   Not collective

263:   Input Parameters:
264: + v - The Vec
265: - dm - The DM

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

269:   Level: intermediate

271: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
272: @*/
273: PetscErrorCode VecSetDM(Vec v, DM dm)
274: {

280:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
281:   return(0);
282: }

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

287:    Logically Collective on dm

289:    Input Parameters:
290: +  dm - the DM context
291: -  ctype - the matrix type

293:    Options Database:
294: .   -dm_is_coloring_type - global or local

296:    Level: intermediate

298: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
299:           DMGetISColoringType()
300: @*/
301: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
302: {
305:   dm->coloringtype = ctype;
306:   return(0);
307: }

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

312:    Logically Collective on dm

314:    Input Parameter:
315: .  dm - the DM context

317:    Output Parameter:
318: .  ctype - the matrix type

320:    Options Database:
321: .   -dm_is_coloring_type - global or local

323:    Level: intermediate

325: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
326:           DMGetISColoringType()
327: @*/
328: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
329: {
332:   *ctype = dm->coloringtype;
333:   return(0);
334: }

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

339:    Logically Collective on dm

341:    Input Parameters:
342: +  dm - the DM context
343: -  ctype - the matrix type

345:    Options Database:
346: .   -dm_mat_type ctype

348:    Level: intermediate

350: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
351: @*/
352: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
353: {

358:   PetscFree(dm->mattype);
359:   PetscStrallocpy(ctype,(char**)&dm->mattype);
360:   return(0);
361: }

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

366:    Logically Collective on dm

368:    Input Parameter:
369: .  dm - the DM context

371:    Output Parameter:
372: .  ctype - the matrix type

374:    Options Database:
375: .   -dm_mat_type ctype

377:    Level: intermediate

379: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
380: @*/
381: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
382: {
385:   *ctype = dm->mattype;
386:   return(0);
387: }

389: /*@
390:   MatGetDM - Gets the DM defining the data layout of the matrix

392:   Not collective

394:   Input Parameter:
395: . A - The Mat

397:   Output Parameter:
398: . dm - The DM

400:   Level: intermediate

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

405: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
406: @*/
407: PetscErrorCode MatGetDM(Mat A, DM *dm)
408: {

414:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
415:   return(0);
416: }

418: /*@
419:   MatSetDM - Sets the DM defining the data layout of the matrix

421:   Not collective

423:   Input Parameters:
424: + A - The Mat
425: - dm - The DM

427:   Level: intermediate

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


433: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
434: @*/
435: PetscErrorCode MatSetDM(Mat A, DM dm)
436: {

442:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
443:   return(0);
444: }

446: /*@C
447:    DMSetOptionsPrefix - Sets the prefix used for searching for all
448:    DM options in the database.

450:    Logically Collective on dm

452:    Input Parameter:
453: +  da - the DM context
454: -  prefix - the prefix to prepend to all option names

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

460:    Level: advanced

462: .seealso: DMSetFromOptions()
463: @*/
464: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
465: {

470:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
471:   if (dm->sf) {
472:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
473:   }
474:   if (dm->sectionSF) {
475:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
476:   }
477:   return(0);
478: }

480: /*@C
481:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
482:    DM options in the database.

484:    Logically Collective on dm

486:    Input Parameters:
487: +  dm - the DM context
488: -  prefix - the prefix string to prepend to all DM option requests

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

494:    Level: advanced

496: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
497: @*/
498: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
499: {

504:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
505:   return(0);
506: }

508: /*@C
509:    DMGetOptionsPrefix - Gets the prefix used for searching for all
510:    DM options in the database.

512:    Not Collective

514:    Input Parameters:
515: .  dm - the DM context

517:    Output Parameters:
518: .  prefix - pointer to the prefix string used is returned

520:    Notes:
521:     On the fortran side, the user should pass in a string 'prefix' of
522:    sufficient length to hold the prefix.

524:    Level: advanced

526: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
527: @*/
528: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
529: {

534:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
535:   return(0);
536: }

538: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
539: {
540:   PetscInt       refct = ((PetscObject) dm)->refct;

544:   *ncrefct = 0;
545:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
546:     refct--;
547:     if (recurseCoarse) {
548:       PetscInt coarseCount;

550:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
551:       refct += coarseCount;
552:     }
553:   }
554:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
555:     refct--;
556:     if (recurseFine) {
557:       PetscInt fineCount;

559:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
560:       refct += fineCount;
561:     }
562:   }
563:   *ncrefct = refct;
564:   return(0);
565: }

567: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
568: {
569:   DMLabelLink    next = dm->labels;

573:   /* destroy the labels */
574:   while (next) {
575:     DMLabelLink tmp = next->next;

577:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
578:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
579:     DMLabelDestroy(&next->label);
580:     PetscFree(next);
581:     next = tmp;
582:   }
583:   dm->labels = NULL;
584:   return(0);
585: }

587: /*@
588:     DMDestroy - Destroys a vector packer or DM.

590:     Collective on dm

592:     Input Parameter:
593: .   dm - the DM object to destroy

595:     Level: developer

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

599: @*/
600: PetscErrorCode  DMDestroy(DM *dm)
601: {
602:   PetscInt       cnt;
603:   DMNamedVecLink nlink,nnext;

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

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

617:   DMClearGlobalVectors(*dm);
618:   DMClearLocalVectors(*dm);

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

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

701:       next = b->next;
702:       PetscFree(b);
703:     }
704:   }

706:   PetscObjectDestroy(&(*dm)->dmksp);
707:   PetscObjectDestroy(&(*dm)->dmsnes);
708:   PetscObjectDestroy(&(*dm)->dmts);

710:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
711:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
712:   }
713:   MatFDColoringDestroy(&(*dm)->fd);
714:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
715:   PetscFree((*dm)->vectype);
716:   PetscFree((*dm)->mattype);

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

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

751:   DMClearDS(*dm);
752:   DMDestroy(&(*dm)->dmBC);
753:   /* if memory was published with SAWs then destroy it */
754:   PetscObjectSAWsViewOff((PetscObject)*dm);

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

765: /*@
766:     DMSetUp - sets up the data structures inside a DM object

768:     Collective on dm

770:     Input Parameter:
771: .   dm - the DM object to setup

773:     Level: developer

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

777: @*/
778: PetscErrorCode  DMSetUp(DM dm)
779: {

784:   if (dm->setupcalled) return(0);
785:   if (dm->ops->setup) {
786:     (*dm->ops->setup)(dm);
787:   }
788:   dm->setupcalled = PETSC_TRUE;
789:   return(0);
790: }

792: /*@
793:     DMSetFromOptions - sets parameters in a DM from the options database

795:     Collective on dm

797:     Input Parameter:
798: .   dm - the DM object to set options for

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

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

815:     Level: intermediate

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

820: @*/
821: PetscErrorCode DMSetFromOptions(DM dm)
822: {
823:   char           typeName[256];
824:   PetscBool      flg;

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

852: /*@C
853:    DMViewFromOptions - View from Options

855:    Collective on DM

857:    Input Parameters:
858: +  dm - the DM object
859: .  obj - Optional object
860: -  name - command line option

862:    Level: intermediate
863: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
864: @*/
865: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
866: {

871:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
872:   return(0);
873: }

875: /*@C
876:     DMView - Views a DM

878:     Collective on dm

880:     Input Parameter:
881: +   dm - the DM object to view
882: -   v - the viewer

884:     Level: beginner

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

888: @*/
889: PetscErrorCode  DMView(DM dm,PetscViewer v)
890: {
891:   PetscErrorCode    ierr;
892:   PetscBool         isbinary;
893:   PetscMPIInt       size;
894:   PetscViewerFormat format;

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

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

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

931: /*@
932:     DMCreateGlobalVector - Creates a global vector from a DM object

934:     Collective on dm

936:     Input Parameter:
937: .   dm - the DM object

939:     Output Parameter:
940: .   vec - the global vector

942:     Level: beginner

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

946: @*/
947: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
948: {

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

959:     VecGetDM(*vec,&vdm);
960:     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);
961:   }
962:   return(0);
963: }

965: /*@
966:     DMCreateLocalVector - Creates a local vector from a DM object

968:     Not Collective

970:     Input Parameter:
971: .   dm - the DM object

973:     Output Parameter:
974: .   vec - the local vector

976:     Level: beginner

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

980: @*/
981: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
982: {

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

993:     VecGetDM(*vec,&vdm);
994:     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);
995:   }
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 (PetscDefined(USE_DEBUG)) {
1357:     DM mdm;

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

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

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

1389:   Logically Collective on dm

1391:   Input Parameter:
1392: + dm - the DM
1393: - only - PETSC_TRUE if only want preallocation

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

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

1410:   Logically Collective on dm

1412:   Input Parameter:
1413: + dm - the DM
1414: - only - PETSC_TRUE if only want matrix stucture

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

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

1430:   Not Collective

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

1437:   Output Parameter:
1438: . array - the work array

1440:   Level: developer

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

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

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

1478:   Not Collective

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

1485:   Output Parameter:
1486: . array - the work array

1488:   Level: developer

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

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

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

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

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

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

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

1554:   Not collective

1556:   Input Parameter:
1557: . dm - the DM object

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

1564:   Level: intermediate

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

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

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

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

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

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

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

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

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

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


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

1682:   Not collective

1684:   Input Parameter:
1685: . dm - the DM object

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

1693:   Level: intermediate

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

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

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

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

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

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

1765:   Not collective

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

1772:   Output Parameters:
1773: + is - The global indices for the subproblem
1774: - subdm - The DM for the subproblem

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

1778:   Level: intermediate

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

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

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

1799:   Not collective

1801:   Input Parameter:
1802: + dms - The DM objects
1803: - len - The number of DMs

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

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

1811:   Level: intermediate

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

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


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

1842:   Not collective

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

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

1854:   Level: intermediate

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

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

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


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

1902:   Not collective

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

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

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

1921:   Level: developer

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

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

1937: /*@
1938:   DMRefine - Refines a DM object

1940:   Collective on dm

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

1946:   Output Parameter:
1947: . dmf - the refined DM, or NULL

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

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

1954:   Level: developer

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

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

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

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

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

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

1991:    Logically Collective

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

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

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

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

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

2014:    Level: advanced

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

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

2021:    This function is currently not available from Fortran.

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

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

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

2047:    Logically Collective

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

2055:    Level: advanced

2057:    Notes:
2058:    This function does nothing if the hook is not in the list.

2060:    This function is currently not available from Fortran.

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

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

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

2085:    Collective if any hooks are

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

2092:    Level: developer

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

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

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

2113:     Not Collective

2115:     Input Parameter:
2116: .   dm - the DM object

2118:     Output Parameter:
2119: .   level - number of refinements

2121:     Level: developer

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

2125: @*/
2126: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2127: {
2130:   *level = dm->levelup;
2131:   return(0);
2132: }

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

2137:     Not Collective

2139:     Input Parameter:
2140: +   dm - the DM object
2141: -   level - number of refinements

2143:     Level: advanced

2145:     Notes:
2146:     This value is used by PCMG to determine how many multigrid levels to use

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

2150: @*/
2151: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2152: {
2155:   dm->levelup = level;
2156:   return(0);
2157: }

2159: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2160: {
2164:   *tdm = dm->transformDM;
2165:   return(0);
2166: }

2168: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2169: {
2173:   *tv = dm->transform;
2174:   return(0);
2175: }

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

2180:   Input Parameter:
2181: . dm - The DM

2183:   Output Parameter:
2184: . flg - PETSC_TRUE if a basis transformation should be done

2186:   Level: developer

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

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

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

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

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

2252: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2253: {

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

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

2270:    Logically Collective

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

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

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


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

2291: +  global - global DM
2292: -  ctx - optional user-defined function context

2294:    Level: advanced

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

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

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

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

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

2348: /*@
2349:     DMGlobalToLocal - update local vectors from global vector

2351:     Neighbor-wise Collective on dm

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

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

2363:     Level: beginner

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

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

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

2378: /*@
2379:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2381:     Neighbor-wise Collective on dm

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

2389:     Level: intermediate

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

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

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

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

2425: /*@
2426:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2428:     Neighbor-wise Collective on dm

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

2436:     Level: intermediate

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

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

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

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

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

2477:    Logically Collective

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

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

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


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

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

2504:    Level: advanced

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

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

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

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

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

2566:     Neighbor-wise Collective on dm

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

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

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

2581:     Level: beginner

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

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

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

2596: /*@
2597:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2599:     Neighbor-wise Collective on dm

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

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

2611:     Level: intermediate

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

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

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

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

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

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

2724: /*@
2725:     DMLocalToGlobalEnd - updates global vectors from local vectors

2727:     Neighbor-wise Collective on dm

2729:     Input Parameters:
2730: +   dm - the DM object
2731: .   l - the local vector
2732: .   mode - INSERT_VALUES or ADD_VALUES
2733: -   g - the global vector

2735:     Level: intermediate

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

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

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

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

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

2799:    Neighbor-wise Collective on dm

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

2806:    Output Parameter:
2807: .  l  - the local vector with correct ghost values

2809:    Level: intermediate

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

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

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

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

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

2836:    Neighbor-wise Collective on dm

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

2843:    Output Parameter:
2844: .  l  - the local vector with correct ghost values

2846:    Level: intermediate

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

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

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

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


2869: /*@
2870:     DMCoarsen - Coarsens a DM object

2872:     Collective on dm

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

2878:     Output Parameter:
2879: .   dmc - the coarsened DM

2881:     Level: developer

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

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

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

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

2916:    Logically Collective

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

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

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

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

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

2941:    Level: advanced

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

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

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

2951:    This function is currently not available from Fortran.

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

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

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

2977:    Logically Collective

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

2985:    Level: advanced

2987:    Notes:
2988:    This function does nothing if the hook is not in the list.

2990:    This function is currently not available from Fortran.

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

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


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

3016:    Collective if any hooks are

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

3025:    Level: developer

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

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

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

3046:    Logically Collective on global

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


3055:    Calling sequence for ddhook:
3056: $    ddhook(DM global,DM block,void *ctx)

3058: +  global - global DM
3059: .  block  - block DM
3060: -  ctx - optional user-defined function context

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

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

3071:    Level: advanced

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

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

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

3081:    This function is currently not available from Fortran.

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

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

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

3107:    Logically Collective

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

3115:    Level: advanced

3117:    Notes:

3119:    This function is currently not available from Fortran.

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

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

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

3144:    Collective if any hooks are

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

3152:    Level: developer

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

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

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

3173:     Not Collective

3175:     Input Parameter:
3176: .   dm - the DM object

3178:     Output Parameter:
3179: .   level - number of coarsenings

3181:     Level: developer

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

3185: @*/
3186: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3187: {
3191:   *level = dm->leveldown;
3192:   return(0);
3193: }

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

3198:     Not Collective

3200:     Input Parameters:
3201: +   dm - the DM object
3202: -   level - number of coarsenings

3204:     Level: developer

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



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

3221:     Collective on dm

3223:     Input Parameter:
3224: +   dm - the DM object
3225: -   nlevels - the number of levels of refinement

3227:     Output Parameter:
3228: .   dmf - the refined DM hierarchy

3230:     Level: developer

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

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

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

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

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

3260:     Collective on dm

3262:     Input Parameter:
3263: +   dm - the DM object
3264: -   nlevels - the number of levels of coarsening

3266:     Output Parameter:
3267: .   dmc - the coarsened DM hierarchy

3269:     Level: developer

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

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

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

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

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

3299:     Not Collective

3301:     Input Parameters:
3302: +   dm - the DM object
3303: -   destroy - the destroy function

3305:     Level: intermediate

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

3309: @*/
3310: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3311: {
3314:   dm->ctxdestroy = destroy;
3315:   return(0);
3316: }

3318: /*@
3319:     DMSetApplicationContext - Set a user context into a DM object

3321:     Not Collective

3323:     Input Parameters:
3324: +   dm - the DM object
3325: -   ctx - the user context

3327:     Level: intermediate

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

3331: @*/
3332: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3333: {
3336:   dm->ctx = ctx;
3337:   return(0);
3338: }

3340: /*@
3341:     DMGetApplicationContext - Gets a user context from a DM object

3343:     Not Collective

3345:     Input Parameter:
3346: .   dm - the DM object

3348:     Output Parameter:
3349: .   ctx - the user context

3351:     Level: intermediate

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

3355: @*/
3356: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3357: {
3360:   *(void**)ctx = dm->ctx;
3361:   return(0);
3362: }

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

3367:     Logically Collective on dm

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

3373:     Level: intermediate

3375: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3376:          DMSetJacobian()

3378: @*/
3379: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3380: {
3383:   dm->ops->computevariablebounds = f;
3384:   return(0);
3385: }

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

3390:     Not Collective

3392:     Input Parameter:
3393: .   dm - the DM object to destroy

3395:     Output Parameter:
3396: .   flg - PETSC_TRUE if the variable bounds function exists

3398:     Level: developer

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

3402: @*/
3403: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3404: {
3408:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3409:   return(0);
3410: }

3412: /*@C
3413:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3415:     Logically Collective on dm

3417:     Input Parameters:
3418: .   dm - the DM object

3420:     Output parameters:
3421: +   xl - lower bound
3422: -   xu - upper bound

3424:     Level: advanced

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

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

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

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

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

3448:     Not Collective

3450:     Input Parameter:
3451: .   dm - the DM object

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

3456:     Level: developer

3458: .seealso DMCreateColoring()

3460: @*/
3461: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3462: {
3466:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3467:   return(0);
3468: }

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

3473:     Not Collective

3475:     Input Parameter:
3476: .   dm - the DM object

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

3481:     Level: developer

3483: .seealso DMCreateRestriction()

3485: @*/
3486: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3487: {
3491:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3492:   return(0);
3493: }


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

3499:     Not Collective

3501:     Input Parameter:
3502: .   dm - the DM object

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

3507:     Level: developer

3509: .seealso DMCreateInjection()

3511: @*/
3512: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3513: {

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

3527: PetscFunctionList DMList              = NULL;
3528: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3530: /*@C
3531:   DMSetType - Builds a DM, for a particular DM implementation.

3533:   Collective on dm

3535:   Input Parameters:
3536: + dm     - The DM object
3537: - method - The name of the DM type

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

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

3545:   Level: intermediate

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

3557:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3558:   if (match) return(0);

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

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

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

3576:   Not Collective

3578:   Input Parameter:
3579: . dm  - The DM

3581:   Output Parameter:
3582: . type - The DM type name

3584:   Level: intermediate

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

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

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

3603:   Collective on dm

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

3609:   Output Parameter:
3610: . M - pointer to new DM

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

3617:   Level: intermediate

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

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

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

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

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

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

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

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

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

3706: /*--------------------------------------------------------------------------------------------------------------------*/

3708: /*@C
3709:   DMRegister -  Adds a new DM component implementation

3711:   Not Collective

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

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


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

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

3736:   Level: advanced

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

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

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

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

3754:   Collective on viewer

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

3762:    Level: intermediate

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

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

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

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

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

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

3809:   Not collective

3811:   Input Parameter:
3812: . dm - the DM

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

3818:   Level: beginner

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


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

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

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

3861: /*@
3862:   DMGetBoundingBox - Returns the global bounding box for the DM.

3864:   Collective

3866:   Input Parameter:
3867: . dm - the DM

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

3873:   Level: beginner

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

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

3894: /******************************** FEM Support **********************************/

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

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

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

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

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

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

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

3960:   Input Parameter:
3961: . dm - The DM

3963:   Output Parameter:
3964: . section - The PetscSection

3966:   Options Database Keys:
3967: . -dm_petscsection_view - View the Section created by the DM

3969:   Level: advanced

3971:   Notes:
3972:   Use DMGetLocalSection() in new code.

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

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

3983:   DMGetLocalSection(dm,section);
3984:   return(0);
3985: }

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

3990:   Input Parameter:
3991: . dm - The DM

3993:   Output Parameter:
3994: . section - The PetscSection

3996:   Options Database Keys:
3997: . -dm_petscsection_view - View the Section created by the DM

3999:   Level: intermediate

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

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

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

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

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

4026:   Input Parameters:
4027: + dm - The DM
4028: - section - The PetscSection

4030:   Level: advanced

4032:   Notes:
4033:   Use DMSetLocalSection() in new code.

4035:   Any existing Section will be destroyed

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

4044:   DMSetLocalSection(dm,section);
4045:   return(0);
4046: }

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

4051:   Input Parameters:
4052: + dm - The DM
4053: - section - The PetscSection

4055:   Level: intermediate

4057:   Note: Any existing Section will be destroyed

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

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

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

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

4093:   not collective

4095:   Input Parameter:
4096: . dm - The DM

4098:   Output Parameter:
4099: + 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.
4100: - 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.

4102:   Level: advanced

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

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

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

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

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

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

4127:   collective on dm

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

4134:   Level: advanced

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

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

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

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

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

4175:   Level: intermediate

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

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

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

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

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

4238:   Collective on dm

4240:   Input Parameter:
4241: . dm - The DM

4243:   Output Parameter:
4244: . section - The PetscSection

4246:   Level: intermediate

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

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

4259:   if (!dm->globalSection) {
4260:     PetscSection s;

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

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

4277:   Input Parameters:
4278: + dm - The DM
4279: - section - The PetscSection, or NULL

4281:   Level: intermediate

4283:   Note: Any existing Section will be destroyed

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

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

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

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

4310:   Output Parameter:
4311: . sf - The PetscSF

4313:   Level: intermediate

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

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

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

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

4347: /*@
4348:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4350:   Input Parameters:
4351: + dm - The DM
4352: - sf - The PetscSF

4354:   Level: intermediate

4356:   Note: Any previous SF is destroyed

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

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

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

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

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

4384:   Level: developer

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

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

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

4418:     PetscSectionGetDof(globalSection, p, &gdof);
4419:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4420:     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));
4421:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4422:   }
4423:   PetscMalloc1(nleaves, &local);
4424:   PetscMalloc1(nleaves, &remote);
4425:   for (p = pStart, l = 0; p < pEnd; ++p) {
4426:     const PetscInt *cind;
4427:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4429:     PetscSectionGetDof(localSection, p, &dof);
4430:     PetscSectionGetOffset(localSection, p, &off);
4431:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4432:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4433:     PetscSectionGetDof(globalSection, p, &gdof);
4434:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4435:     PetscSectionGetOffset(globalSection, p, &goff);
4436:     if (!gdof) continue; /* Censored point */
4437:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4438:     if (gsize != dof-cdof) {
4439:       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);
4440:       cdof = 0; /* Ignore constraints */
4441:     }
4442:     for (d = 0, c = 0; d < dof; ++d) {
4443:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4444:       local[l+d-c] = off+d;
4445:     }
4446:     if (gdof < 0) {
4447:       for (d = 0; d < gsize; ++d, ++l) {
4448:         PetscInt offset = -(goff+1) + d, r;

4450:         PetscFindInt(offset,size+1,ranges,&r);
4451:         if (r < 0) r = -(r+2);
4452:         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);
4453:         remote[l].rank  = r;
4454:         remote[l].index = offset - ranges[r];
4455:       }
4456:     } else {
4457:       for (d = 0; d < gsize; ++d, ++l) {
4458:         remote[l].rank  = rank;
4459:         remote[l].index = goff+d - ranges[rank];
4460:       }
4461:     }
4462:   }
4463:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4464:   PetscLayoutDestroy(&layout);
4465:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4466:   return(0);
4467: }

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

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

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

4478:   Level: intermediate

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

4482: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4483: @*/
4484: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4485: {
4489:   *sf = dm->sf;
4490:   return(0);
4491: }

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

4496:   Input Parameters:
4497: + dm - The DM
4498: - sf - The PetscSF

4500:   Level: intermediate

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

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

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

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

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

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

4551: /*@
4552:   DMClearFields - Remove all fields from the DM

4554:   Logically collective on dm

4556:   Input Parameter:
4557: . dm - The DM

4559:   Level: intermediate

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

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

4580: /*@
4581:   DMGetNumFields - Get the number of fields in the DM

4583:   Not collective

4585:   Input Parameter:
4586: . dm - The DM

4588:   Output Parameter:
4589: . Nf - The number of fields

4591:   Level: intermediate

4593: .seealso: DMSetNumFields(), DMSetField()
4594: @*/
4595: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4596: {
4600:   *numFields = dm->Nf;
4601:   return(0);
4602: }

4604: /*@
4605:   DMSetNumFields - Set the number of fields in the DM

4607:   Logically collective on dm

4609:   Input Parameters:
4610: + dm - The DM
4611: - Nf - The number of fields

4613:   Level: intermediate

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

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

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

4635: /*@
4636:   DMGetField - Return the discretization object for a given DM field

4638:   Not collective

4640:   Input Parameters:
4641: + dm - The DM
4642: - f  - The field number

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

4648:   Level: intermediate

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

4663: /* Does not clear the DS */
4664: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4665: {

4669:   DMFieldEnlarge_Static(dm, f+1);
4670:   DMLabelDestroy(&dm->fields[f].label);
4671:   PetscObjectDestroy(&dm->fields[f].disc);
4672:   dm->fields[f].label = label;
4673:   dm->fields[f].disc  = field;
4674:   PetscObjectReference((PetscObject) label);
4675:   PetscObjectReference((PetscObject) field);
4676:   return(0);
4677: }

4679: /*@
4680:   DMSetField - Set the discretization object for a given DM field

4682:   Logically collective on dm

4684:   Input Parameters:
4685: + dm    - The DM
4686: . f     - The field number
4687: . label - The label indicating the support of the field, or NULL for the entire mesh
4688: - field - The discretization object

4690:   Level: intermediate

4692: .seealso: DMAddField(), DMGetField()
4693: @*/
4694: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4695: {

4702:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4703:   DMSetField_Internal(dm, f, label, field);
4704:   DMSetDefaultAdjacency_Private(dm, f, field);
4705:   DMClearDS(dm);
4706:   return(0);
4707: }

4709: /*@
4710:   DMAddField - Add the discretization object for the given DM field

4712:   Logically collective on dm

4714:   Input Parameters:
4715: + dm    - The DM
4716: . label - The label indicating the support of the field, or NULL for the entire mesh
4717: - field - The discretization object

4719:   Level: intermediate

4721: .seealso: DMSetField(), DMGetField()
4722: @*/
4723: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4724: {
4725:   PetscInt       Nf = dm->Nf;

4732:   DMFieldEnlarge_Static(dm, Nf+1);
4733:   dm->fields[Nf].label = label;
4734:   dm->fields[Nf].disc  = field;
4735:   PetscObjectReference((PetscObject) label);
4736:   PetscObjectReference((PetscObject) field);
4737:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4738:   DMClearDS(dm);
4739:   return(0);
4740: }

4742: /*@
4743:   DMCopyFields - Copy the discretizations for the DM into another DM

4745:   Collective on dm

4747:   Input Parameter:
4748: . dm - The DM

4750:   Output Parameter:
4751: . newdm - The DM

4753:   Level: advanced

4755: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4756: @*/
4757: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4758: {
4759:   PetscInt       Nf, f;

4763:   if (dm == newdm) return(0);
4764:   DMGetNumFields(dm, &Nf);
4765:   DMClearFields(newdm);
4766:   for (f = 0; f < Nf; ++f) {
4767:     DMLabel     label;
4768:     PetscObject field;
4769:     PetscBool   useCone, useClosure;

4771:     DMGetField(dm, f, &label, &field);
4772:     DMSetField(newdm, f, label, field);
4773:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4774:     DMSetAdjacency(newdm, f, useCone, useClosure);
4775:   }
4776:   return(0);
4777: }

4779: /*@
4780:   DMGetAdjacency - Returns the flags for determining variable influence

4782:   Not collective

4784:   Input Parameters:
4785: + dm - The DM object
4786: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4788:   Output Parameter:
4789: + useCone    - Flag for variable influence starting with the cone operation
4790: - useClosure - Flag for variable influence using transitive closure

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

4798:   Level: developer

4800: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4801: @*/
4802: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4803: {
4808:   if (f < 0) {
4809:     if (useCone)    *useCone    = dm->adjacency[0];
4810:     if (useClosure) *useClosure = dm->adjacency[1];
4811:   } else {
4812:     PetscInt       Nf;

4815:     DMGetNumFields(dm, &Nf);
4816:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4817:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4818:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4819:   }
4820:   return(0);
4821: }

4823: /*@
4824:   DMSetAdjacency - Set the flags for determining variable influence

4826:   Not collective

4828:   Input Parameters:
4829: + dm         - The DM object
4830: . f          - The field number
4831: . useCone    - Flag for variable influence starting with the cone operation
4832: - useClosure - Flag for variable influence using transitive closure

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

4840:   Level: developer

4842: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4843: @*/
4844: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4845: {
4848:   if (f < 0) {
4849:     dm->adjacency[0] = useCone;
4850:     dm->adjacency[1] = useClosure;
4851:   } else {
4852:     PetscInt       Nf;

4855:     DMGetNumFields(dm, &Nf);
4856:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4857:     dm->fields[f].adjacency[0] = useCone;
4858:     dm->fields[f].adjacency[1] = useClosure;
4859:   }
4860:   return(0);
4861: }

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

4866:   Not collective

4868:   Input Parameters:
4869: . dm - The DM object

4871:   Output Parameter:
4872: + useCone    - Flag for variable influence starting with the cone operation
4873: - useClosure - Flag for variable influence using transitive closure

4875:   Notes:
4876: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4877: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4878: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4880:   Level: developer

4882: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4883: @*/
4884: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4885: {
4886:   PetscInt       Nf;

4893:   DMGetNumFields(dm, &Nf);
4894:   if (!Nf) {
4895:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4896:   } else {
4897:     DMGetAdjacency(dm, 0, useCone, useClosure);
4898:   }
4899:   return(0);
4900: }

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

4905:   Not collective

4907:   Input Parameters:
4908: + dm         - The DM object
4909: . useCone    - Flag for variable influence starting with the cone operation
4910: - useClosure - Flag for variable influence using transitive closure

4912:   Notes:
4913: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4914: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4915: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4917:   Level: developer

4919: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
4920: @*/
4921: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
4922: {
4923:   PetscInt       Nf;

4928:   DMGetNumFields(dm, &Nf);
4929:   if (!Nf) {
4930:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4931:   } else {
4932:     DMSetAdjacency(dm, 0, useCone, useClosure);
4933:   }
4934:   return(0);
4935: }

4937: /* Complete labels that are being used for FEM BC */
4938: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
4939: {
4940:   DMLabel        label;
4941:   PetscObject    obj;
4942:   PetscClassId   id;
4943:   PetscInt       Nbd, bd;
4944:   PetscBool      isFE      = PETSC_FALSE;
4945:   PetscBool      duplicate = PETSC_FALSE;

4949:   DMGetField(dm, field, NULL, &obj);
4950:   PetscObjectGetClassId(obj, &id);
4951:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
4952:   DMGetLabel(dm, labelname, &label);
4953:   if (isFE && label) {
4954:     /* Only want to modify label once */
4955:     PetscDSGetNumBoundary(ds, &Nbd);
4956:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
4957:       const char *lname;

4959:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
4960:       PetscStrcmp(lname, labelname, &duplicate);
4961:       if (duplicate) break;
4962:     }
4963:     if (!duplicate) {
4964:       DM plex;

4966:       DMConvert(dm, DMPLEX, &plex);
4967:       if (plex) {DMPlexLabelComplete(plex, label);}
4968:       DMDestroy(&plex);
4969:     }
4970:   }
4971:   return(0);
4972: }

4974: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4975: {
4976:   DMSpace       *tmpd;
4977:   PetscInt       Nds = dm->Nds, s;

4981:   if (Nds >= NdsNew) return(0);
4982:   PetscMalloc1(NdsNew, &tmpd);
4983:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4984:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
4985:   PetscFree(dm->probs);
4986:   dm->Nds   = NdsNew;
4987:   dm->probs = tmpd;
4988:   return(0);
4989: }

4991: /*@
4992:   DMGetNumDS - Get the number of discrete systems in the DM

4994:   Not collective

4996:   Input Parameter:
4997: . dm - The DM

4999:   Output Parameter:
5000: . Nds - The number of PetscDS objects

5002:   Level: intermediate

5004: .seealso: DMGetDS(), DMGetCellDS()
5005: @*/
5006: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5007: {
5011:   *Nds = dm->Nds;
5012:   return(0);
5013: }

5015: /*@
5016:   DMClearDS - Remove all discrete systems from the DM

5018:   Logically collective on dm

5020:   Input Parameter:
5021: . dm - The DM

5023:   Level: intermediate

5025: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5026: @*/
5027: PetscErrorCode DMClearDS(DM dm)
5028: {
5029:   PetscInt       s;

5034:   for (s = 0; s < dm->Nds; ++s) {
5035:     PetscDSDestroy(&dm->probs[s].ds);
5036:     DMLabelDestroy(&dm->probs[s].label);
5037:     ISDestroy(&dm->probs[s].fields);
5038:   }
5039:   PetscFree(dm->probs);
5040:   dm->probs = NULL;
5041:   dm->Nds   = 0;
5042:   return(0);
5043: }

5045: /*@
5046:   DMGetDS - Get the default PetscDS

5048:   Not collective

5050:   Input Parameter:
5051: . dm    - The DM

5053:   Output Parameter:
5054: . prob - The default PetscDS

5056:   Level: intermediate

5058: .seealso: DMGetCellDS(), DMGetRegionDS()
5059: @*/
5060: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5061: {

5067:   if (dm->Nds <= 0) {
5068:     PetscDS ds;

5070:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5071:     DMSetRegionDS(dm, NULL, NULL, ds);
5072:     PetscDSDestroy(&ds);
5073:   }
5074:   *prob = dm->probs[0].ds;
5075:   return(0);
5076: }

5078: /*@
5079:   DMGetCellDS - Get the PetscDS defined on a given cell

5081:   Not collective

5083:   Input Parameters:
5084: + dm    - The DM
5085: - point - Cell for the DS

5087:   Output Parameter:
5088: . prob - The PetscDS defined on the given cell

5090:   Level: developer

5092: .seealso: DMGetDS(), DMSetRegionDS()
5093: @*/
5094: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5095: {
5096:   PetscDS        probDef = NULL;
5097:   PetscInt       s;

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

5108:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5109:     else {
5110:       DMLabelGetValue(dm->probs[s].label, point, &val);
5111:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5112:     }
5113:   }
5114:   if (!*prob) *prob = probDef;
5115:   return(0);
5116: }

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

5121:   Not collective

5123:   Input Parameters:
5124: + dm    - The DM
5125: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5133:   Level: advanced

5135: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5136: @*/
5137: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5138: {
5139:   PetscInt Nds = dm->Nds, s;

5146:   for (s = 0; s < Nds; ++s) {
5147:     if (dm->probs[s].label == label) {
5148:       if (fields) *fields = dm->probs[s].fields;
5149:       if (ds)     *ds     = dm->probs[s].ds;
5150:       return(0);
5151:     }
5152:   }
5153:   return(0);
5154: }

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

5159:   Collective on dm

5161:   Input Parameters:
5162: + dm     - The DM
5163: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5164: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5165: - prob   - The PetscDS defined on the given cell

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

5170:   Level: advanced

5172: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5173: @*/
5174: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5175: {
5176:   PetscInt       Nds = dm->Nds, s;

5183:   for (s = 0; s < Nds; ++s) {
5184:     if (dm->probs[s].label == label) {
5185:       PetscDSDestroy(&dm->probs[s].ds);
5186:       dm->probs[s].ds = ds;
5187:       return(0);
5188:     }
5189:   }
5190:   DMDSEnlarge_Static(dm, Nds+1);
5191:   PetscObjectReference((PetscObject) label);
5192:   PetscObjectReference((PetscObject) fields);
5193:   PetscObjectReference((PetscObject) ds);
5194:   if (!label) {
5195:     /* Put the NULL label at the front, so it is returned as the default */
5196:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5197:     Nds = 0;
5198:   }
5199:   dm->probs[Nds].label  = label;
5200:   dm->probs[Nds].fields = fields;
5201:   dm->probs[Nds].ds     = ds;
5202:   return(0);
5203: }

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

5208:   Not collective

5210:   Input Parameters:
5211: + dm  - The DM
5212: - num - The region number, in [0, Nds)

5214:   Output Parameters:
5215: + label  - The region label, or NULL
5216: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5217: - ds     - The PetscDS defined on the given region, or NULL

5219:   Level: advanced

5221: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5222: @*/
5223: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5224: {
5225:   PetscInt       Nds;

5230:   DMGetNumDS(dm, &Nds);
5231:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5232:   if (label) {
5234:     *label = dm->probs[num].label;
5235:   }
5236:   if (fields) {
5238:     *fields = dm->probs[num].fields;
5239:   }
5240:   if (ds) {
5242:     *ds = dm->probs[num].ds;
5243:   }
5244:   return(0);
5245: }

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

5250:   Not collective

5252:   Input Parameters:
5253: + dm     - The DM
5254: . num    - The region number, in [0, Nds)
5255: . label  - The region label, or NULL
5256: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5257: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5259:   Level: advanced

5261: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5262: @*/
5263: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5264: {
5265:   PetscInt       Nds;

5271:   DMGetNumDS(dm, &Nds);
5272:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5273:   PetscObjectReference((PetscObject) label);
5274:   DMLabelDestroy(&dm->probs[num].label);
5275:   dm->probs[num].label = label;
5276:   if (fields) {
5278:     PetscObjectReference((PetscObject) fields);
5279:     ISDestroy(&dm->probs[num].fields);
5280:     dm->probs[num].fields = fields;
5281:   }
5282:   if (ds) {
5284:     PetscObjectReference((PetscObject) ds);
5285:     PetscDSDestroy(&dm->probs[num].ds);
5286:     dm->probs[num].ds = ds;
5287:   }
5288:   return(0);
5289: }

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

5294:   Not collective

5296:   Input Parameters:
5297: + dm  - The DM
5298: - ds  - The PetscDS defined on the given region

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

5303:   Level: advanced

5305: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5306: @*/
5307: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5308: {
5309:   PetscInt       Nds, n;

5316:   DMGetNumDS(dm, &Nds);
5317:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5318:   if (n >= Nds) *num = -1;
5319:   else          *num = n;
5320:   return(0);
5321: }

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

5326:   Collective on dm

5328:   Input Parameter:
5329: . dm - The DM

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

5333:   Level: intermediate

5335: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5336: @*/
5337: PetscErrorCode DMCreateDS(DM dm)
5338: {
5339:   MPI_Comm       comm;
5340:   PetscDS        dsDef;
5341:   DMLabel       *labelSet;
5342:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5343:   PetscBool      doSetup = PETSC_TRUE;

5348:   if (!dm->fields) return(0);
5349:   PetscObjectGetComm((PetscObject) dm, &comm);
5350:   DMGetCoordinateDim(dm, &dE);
5351:   /* Determine how many regions we have */
5352:   PetscMalloc1(Nf, &labelSet);
5353:   Nl   = 0;
5354:   Ndef = 0;
5355:   for (f = 0; f < Nf; ++f) {
5356:     DMLabel  label = dm->fields[f].label;
5357:     PetscInt l;

5359:     if (!label) {++Ndef; continue;}
5360:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5361:     if (l < Nl) continue;
5362:     labelSet[Nl++] = label;
5363:   }
5364:   /* Create default DS if there are no labels to intersect with */
5365:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5366:   if (!dsDef && Ndef && !Nl) {
5367:     IS        fields;
5368:     PetscInt *fld, nf;

5370:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5371:     if (nf) {
5372:       PetscMalloc1(nf, &fld);
5373:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5374:       ISCreate(PETSC_COMM_SELF, &fields);
5375:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5376:       ISSetType(fields, ISGENERAL);
5377:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5379:       PetscDSCreate(comm, &dsDef);
5380:       DMSetRegionDS(dm, NULL, fields, dsDef);
5381:       PetscDSDestroy(&dsDef);
5382:       ISDestroy(&fields);
5383:     }
5384:   }
5385:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5386:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5387:   /* Intersect labels with default fields */
5388:   if (Ndef && Nl) {
5389:     DM              plex;
5390:     DMLabel         cellLabel;
5391:     IS              fieldIS, allcellIS, defcellIS = NULL;
5392:     PetscInt       *fields;
5393:     const PetscInt *cells;
5394:     PetscInt        depth, nf = 0, n, c;

5396:     DMConvert(dm, DMPLEX, &plex);
5397:     DMPlexGetDepth(plex, &depth);
5398:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5399:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5400:     for (l = 0; l < Nl; ++l) {
5401:       DMLabel label = labelSet[l];
5402:       IS      pointIS;

5404:       ISDestroy(&defcellIS);
5405:       DMLabelGetStratumIS(label, 1, &pointIS);
5406:       ISDifference(allcellIS, pointIS, &defcellIS);
5407:       ISDestroy(&pointIS);
5408:     }
5409:     ISDestroy(&allcellIS);

5411:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5412:     ISGetLocalSize(defcellIS, &n);
5413:     ISGetIndices(defcellIS, &cells);
5414:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5415:     ISRestoreIndices(defcellIS, &cells);
5416:     ISDestroy(&defcellIS);
5417:     DMPlexLabelComplete(plex, cellLabel);

5419:     PetscMalloc1(Ndef, &fields);
5420:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5421:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5422:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5423:     ISSetType(fieldIS, ISGENERAL);
5424:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5426:     PetscDSCreate(comm, &dsDef);
5427:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5428:     DMLabelDestroy(&cellLabel);
5429:     PetscDSSetCoordinateDimension(dsDef, dE);
5430:     PetscDSDestroy(&dsDef);
5431:     ISDestroy(&fieldIS);
5432:     DMDestroy(&plex);
5433:   }
5434:   /* Create label DSes
5435:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5436:   */
5437:   /* TODO Should check that labels are disjoint */
5438:   for (l = 0; l < Nl; ++l) {
5439:     DMLabel   label = labelSet[l];
5440:     PetscDS   ds;
5441:     IS        fields;
5442:     PetscInt *fld, nf;

5444:     PetscDSCreate(comm, &ds);
5445:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5446:     PetscMalloc1(nf, &fld);
5447:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5448:     ISCreate(PETSC_COMM_SELF, &fields);
5449:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5450:     ISSetType(fields, ISGENERAL);
5451:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5452:     DMSetRegionDS(dm, label, fields, ds);
5453:     ISDestroy(&fields);
5454:     PetscDSSetCoordinateDimension(ds, dE);
5455:     {
5456:       DMPolytopeType ct;
5457:       PetscInt       lStart, lEnd;
5458:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5460:       DMLabelGetBounds(label, &lStart, &lEnd);
5461:       if (lStart >= 0) {
5462:         DMPlexGetCellType(dm, lStart, &ct);
5463:         switch (ct) {
5464:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5465:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5466:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5467:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5468:             isHybridLocal = PETSC_TRUE;break;
5469:           default: break;
5470:         }
5471:       }
5472:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5473:       PetscDSSetHybrid(ds, isHybrid);
5474:     }
5475:     PetscDSDestroy(&ds);
5476:   }
5477:   PetscFree(labelSet);
5478:   /* Set fields in DSes */
5479:   for (s = 0; s < dm->Nds; ++s) {
5480:     PetscDS         ds     = dm->probs[s].ds;
5481:     IS              fields = dm->probs[s].fields;
5482:     const PetscInt *fld;
5483:     PetscInt        nf;

5485:     ISGetLocalSize(fields, &nf);
5486:     ISGetIndices(fields, &fld);
5487:     for (f = 0; f < nf; ++f) {
5488:       PetscObject  disc  = dm->fields[fld[f]].disc;
5489:       PetscBool    isHybrid;
5490:       PetscClassId id;

5492:       PetscDSGetHybrid(ds, &isHybrid);
5493:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5494:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5495:       PetscDSSetDiscretization(ds, f, disc);
5496:       /* We allow people to have placeholder fields and construct the Section by hand */
5497:       PetscObjectGetClassId(disc, &id);
5498:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5499:     }
5500:     ISRestoreIndices(fields, &fld);
5501:   }
5502:   /* Setup DSes */
5503:   if (doSetup) {
5504:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5505:   }
5506:   return(0);
5507: }

5509: /*@
5510:   DMCopyDS - Copy the discrete systems for the DM into another DM

5512:   Collective on dm

5514:   Input Parameter:
5515: . dm - The DM

5517:   Output Parameter:
5518: . newdm - The DM

5520:   Level: advanced

5522: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5523: @*/
5524: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5525: {
5526:   PetscInt       Nds, s;

5530:   if (dm == newdm) return(0);
5531:   DMGetNumDS(dm, &Nds);
5532:   DMClearDS(newdm);
5533:   for (s = 0; s < Nds; ++s) {
5534:     DMLabel  label;
5535:     IS       fields;
5536:     PetscDS  ds;
5537:     PetscInt Nbd, bd;

5539:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5540:     DMSetRegionDS(newdm, label, fields, ds);
5541:     PetscDSGetNumBoundary(ds, &Nbd);
5542:     for (bd = 0; bd < Nbd; ++bd) {
5543:       const char *labelname, *name;
5544:       PetscInt    field;

5546:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5547:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL);
5548:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5549:     }
5550:   }
5551:   return(0);
5552: }

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

5557:   Collective on dm

5559:   Input Parameter:
5560: . dm - The DM

5562:   Output Parameter:
5563: . newdm - The DM

5565:   Level: advanced

5567: .seealso: DMCopyFields(), DMCopyDS()
5568: @*/
5569: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5570: {

5574:   DMCopyFields(dm, newdm);
5575:   DMCopyDS(dm, newdm);
5576:   return(0);
5577: }

5579: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5580: {
5581:   DM dm_coord,dmc_coord;
5583:   Vec coords,ccoords;
5584:   Mat inject;
5586:   DMGetCoordinateDM(dm,&dm_coord);
5587:   DMGetCoordinateDM(dmc,&dmc_coord);
5588:   DMGetCoordinates(dm,&coords);
5589:   DMGetCoordinates(dmc,&ccoords);
5590:   if (coords && !ccoords) {
5591:     DMCreateGlobalVector(dmc_coord,&ccoords);
5592:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5593:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5594:     MatRestrict(inject,coords,ccoords);
5595:     MatDestroy(&inject);
5596:     DMSetCoordinates(dmc,ccoords);
5597:     VecDestroy(&ccoords);
5598:   }
5599:   return(0);
5600: }

5602: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5603: {
5604:   DM dm_coord,subdm_coord;
5606:   Vec coords,ccoords,clcoords;
5607:   VecScatter *scat_i,*scat_g;
5609:   DMGetCoordinateDM(dm,&dm_coord);
5610:   DMGetCoordinateDM(subdm,&subdm_coord);
5611:   DMGetCoordinates(dm,&coords);
5612:   DMGetCoordinates(subdm,&ccoords);
5613:   if (coords && !ccoords) {
5614:     DMCreateGlobalVector(subdm_coord,&ccoords);
5615:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5616:     DMCreateLocalVector(subdm_coord,&clcoords);
5617:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5618:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5619:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5620:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5621:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5622:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5623:     DMSetCoordinates(subdm,ccoords);
5624:     DMSetCoordinatesLocal(subdm,clcoords);
5625:     VecScatterDestroy(&scat_i[0]);
5626:     VecScatterDestroy(&scat_g[0]);
5627:     VecDestroy(&ccoords);
5628:     VecDestroy(&clcoords);
5629:     PetscFree(scat_i);
5630:     PetscFree(scat_g);
5631:   }
5632:   return(0);
5633: }

5635: /*@
5636:   DMGetDimension - Return the topological dimension of the DM

5638:   Not collective

5640:   Input Parameter:
5641: . dm - The DM

5643:   Output Parameter:
5644: . dim - The topological dimension

5646:   Level: beginner

5648: .seealso: DMSetDimension(), DMCreate()
5649: @*/
5650: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5651: {
5655:   *dim = dm->dim;
5656:   return(0);
5657: }

5659: /*@
5660:   DMSetDimension - Set the topological dimension of the DM

5662:   Collective on dm

5664:   Input Parameters:
5665: + dm - The DM
5666: - dim - The topological dimension

5668:   Level: beginner

5670: .seealso: DMGetDimension(), DMCreate()
5671: @*/
5672: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5673: {
5674:   PetscDS        ds;

5680:   dm->dim = dim;
5681:   DMGetDS(dm, &ds);
5682:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5683:   return(0);
5684: }

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

5689:   Collective on dm

5691:   Input Parameters:
5692: + dm - the DM
5693: - dim - the dimension

5695:   Output Parameters:
5696: + pStart - The first point of the given dimension
5697: - pEnd - The first point following points of the given dimension

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

5704:   Level: intermediate

5706: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5707: @*/
5708: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5709: {
5710:   PetscInt       d;

5715:   DMGetDimension(dm, &d);
5716:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5717:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5718:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5719:   return(0);
5720: }

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

5725:   Collective on dm

5727:   Input Parameters:
5728: + dm - the DM
5729: - c - coordinate vector

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

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

5736:   Level: intermediate

5738: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5739: @*/
5740: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5741: {

5747:   PetscObjectReference((PetscObject) c);
5748:   VecDestroy(&dm->coordinates);
5749:   dm->coordinates = c;
5750:   VecDestroy(&dm->coordinatesLocal);
5751:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5752:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5753:   return(0);
5754: }

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

5759:   Not collective

5761:    Input Parameters:
5762: +  dm - the DM
5763: -  c - coordinate vector

5765:   Notes:
5766:   The coordinates of ghost points can be set using DMSetCoordinates()
5767:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5768:   setting of ghost coordinates outside of the domain.

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

5772:   Level: intermediate

5774: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5775: @*/
5776: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5777: {

5783:   PetscObjectReference((PetscObject) c);
5784:   VecDestroy(&dm->coordinatesLocal);

5786:   dm->coordinatesLocal = c;

5788:   VecDestroy(&dm->coordinates);
5789:   return(0);
5790: }

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

5795:   Collective on dm

5797:   Input Parameter:
5798: . dm - the DM

5800:   Output Parameter:
5801: . c - global coordinate vector

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

5806:   Each process has only the local coordinates (does NOT have the ghost coordinates).

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

5811:   Level: intermediate

5813: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5814: @*/
5815: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5816: {

5822:   if (!dm->coordinates && dm->coordinatesLocal) {
5823:     DM        cdm = NULL;
5824:     PetscBool localized;

5826:     DMGetCoordinateDM(dm, &cdm);
5827:     DMCreateGlobalVector(cdm, &dm->coordinates);
5828:     DMGetCoordinatesLocalized(dm, &localized);
5829:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5830:     if (localized) {
5831:       PetscInt cdim;

5833:       DMGetCoordinateDim(dm, &cdim);
5834:       VecSetBlockSize(dm->coordinates, cdim);
5835:     }
5836:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
5837:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5838:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5839:   }
5840:   *c = dm->coordinates;
5841:   return(0);
5842: }

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

5847:   Collective on dm

5849:   Input Parameter:
5850: . dm - the DM

5852:   Level: advanced

5854: .seealso: DMGetCoordinatesLocalNoncollective()
5855: @*/
5856: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5857: {

5862:   if (!dm->coordinatesLocal && dm->coordinates) {
5863:     DM        cdm = NULL;
5864:     PetscBool localized;

5866:     DMGetCoordinateDM(dm, &cdm);
5867:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
5868:     DMGetCoordinatesLocalized(dm, &localized);
5869:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5870:     if (localized) {
5871:       PetscInt cdim;

5873:       DMGetCoordinateDim(dm, &cdim);
5874:       VecSetBlockSize(dm->coordinates, cdim);
5875:     }
5876:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
5877:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5878:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5879:   }
5880:   return(0);
5881: }

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

5886:   Collective on dm

5888:   Input Parameter:
5889: . dm - the DM

5891:   Output Parameter:
5892: . c - coordinate vector

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

5897:   Each process has the local and ghost coordinates

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

5902:   Level: intermediate

5904: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5905: @*/
5906: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5907: {

5913:   DMGetCoordinatesLocalSetUp(dm);
5914:   *c = dm->coordinatesLocal;
5915:   return(0);
5916: }

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

5921:   Not collective

5923:   Input Parameter:
5924: . dm - the DM

5926:   Output Parameter:
5927: . c - coordinate vector

5929:   Level: advanced

5931: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5932: @*/
5933: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5934: {
5938:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5939:   *c = dm->coordinatesLocal;
5940:   return(0);
5941: }

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

5946:   Not collective

5948:   Input Parameter:
5949: + dm - the DM
5950: - p - the IS of points whose coordinates will be returned

5952:   Output Parameter:
5953: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
5954: - pCoord - the Vec with coordinates of points in p

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

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

5961:   Each process has the local and ghost coordinates

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

5966:   Level: advanced

5968: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5969: @*/
5970: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5971: {
5972:   PetscSection        cs, newcs;
5973:   Vec                 coords;
5974:   const PetscScalar   *arr;
5975:   PetscScalar         *newarr=NULL;
5976:   PetscInt            n;
5977:   PetscErrorCode      ierr;

5984:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5985:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5986:   cs = dm->coordinateDM->localSection;
5987:   coords = dm->coordinatesLocal;
5988:   VecGetArrayRead(coords, &arr);
5989:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
5990:   VecRestoreArrayRead(coords, &arr);
5991:   if (pCoord) {
5992:     PetscSectionGetStorageSize(newcs, &n);
5993:     /* set array in two steps to mimic PETSC_OWN_POINTER */
5994:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
5995:     VecReplaceArray(*pCoord, newarr);
5996:   } else {
5997:     PetscFree(newarr);
5998:   }
5999:   if (pCoordSection) {*pCoordSection = newcs;}
6000:   else               {PetscSectionDestroy(&newcs);}
6001:   return(0);
6002: }

6004: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6005: {

6011:   if (!dm->coordinateField) {
6012:     if (dm->ops->createcoordinatefield) {
6013:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6014:     }
6015:   }
6016:   *field = dm->coordinateField;
6017:   return(0);
6018: }

6020: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6021: {

6027:   PetscObjectReference((PetscObject)field);
6028:   DMFieldDestroy(&dm->coordinateField);
6029:   dm->coordinateField = field;
6030:   return(0);
6031: }

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

6036:   Collective on dm

6038:   Input Parameter:
6039: . dm - the DM

6041:   Output Parameter:
6042: . cdm - coordinate DM

6044:   Level: intermediate

6046: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6047: @*/
6048: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6049: {

6055:   if (!dm->coordinateDM) {
6056:     DM cdm;

6058:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6059:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6060:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6061:      * until the call to CreateCoordinateDM) */
6062:     DMDestroy(&dm->coordinateDM);
6063:     dm->coordinateDM = cdm;
6064:   }
6065:   *cdm = dm->coordinateDM;
6066:   return(0);
6067: }

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

6072:   Logically Collective on dm

6074:   Input Parameters:
6075: + dm - the DM
6076: - cdm - coordinate DM

6078:   Level: intermediate

6080: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6081: @*/
6082: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6083: {

6089:   PetscObjectReference((PetscObject)cdm);
6090:   DMDestroy(&dm->coordinateDM);
6091:   dm->coordinateDM = cdm;
6092:   return(0);
6093: }

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

6098:   Not Collective

6100:   Input Parameter:
6101: . dm - The DM object

6103:   Output Parameter:
6104: . dim - The embedding dimension

6106:   Level: intermediate

6108: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6109: @*/
6110: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6111: {
6115:   if (dm->dimEmbed == PETSC_DEFAULT) {
6116:     dm->dimEmbed = dm->dim;
6117:   }
6118:   *dim = dm->dimEmbed;
6119:   return(0);
6120: }

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

6125:   Not Collective

6127:   Input Parameters:
6128: + dm  - The DM object
6129: - dim - The embedding dimension

6131:   Level: intermediate

6133: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6134: @*/
6135: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6136: {
6137:   PetscDS        ds;

6142:   dm->dimEmbed = dim;
6143:   DMGetDS(dm, &ds);
6144:   PetscDSSetCoordinateDimension(ds, dim);
6145:   return(0);
6146: }

6148: /*@
6149:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6151:   Collective on dm

6153:   Input Parameter:
6154: . dm - The DM object

6156:   Output Parameter:
6157: . section - The PetscSection object

6159:   Level: intermediate

6161: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6162: @*/
6163: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6164: {
6165:   DM             cdm;

6171:   DMGetCoordinateDM(dm, &cdm);
6172:   DMGetLocalSection(cdm, section);
6173:   return(0);
6174: }

6176: /*@
6177:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6179:   Not Collective

6181:   Input Parameters:
6182: + dm      - The DM object
6183: . dim     - The embedding dimension, or PETSC_DETERMINE
6184: - section - The PetscSection object

6186:   Level: intermediate

6188: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6189: @*/
6190: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6191: {
6192:   DM             cdm;

6198:   DMGetCoordinateDM(dm, &cdm);
6199:   DMSetLocalSection(cdm, section);
6200:   if (dim == PETSC_DETERMINE) {
6201:     PetscInt d = PETSC_DEFAULT;
6202:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6204:     PetscSectionGetChart(section, &pStart, &pEnd);
6205:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6206:     pStart = PetscMax(vStart, pStart);
6207:     pEnd   = PetscMin(vEnd, pEnd);
6208:     for (v = pStart; v < pEnd; ++v) {
6209:       PetscSectionGetDof(section, v, &dd);
6210:       if (dd) {d = dd; break;}
6211:     }
6212:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6213:   }
6214:   return(0);
6215: }

6217: /*@C
6218:   DMGetPeriodicity - Get the description of mesh periodicity

6220:   Input Parameters:
6221: . dm      - The DM object

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

6229:   Level: developer

6231: .seealso: DMGetPeriodicity()
6232: @*/
6233: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6234: {
6237:   if (per)     *per     = dm->periodic;
6238:   if (L)       *L       = dm->L;
6239:   if (maxCell) *maxCell = dm->maxCell;
6240:   if (bd)      *bd      = dm->bdtype;
6241:   return(0);
6242: }

6244: /*@C
6245:   DMSetPeriodicity - Set the description of mesh periodicity

6247:   Input Parameters:
6248: + dm      - The DM object
6249: . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6250: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6251: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6252: - bd      - This describes the type of periodicity in each topological dimension

6254:   Level: developer

6256: .seealso: DMGetPeriodicity()
6257: @*/
6258: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6259: {
6260:   PetscInt       dim, d;

6269:   DMGetDimension(dm, &dim);
6270:   if (maxCell) {
6271:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6272:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6273:   }
6274:   if (L) {
6275:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6276:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6277:   }
6278:   if (bd) {
6279:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6280:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6281:   }
6282:   dm->periodic = per;
6283:   return(0);
6284: }

6286: /*@
6287:   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.

6289:   Input Parameters:
6290: + dm     - The DM
6291: . in     - The input coordinate point (dim numbers)
6292: - endpoint - Include the endpoint L_i

6294:   Output Parameter:
6295: . out - The localized coordinate point

6297:   Level: developer

6299: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6300: @*/
6301: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6302: {
6303:   PetscInt       dim, d;

6307:   DMGetCoordinateDim(dm, &dim);
6308:   if (!dm->maxCell) {
6309:     for (d = 0; d < dim; ++d) out[d] = in[d];
6310:   } else {
6311:     if (endpoint) {
6312:       for (d = 0; d < dim; ++d) {
6313:         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)) {
6314:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6315:         } else {
6316:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6317:         }
6318:       }
6319:     } else {
6320:       for (d = 0; d < dim; ++d) {
6321:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6322:       }
6323:     }
6324:   }
6325:   return(0);
6326: }

6328: /*
6329:   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.

6331:   Input Parameters:
6332: + dm     - The DM
6333: . dim    - The spatial dimension
6334: . anchor - The anchor point, the input point can be no more than maxCell away from it
6335: - in     - The input coordinate point (dim numbers)

6337:   Output Parameter:
6338: . out - The localized coordinate point

6340:   Level: developer

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

6344: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6345: */
6346: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6347: {
6348:   PetscInt d;

6351:   if (!dm->maxCell) {
6352:     for (d = 0; d < dim; ++d) out[d] = in[d];
6353:   } else {
6354:     for (d = 0; d < dim; ++d) {
6355:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6356:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6357:       } else {
6358:         out[d] = in[d];
6359:       }
6360:     }
6361:   }
6362:   return(0);
6363: }

6365: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6366: {
6367:   PetscInt d;

6370:   if (!dm->maxCell) {
6371:     for (d = 0; d < dim; ++d) out[d] = in[d];
6372:   } else {
6373:     for (d = 0; d < dim; ++d) {
6374:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6375:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6376:       } else {
6377:         out[d] = in[d];
6378:       }
6379:     }
6380:   }
6381:   return(0);
6382: }

6384: /*
6385:   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.

6387:   Input Parameters:
6388: + dm     - The DM
6389: . dim    - The spatial dimension
6390: . anchor - The anchor point, the input point can be no more than maxCell away from it
6391: . in     - The input coordinate delta (dim numbers)
6392: - out    - The input coordinate point (dim numbers)

6394:   Output Parameter:
6395: . out    - The localized coordinate in + out

6397:   Level: developer

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

6401: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6402: */
6403: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6404: {
6405:   PetscInt d;

6408:   if (!dm->maxCell) {
6409:     for (d = 0; d < dim; ++d) out[d] += in[d];
6410:   } else {
6411:     for (d = 0; d < dim; ++d) {
6412:       const PetscReal maxC = dm->maxCell[d];

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

6417:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6418:           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]));
6419:         out[d] += newCoord;
6420:       } else {
6421:         out[d] += in[d];
6422:       }
6423:     }
6424:   }
6425:   return(0);
6426: }

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

6431:   Not collective

6433:   Input Parameter:
6434: . dm - The DM

6436:   Output Parameter:
6437:   areLocalized - True if localized

6439:   Level: developer

6441: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6442: @*/
6443: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6444: {
6445:   DM             cdm;
6446:   PetscSection   coordSection;
6447:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6448:   PetscBool      isPlex, alreadyLocalized;

6454:   *areLocalized = PETSC_FALSE;

6456:   /* We need some generic way of refering to cells/vertices */
6457:   DMGetCoordinateDM(dm, &cdm);
6458:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6459:   if (!isPlex) return(0);

6461:   DMGetCoordinateSection(dm, &coordSection);
6462:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6463:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6464:   alreadyLocalized = PETSC_FALSE;
6465:   for (c = cStart; c < cEnd; ++c) {
6466:     if (c < sStart || c >= sEnd) continue;
6467:     PetscSectionGetDof(coordSection, c, &dof);
6468:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6469:   }
6470:   *areLocalized = alreadyLocalized;
6471:   return(0);
6472: }

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

6477:   Collective on dm

6479:   Input Parameter:
6480: . dm - The DM

6482:   Output Parameter:
6483:   areLocalized - True if localized

6485:   Level: developer

6487: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6488: @*/
6489: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6490: {
6491:   PetscBool      localized;

6497:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6498:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6499:   return(0);
6500: }

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

6505:   Collective on dm

6507:   Input Parameter:
6508: . dm - The DM

6510:   Level: developer

6512: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6513: @*/
6514: PetscErrorCode DMLocalizeCoordinates(DM dm)
6515: {
6516:   DM             cdm;
6517:   PetscSection   coordSection, cSection;
6518:   Vec            coordinates,  cVec;
6519:   PetscScalar   *coords, *coords2, *anchor, *localized;
6520:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6521:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6522:   PetscInt       maxHeight = 0, h;
6523:   PetscInt       *pStart = NULL, *pEnd = NULL;

6528:   if (!dm->periodic) return(0);
6529:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6530:   if (alreadyLocalized) return(0);

6532:   /* We need some generic way of refering to cells/vertices */
6533:   DMGetCoordinateDM(dm, &cdm);
6534:   {
6535:     PetscBool isplex;

6537:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6538:     if (isplex) {
6539:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6540:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6541:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6542:       pEnd = &pStart[maxHeight + 1];
6543:       newStart = vStart;
6544:       newEnd   = vEnd;
6545:       for (h = 0; h <= maxHeight; h++) {
6546:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6547:         newStart = PetscMin(newStart,pStart[h]);
6548:         newEnd   = PetscMax(newEnd,pEnd[h]);
6549:       }
6550:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6551:   }
6552:   DMGetCoordinatesLocal(dm, &coordinates);
6553:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6554:   DMGetCoordinateSection(dm, &coordSection);
6555:   VecGetBlockSize(coordinates, &bs);
6556:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6558:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6559:   PetscSectionSetNumFields(cSection, 1);
6560:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6561:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6562:   PetscSectionSetChart(cSection, newStart, newEnd);

6564:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6565:   localized = &anchor[bs];
6566:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6567:   for (h = 0; h <= maxHeight; h++) {
6568:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6570:     for (c = cStart; c < cEnd; ++c) {
6571:       PetscScalar *cellCoords = NULL;
6572:       PetscInt     b;

6574:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6575:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6576:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6577:       for (d = 0; d < dof/bs; ++d) {
6578:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6579:         for (b = 0; b < bs; b++) {
6580:           if (cellCoords[d*bs + b] != localized[b]) break;
6581:         }
6582:         if (b < bs) break;
6583:       }
6584:       if (d < dof/bs) {
6585:         if (c >= sStart && c < sEnd) {
6586:           PetscInt cdof;

6588:           PetscSectionGetDof(coordSection, c, &cdof);
6589:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6590:         }
6591:         PetscSectionSetDof(cSection, c, dof);
6592:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6593:       }
6594:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6595:     }
6596:   }
6597:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6598:   if (alreadyLocalizedGlobal) {
6599:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6600:     PetscSectionDestroy(&cSection);
6601:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6602:     return(0);
6603:   }
6604:   for (v = vStart; v < vEnd; ++v) {
6605:     PetscSectionGetDof(coordSection, v, &dof);
6606:     PetscSectionSetDof(cSection, v, dof);
6607:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6608:   }
6609:   PetscSectionSetUp(cSection);
6610:   PetscSectionGetStorageSize(cSection, &coordSize);
6611:   VecCreate(PETSC_COMM_SELF, &cVec);
6612:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6613:   VecSetBlockSize(cVec, bs);
6614:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6615:   VecSetType(cVec, VECSTANDARD);
6616:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6617:   VecGetArray(cVec, &coords2);
6618:   for (v = vStart; v < vEnd; ++v) {
6619:     PetscSectionGetDof(coordSection, v, &dof);
6620:     PetscSectionGetOffset(coordSection, v, &off);
6621:     PetscSectionGetOffset(cSection,     v, &off2);
6622:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6623:   }
6624:   for (h = 0; h <= maxHeight; h++) {
6625:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6627:     for (c = cStart; c < cEnd; ++c) {
6628:       PetscScalar *cellCoords = NULL;
6629:       PetscInt     b, cdof;

6631:       PetscSectionGetDof(cSection,c,&cdof);
6632:       if (!cdof) continue;
6633:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6634:       PetscSectionGetOffset(cSection, c, &off2);
6635:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6636:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6637:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6638:     }
6639:   }
6640:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6641:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6642:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6643:   VecRestoreArray(cVec, &coords2);
6644:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6645:   DMSetCoordinatesLocal(dm, cVec);
6646:   VecDestroy(&cVec);
6647:   PetscSectionDestroy(&cSection);
6648:   return(0);
6649: }

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

6654:   Collective on v (see explanation below)

6656:   Input Parameters:
6657: + dm - The DM
6658: . v - The Vec of points
6659: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6660: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6662:   Output Parameter:
6663: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6664: - cells - The PetscSF containing the ranks and local indices of the containing points.


6667:   Level: developer

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

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

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

6678: $    const PetscSFNode *cells;
6679: $    PetscInt           nFound;
6680: $    const PetscInt    *found;
6681: $
6682: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

6687: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6688: @*/
6689: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6690: {

6697:   if (*cellSF) {
6698:     PetscMPIInt result;

6701:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6702:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6703:   } else {
6704:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6705:   }
6706:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6707:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6708:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6709:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6710:   return(0);
6711: }

6713: /*@
6714:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6716:   Collective on dm

6718:   Input Parameter:
6719: . dm - The original DM

6721:   Output Parameter:
6722: . odm - The DM which provides the layout for output

6724:   Level: intermediate

6726: .seealso: VecView(), DMGetGlobalSection()
6727: @*/
6728: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6729: {
6730:   PetscSection   section;
6731:   PetscBool      hasConstraints, ghasConstraints;

6737:   DMGetLocalSection(dm, &section);
6738:   PetscSectionHasConstraints(section, &hasConstraints);
6739:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6740:   if (!ghasConstraints) {
6741:     *odm = dm;
6742:     return(0);
6743:   }
6744:   if (!dm->dmBC) {
6745:     PetscSection newSection, gsection;
6746:     PetscSF      sf;

6748:     DMClone(dm, &dm->dmBC);
6749:     DMCopyDisc(dm, dm->dmBC);
6750:     PetscSectionClone(section, &newSection);
6751:     DMSetLocalSection(dm->dmBC, newSection);
6752:     PetscSectionDestroy(&newSection);
6753:     DMGetPointSF(dm->dmBC, &sf);
6754:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6755:     DMSetGlobalSection(dm->dmBC, gsection);
6756:     PetscSectionDestroy(&gsection);
6757:   }
6758:   *odm = dm->dmBC;
6759:   return(0);
6760: }

6762: /*@
6763:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6765:   Input Parameter:
6766: . dm - The original DM

6768:   Output Parameters:
6769: + num - The output sequence number
6770: - val - The output sequence value

6772:   Level: intermediate

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

6777: .seealso: VecView()
6778: @*/
6779: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6780: {
6785:   return(0);
6786: }

6788: /*@
6789:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6791:   Input Parameters:
6792: + dm - The original DM
6793: . num - The output sequence number
6794: - val - The output sequence value

6796:   Level: intermediate

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

6801: .seealso: VecView()
6802: @*/
6803: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6804: {
6807:   dm->outputSequenceNum = num;
6808:   dm->outputSequenceVal = val;
6809:   return(0);
6810: }

6812: /*@C
6813:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

6815:   Input Parameters:
6816: + dm   - The original DM
6817: . name - The sequence name
6818: - num  - The output sequence number

6820:   Output Parameter:
6821: . val  - The output sequence value

6823:   Level: intermediate

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

6828: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6829: @*/
6830: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6831: {
6832:   PetscBool      ishdf5;

6839:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
6840:   if (ishdf5) {
6841: #if defined(PETSC_HAVE_HDF5)
6842:     PetscScalar value;

6844:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6845:     *val = PetscRealPart(value);
6846: #endif
6847:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6848:   return(0);
6849: }

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

6854:   Not collective

6856:   Input Parameter:
6857: . dm - The DM

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

6862:   Level: beginner

6864: .seealso: DMSetUseNatural(), DMCreate()
6865: @*/
6866: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6867: {
6871:   *useNatural = dm->useNatural;
6872:   return(0);
6873: }

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

6878:   Collective on dm

6880:   Input Parameters:
6881: + dm - The DM
6882: - useNatural - The flag to build the mapping to a natural order during distribution

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

6886:   Level: beginner

6888: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6889: @*/
6890: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6891: {
6895:   dm->useNatural = useNatural;
6896:   return(0);
6897: }


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

6903:   Not Collective

6905:   Input Parameters:
6906: + dm   - The DM object
6907: - name - The label name

6909:   Level: intermediate

6911: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6912: @*/
6913: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6914: {
6915:   PetscBool      flg;
6916:   DMLabel        label;

6922:   DMHasLabel(dm, name, &flg);
6923:   if (!flg) {
6924:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6925:     DMAddLabel(dm, label);
6926:     DMLabelDestroy(&label);
6927:   }
6928:   return(0);
6929: }

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

6934:   Not Collective

6936:   Input Parameters:
6937: + dm   - The DM object
6938: . name - The label name
6939: - point - The mesh point

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

6944:   Level: beginner

6946: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6947: @*/
6948: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6949: {
6950:   DMLabel        label;

6956:   DMGetLabel(dm, name, &label);
6957:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6958:   DMLabelGetValue(label, point, value);
6959:   return(0);
6960: }

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

6965:   Not Collective

6967:   Input Parameters:
6968: + dm   - The DM object
6969: . name - The label name
6970: . point - The mesh point
6971: - value - The label value for this point

6973:   Output Parameter:

6975:   Level: beginner

6977: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6978: @*/
6979: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6980: {
6981:   DMLabel        label;

6987:   DMGetLabel(dm, name, &label);
6988:   if (!label) {
6989:     DMCreateLabel(dm, name);
6990:     DMGetLabel(dm, name, &label);
6991:   }
6992:   DMLabelSetValue(label, point, value);
6993:   return(0);
6994: }

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

6999:   Not Collective

7001:   Input Parameters:
7002: + dm   - The DM object
7003: . name - The label name
7004: . point - The mesh point
7005: - value - The label value for this point

7007:   Output Parameter:

7009:   Level: beginner

7011: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7012: @*/
7013: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7014: {
7015:   DMLabel        label;

7021:   DMGetLabel(dm, name, &label);
7022:   if (!label) return(0);
7023:   DMLabelClearValue(label, point, value);
7024:   return(0);
7025: }

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

7030:   Not Collective

7032:   Input Parameters:
7033: + dm   - The DM object
7034: - name - The label name

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

7039:   Level: beginner

7041: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7042: @*/
7043: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7044: {
7045:   DMLabel        label;

7052:   DMGetLabel(dm, name, &label);
7053:   *size = 0;
7054:   if (!label) return(0);
7055:   DMLabelGetNumValues(label, size);
7056:   return(0);
7057: }

7059: /*@C
7060:   DMGetLabelIdIS - Get the integer ids in a label

7062:   Not Collective

7064:   Input Parameters:
7065: + mesh - The DM object
7066: - name - The label name

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

7071:   Level: beginner

7073: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7074: @*/
7075: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7076: {
7077:   DMLabel        label;

7084:   DMGetLabel(dm, name, &label);
7085:   *ids = NULL;
7086:  if (label) {
7087:     DMLabelGetValueIS(label, ids);
7088:   } else {
7089:     /* returning an empty IS */
7090:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7091:   }
7092:   return(0);
7093: }

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

7098:   Not Collective

7100:   Input Parameters:
7101: + dm - The DM object
7102: . name - The label name
7103: - value - The stratum value

7105:   Output Parameter:
7106: . size - The stratum size

7108:   Level: beginner

7110: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7111: @*/
7112: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7113: {
7114:   DMLabel        label;

7121:   DMGetLabel(dm, name, &label);
7122:   *size = 0;
7123:   if (!label) return(0);
7124:   DMLabelGetStratumSize(label, value, size);
7125:   return(0);
7126: }

7128: /*@C
7129:   DMGetStratumIS - Get the points in a label stratum

7131:   Not Collective

7133:   Input Parameters:
7134: + dm - The DM object
7135: . name - The label name
7136: - value - The stratum value

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

7141:   Level: beginner

7143: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7144: @*/
7145: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7146: {
7147:   DMLabel        label;

7154:   DMGetLabel(dm, name, &label);
7155:   *points = NULL;
7156:   if (!label) return(0);
7157:   DMLabelGetStratumIS(label, value, points);
7158:   return(0);
7159: }

7161: /*@C
7162:   DMSetStratumIS - Set the points in a label stratum

7164:   Not Collective

7166:   Input Parameters:
7167: + dm - The DM object
7168: . name - The label name
7169: . value - The stratum value
7170: - points - The stratum points

7172:   Level: beginner

7174: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7175: @*/
7176: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7177: {
7178:   DMLabel        label;

7185:   DMGetLabel(dm, name, &label);
7186:   if (!label) return(0);
7187:   DMLabelSetStratumIS(label, value, points);
7188:   return(0);
7189: }

7191: /*@C
7192:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7194:   Not Collective

7196:   Input Parameters:
7197: + dm   - The DM object
7198: . name - The label name
7199: - value - The label value for this point

7201:   Output Parameter:

7203:   Level: beginner

7205: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7206: @*/
7207: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7208: {
7209:   DMLabel        label;

7215:   DMGetLabel(dm, name, &label);
7216:   if (!label) return(0);
7217:   DMLabelClearStratum(label, value);
7218:   return(0);
7219: }

7221: /*@
7222:   DMGetNumLabels - Return the number of labels defined by the mesh

7224:   Not Collective

7226:   Input Parameter:
7227: . dm   - The DM object

7229:   Output Parameter:
7230: . numLabels - the number of Labels

7232:   Level: intermediate

7234: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7235: @*/
7236: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7237: {
7238:   DMLabelLink next = dm->labels;
7239:   PetscInt  n    = 0;

7244:   while (next) {++n; next = next->next;}
7245:   *numLabels = n;
7246:   return(0);
7247: }

7249: /*@C
7250:   DMGetLabelName - Return the name of nth label

7252:   Not Collective

7254:   Input Parameters:
7255: + dm - The DM object
7256: - n  - the label number

7258:   Output Parameter:
7259: . name - the label name

7261:   Level: intermediate

7263: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7264: @*/
7265: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7266: {
7267:   DMLabelLink    next = dm->labels;
7268:   PetscInt       l    = 0;

7274:   while (next) {
7275:     if (l == n) {
7276:       PetscObjectGetName((PetscObject) next->label, name);
7277:       return(0);
7278:     }
7279:     ++l;
7280:     next = next->next;
7281:   }
7282:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7283: }

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

7288:   Not Collective

7290:   Input Parameters:
7291: + dm   - The DM object
7292: - name - The label name

7294:   Output Parameter:
7295: . hasLabel - PETSC_TRUE if the label is present

7297:   Level: intermediate

7299: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7300: @*/
7301: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7302: {
7303:   DMLabelLink    next = dm->labels;
7304:   const char    *lname;

7311:   *hasLabel = PETSC_FALSE;
7312:   while (next) {
7313:     PetscObjectGetName((PetscObject) next->label, &lname);
7314:     PetscStrcmp(name, lname, hasLabel);
7315:     if (*hasLabel) break;
7316:     next = next->next;
7317:   }
7318:   return(0);
7319: }

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

7324:   Not Collective

7326:   Input Parameters:
7327: + dm   - The DM object
7328: - name - The label name

7330:   Output Parameter:
7331: . label - The DMLabel, or NULL if the label is absent

7333:   Level: intermediate

7335: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7336: @*/
7337: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7338: {
7339:   DMLabelLink    next = dm->labels;
7340:   PetscBool      hasLabel;
7341:   const char    *lname;

7348:   *label = NULL;
7349:   while (next) {
7350:     PetscObjectGetName((PetscObject) next->label, &lname);
7351:     PetscStrcmp(name, lname, &hasLabel);
7352:     if (hasLabel) {
7353:       *label = next->label;
7354:       break;
7355:     }
7356:     next = next->next;
7357:   }
7358:   return(0);
7359: }

7361: /*@C
7362:   DMGetLabelByNum - Return the nth label

7364:   Not Collective

7366:   Input Parameters:
7367: + dm - The DM object
7368: - n  - the label number

7370:   Output Parameter:
7371: . label - the label

7373:   Level: intermediate

7375: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7376: @*/
7377: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7378: {
7379:   DMLabelLink next = dm->labels;
7380:   PetscInt    l    = 0;

7385:   while (next) {
7386:     if (l == n) {
7387:       *label = next->label;
7388:       return(0);
7389:     }
7390:     ++l;
7391:     next = next->next;
7392:   }
7393:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7394: }

7396: /*@C
7397:   DMAddLabel - Add the label to this mesh

7399:   Not Collective

7401:   Input Parameters:
7402: + dm   - The DM object
7403: - label - The DMLabel

7405:   Level: developer

7407: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7408: @*/
7409: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7410: {
7411:   DMLabelLink    l, *p, tmpLabel;
7412:   PetscBool      hasLabel;
7413:   const char    *lname;
7414:   PetscBool      flg;

7419:   PetscObjectGetName((PetscObject) label, &lname);
7420:   DMHasLabel(dm, lname, &hasLabel);
7421:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7422:   PetscCalloc1(1, &tmpLabel);
7423:   tmpLabel->label  = label;
7424:   tmpLabel->output = PETSC_TRUE;
7425:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7426:   *p = tmpLabel;
7427:   PetscObjectReference((PetscObject)label);
7428:   PetscStrcmp(lname, "depth", &flg);
7429:   if (flg) dm->depthLabel = label;
7430:   PetscStrcmp(lname, "celltype", &flg);
7431:   if (flg) dm->celltypeLabel = label;
7432:   return(0);
7433: }

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

7438:   Not Collective

7440:   Input Parameters:
7441: + dm   - The DM object
7442: - name - The label name

7444:   Output Parameter:
7445: . label - The DMLabel, or NULL if the label is absent

7447:   Level: developer

7449:   Notes:
7450:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7451:   DMLabelDestroy() on the label.

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

7457: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7458: @*/
7459: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7460: {
7461:   DMLabelLink    link, *pnext;
7462:   PetscBool      hasLabel;
7463:   const char    *lname;

7469:   if (label) {
7471:     *label = NULL;
7472:   }
7473:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7474:     PetscObjectGetName((PetscObject) link->label, &lname);
7475:     PetscStrcmp(name, lname, &hasLabel);
7476:     if (hasLabel) {
7477:       *pnext = link->next; /* Remove from list */
7478:       PetscStrcmp(name, "depth", &hasLabel);
7479:       if (hasLabel) dm->depthLabel = NULL;
7480:       PetscStrcmp(name, "celltype", &hasLabel);
7481:       if (hasLabel) dm->celltypeLabel = NULL;
7482:       if (label) *label = link->label;
7483:       else       {DMLabelDestroy(&link->label);}
7484:       PetscFree(link);
7485:       break;
7486:     }
7487:   }
7488:   return(0);
7489: }

7491: /*@
7492:   DMRemoveLabelBySelf - Remove the label from this mesh

7494:   Not Collective

7496:   Input Parameters:
7497: + dm   - The DM object
7498: . label - (Optional) The DMLabel to be removed from the DM
7499: - failNotFound - Should it fail if the label is not found in the DM?

7501:   Level: developer

7503:   Notes:
7504:   Only exactly the same instance is removed if found, name match is ignored.
7505:   If the DM has an exclusive reference to the label, it gets destroyed and
7506:   *label nullified.

7508: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7509: @*/
7510: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7511: {
7512:   DMLabelLink    link, *pnext;
7513:   PetscBool      hasLabel = PETSC_FALSE;

7519:   if (!*label && !failNotFound) return(0);
7522:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7523:     if (*label == link->label) {
7524:       hasLabel = PETSC_TRUE;
7525:       *pnext = link->next; /* Remove from list */
7526:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7527:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7528:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7529:       DMLabelDestroy(&link->label);
7530:       PetscFree(link);
7531:       break;
7532:     }
7533:   }
7534:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7535:   return(0);
7536: }

7538: /*@C
7539:   DMGetLabelOutput - Get the output flag for a given label

7541:   Not Collective

7543:   Input Parameters:
7544: + dm   - The DM object
7545: - name - The label name

7547:   Output Parameter:
7548: . output - The flag for output

7550:   Level: developer

7552: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7553: @*/
7554: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7555: {
7556:   DMLabelLink    next = dm->labels;
7557:   const char    *lname;

7564:   while (next) {
7565:     PetscBool flg;

7567:     PetscObjectGetName((PetscObject) next->label, &lname);
7568:     PetscStrcmp(name, lname, &flg);
7569:     if (flg) {*output = next->output; return(0);}
7570:     next = next->next;
7571:   }
7572:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7573: }

7575: /*@C
7576:   DMSetLabelOutput - Set the output flag for a given label

7578:   Not Collective

7580:   Input Parameters:
7581: + dm     - The DM object
7582: . name   - The label name
7583: - output - The flag for output

7585:   Level: developer

7587: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7588: @*/
7589: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7590: {
7591:   DMLabelLink    next = dm->labels;
7592:   const char    *lname;

7598:   while (next) {
7599:     PetscBool flg;

7601:     PetscObjectGetName((PetscObject) next->label, &lname);
7602:     PetscStrcmp(name, lname, &flg);
7603:     if (flg) {next->output = output; return(0);}
7604:     next = next->next;
7605:   }
7606:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7607: }

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

7612:   Collective on dmA

7614:   Input Parameter:
7615: + dmA - The DM object with initial labels
7616: . dmB - The DM object with copied labels
7617: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7618: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7620:   Level: intermediate

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

7624: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7625: @*/
7626: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7627: {
7628:   DMLabel        label, labelNew;
7629:   const char    *name;
7630:   PetscBool      flg;
7631:   DMLabelLink    link;

7639:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7640:   if (dmA == dmB) return(0);
7641:   for (link=dmA->labels; link; link=link->next) {
7642:     label=link->label;
7643:     PetscObjectGetName((PetscObject)label, &name);
7644:     if (!all) {
7645:       PetscStrcmp(name, "depth", &flg);
7646:       if (flg) continue;
7647:       PetscStrcmp(name, "dim", &flg);
7648:       if (flg) continue;
7649:       PetscStrcmp(name, "celltype", &flg);
7650:       if (flg) continue;
7651:     }
7652:     if (mode==PETSC_COPY_VALUES) {
7653:       DMLabelDuplicate(label, &labelNew);
7654:     } else {
7655:       labelNew = label;
7656:     }
7657:     DMAddLabel(dmB, labelNew);
7658:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7659:   }
7660:   return(0);
7661: }

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

7666:   Input Parameter:
7667: . dm - The DM object

7669:   Output Parameter:
7670: . cdm - The coarse DM

7672:   Level: intermediate

7674: .seealso: DMSetCoarseDM()
7675: @*/
7676: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7677: {
7681:   *cdm = dm->coarseMesh;
7682:   return(0);
7683: }

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

7688:   Input Parameters:
7689: + dm - The DM object
7690: - cdm - The coarse DM

7692:   Level: intermediate

7694: .seealso: DMGetCoarseDM()
7695: @*/
7696: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7697: {

7703:   PetscObjectReference((PetscObject)cdm);
7704:   DMDestroy(&dm->coarseMesh);
7705:   dm->coarseMesh = cdm;
7706:   return(0);
7707: }

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

7712:   Input Parameter:
7713: . dm - The DM object

7715:   Output Parameter:
7716: . fdm - The fine DM

7718:   Level: intermediate

7720: .seealso: DMSetFineDM()
7721: @*/
7722: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7723: {
7727:   *fdm = dm->fineMesh;
7728:   return(0);
7729: }

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

7734:   Input Parameters:
7735: + dm - The DM object
7736: - fdm - The fine DM

7738:   Level: intermediate

7740: .seealso: DMGetFineDM()
7741: @*/
7742: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7743: {

7749:   PetscObjectReference((PetscObject)fdm);
7750:   DMDestroy(&dm->fineMesh);
7751:   dm->fineMesh = fdm;
7752:   return(0);
7753: }

7755: /*=== DMBoundary code ===*/

7757: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7758: {
7759:   PetscInt       d;

7763:   for (d = 0; d < dm->Nds; ++d) {
7764:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7765:   }
7766:   return(0);
7767: }

7769: /*@C
7770:   DMAddBoundary - Add a boundary condition to the model

7772:   Collective on dm

7774:   Input Parameters:
7775: + dm          - The DM, with a PetscDS that matches the problem being constrained
7776: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7777: . name        - The BC name
7778: . labelname   - The label defining constrained points
7779: . field       - The field to constrain
7780: . numcomps    - The number of constrained field components (0 will constrain all fields)
7781: . comps       - An array of constrained component numbers
7782: . bcFunc      - A pointwise function giving boundary values
7783: . numids      - The number of DMLabel ids for constrained points
7784: . ids         - An array of ids for constrained points
7785: - ctx         - An optional user context for bcFunc

7787:   Options Database Keys:
7788: + -bc_<boundary name> <num> - Overrides the boundary ids
7789: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7791:   Level: developer

7793: .seealso: DMGetBoundary()
7794: @*/
7795: 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)
7796: {
7797:   PetscDS        ds;

7806:   DMGetDS(dm, &ds);
7807:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
7808:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);
7809:   return(0);
7810: }

7812: /*@
7813:   DMGetNumBoundary - Get the number of registered BC

7815:   Input Parameters:
7816: . dm - The mesh object

7818:   Output Parameters:
7819: . numBd - The number of BC

7821:   Level: intermediate

7823: .seealso: DMAddBoundary(), DMGetBoundary()
7824: @*/
7825: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7826: {
7827:   PetscDS        ds;

7832:   DMGetDS(dm, &ds);
7833:   PetscDSGetNumBoundary(ds, numBd);
7834:   return(0);
7835: }

7837: /*@C
7838:   DMGetBoundary - Get a model boundary condition

7840:   Input Parameters:
7841: + dm          - The mesh object
7842: - bd          - The BC number

7844:   Output Parameters:
7845: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7846: . name        - The BC name
7847: . labelname   - The label defining constrained points
7848: . field       - The field to constrain
7849: . numcomps    - The number of constrained field components
7850: . comps       - An array of constrained component numbers
7851: . bcFunc      - A pointwise function giving boundary values
7852: . numids      - The number of DMLabel ids for constrained points
7853: . ids         - An array of ids for constrained points
7854: - ctx         - An optional user context for bcFunc

7856:   Options Database Keys:
7857: + -bc_<boundary name> <num> - Overrides the boundary ids
7858: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7860:   Level: developer

7862: .seealso: DMAddBoundary()
7863: @*/
7864: 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)
7865: {
7866:   PetscDS        ds;

7871:   DMGetDS(dm, &ds);
7872:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);
7873:   return(0);
7874: }

7876: static PetscErrorCode DMPopulateBoundary(DM dm)
7877: {
7878:   PetscDS        ds;
7879:   DMBoundary    *lastnext;
7880:   DSBoundary     dsbound;

7884:   DMGetDS(dm, &ds);
7885:   dsbound = ds->boundary;
7886:   if (dm->boundary) {
7887:     DMBoundary next = dm->boundary;

7889:     /* quick check to see if the PetscDS has changed */
7890:     if (next->dsboundary == dsbound) return(0);
7891:     /* the PetscDS has changed: tear down and rebuild */
7892:     while (next) {
7893:       DMBoundary b = next;

7895:       next = b->next;
7896:       PetscFree(b);
7897:     }
7898:     dm->boundary = NULL;
7899:   }

7901:   lastnext = &(dm->boundary);
7902:   while (dsbound) {
7903:     DMBoundary dmbound;

7905:     PetscNew(&dmbound);
7906:     dmbound->dsboundary = dsbound;
7907:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
7908:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
7909:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7910:     *lastnext = dmbound;
7911:     lastnext = &(dmbound->next);
7912:     dsbound = dsbound->next;
7913:   }
7914:   return(0);
7915: }

7917: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7918: {
7919:   DMBoundary     b;

7925:   *isBd = PETSC_FALSE;
7926:   DMPopulateBoundary(dm);
7927:   b = dm->boundary;
7928:   while (b && !(*isBd)) {
7929:     DMLabel    label = b->label;
7930:     DSBoundary dsb = b->dsboundary;

7932:     if (label) {
7933:       PetscInt i;

7935:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7936:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
7937:       }
7938:     }
7939:     b = b->next;
7940:   }
7941:   return(0);
7942: }

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

7947:   Collective on DM

7949:   Input Parameters:
7950: + dm      - The DM
7951: . time    - The time
7952: . funcs   - The coordinate functions to evaluate, one per field
7953: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7954: - mode    - The insertion mode for values

7956:   Output Parameter:
7957: . X - vector

7959:    Calling sequence of func:
7960: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7962: +  dim - The spatial dimension
7963: .  x   - The coordinates
7964: .  Nf  - The number of fields
7965: .  u   - The output field values
7966: -  ctx - optional user-defined function context

7968:   Level: developer

7970: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7971: @*/
7972: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7973: {
7974:   Vec            localX;

7979:   DMGetLocalVector(dm, &localX);
7980:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7981:   DMLocalToGlobalBegin(dm, localX, mode, X);
7982:   DMLocalToGlobalEnd(dm, localX, mode, X);
7983:   DMRestoreLocalVector(dm, &localX);
7984:   return(0);
7985: }

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

7990:   Not collective

7992:   Input Parameters:
7993: + dm      - The DM
7994: . time    - The time
7995: . funcs   - The coordinate functions to evaluate, one per field
7996: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7997: - mode    - The insertion mode for values

7999:   Output Parameter:
8000: . localX - vector

8002:    Calling sequence of func:
8003: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8005: +  dim - The spatial dimension
8006: .  x   - The coordinates
8007: .  Nf  - The number of fields
8008: .  u   - The output field values
8009: -  ctx - optional user-defined function context

8011:   Level: developer

8013: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8014: @*/
8015: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8016: {

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

8027: /*@C
8028:   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.

8030:   Collective on DM

8032:   Input Parameters:
8033: + dm      - The DM
8034: . time    - The time
8035: . label   - The DMLabel selecting the portion of the mesh for projection
8036: . funcs   - The coordinate functions to evaluate, one per field
8037: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8038: - mode    - The insertion mode for values

8040:   Output Parameter:
8041: . X - vector

8043:    Calling sequence of func:
8044: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8046: +  dim - The spatial dimension
8047: .  x   - The coordinates
8048: .  Nf  - The number of fields
8049: .  u   - The output field values
8050: -  ctx - optional user-defined function context

8052:   Level: developer

8054: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8055: @*/
8056: 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)
8057: {
8058:   Vec            localX;

8063:   DMGetLocalVector(dm, &localX);
8064:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8065:   DMLocalToGlobalBegin(dm, localX, mode, X);
8066:   DMLocalToGlobalEnd(dm, localX, mode, X);
8067:   DMRestoreLocalVector(dm, &localX);
8068:   return(0);
8069: }

8071: /*@C
8072:   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.

8074:   Not collective

8076:   Input Parameters:
8077: + dm      - The DM
8078: . time    - The time
8079: . label   - The DMLabel selecting the portion of the mesh for projection
8080: . funcs   - The coordinate functions to evaluate, one per field
8081: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8082: - mode    - The insertion mode for values

8084:   Output Parameter:
8085: . localX - vector

8087:    Calling sequence of func:
8088: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8090: +  dim - The spatial dimension
8091: .  x   - The coordinates
8092: .  Nf  - The number of fields
8093: .  u   - The output field values
8094: -  ctx - optional user-defined function context

8096:   Level: developer

8098: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8099: @*/
8100: 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)
8101: {

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

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

8115:   Not collective

8117:   Input Parameters:
8118: + dm      - The DM
8119: . time    - The time
8120: . localU  - The input field vector
8121: . funcs   - The functions to evaluate, one per field
8122: - mode    - The insertion mode for values

8124:   Output Parameter:
8125: . localX  - The output vector

8127:    Calling sequence of func:
8128: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8129: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8130: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8131: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8133: +  dim          - The spatial dimension
8134: .  Nf           - The number of input fields
8135: .  NfAux        - The number of input auxiliary fields
8136: .  uOff         - The offset of each field in u[]
8137: .  uOff_x       - The offset of each field in u_x[]
8138: .  u            - The field values at this point in space
8139: .  u_t          - The field time derivative at this point in space (or NULL)
8140: .  u_x          - The field derivatives at this point in space
8141: .  aOff         - The offset of each auxiliary field in u[]
8142: .  aOff_x       - The offset of each auxiliary field in u_x[]
8143: .  a            - The auxiliary field values at this point in space
8144: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8145: .  a_x          - The auxiliary field derivatives at this point in space
8146: .  t            - The current time
8147: .  x            - The coordinates of this point
8148: .  numConstants - The number of constants
8149: .  constants    - The value of each constant
8150: -  f            - The value of the function at this point in space

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

8157:   Level: intermediate

8159: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8160: @*/
8161: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8162:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8163:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8164:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8165:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8166:                                    InsertMode mode, Vec localX)
8167: {

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

8179: /*@C
8180:   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.

8182:   Not collective

8184:   Input Parameters:
8185: + dm      - The DM
8186: . time    - The time
8187: . label   - The DMLabel marking the portion of the domain to output
8188: . numIds  - The number of label ids to use
8189: . ids     - The label ids to use for marking
8190: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8191: . comps   - The components to set in the output, or NULL for all components
8192: . localU  - The input field vector
8193: . funcs   - The functions to evaluate, one per field
8194: - mode    - The insertion mode for values

8196:   Output Parameter:
8197: . localX  - The output vector

8199:    Calling sequence of func:
8200: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8201: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8202: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8203: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8205: +  dim          - The spatial dimension
8206: .  Nf           - The number of input fields
8207: .  NfAux        - The number of input auxiliary fields
8208: .  uOff         - The offset of each field in u[]
8209: .  uOff_x       - The offset of each field in u_x[]
8210: .  u            - The field values at this point in space
8211: .  u_t          - The field time derivative at this point in space (or NULL)
8212: .  u_x          - The field derivatives at this point in space
8213: .  aOff         - The offset of each auxiliary field in u[]
8214: .  aOff_x       - The offset of each auxiliary field in u_x[]
8215: .  a            - The auxiliary field values at this point in space
8216: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8217: .  a_x          - The auxiliary field derivatives at this point in space
8218: .  t            - The current time
8219: .  x            - The coordinates of this point
8220: .  numConstants - The number of constants
8221: .  constants    - The value of each constant
8222: -  f            - The value of the function at this point in space

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

8229:   Level: intermediate

8231: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8232: @*/
8233: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8234:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8235:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8236:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8237:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8238:                                         InsertMode mode, Vec localX)
8239: {

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

8251: /*@C
8252:   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.

8254:   Not collective

8256:   Input Parameters:
8257: + dm      - The DM
8258: . time    - The time
8259: . label   - The DMLabel marking the portion of the domain boundary to output
8260: . numIds  - The number of label ids to use
8261: . ids     - The label ids to use for marking
8262: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8263: . comps   - The components to set in the output, or NULL for all components
8264: . localU  - The input field vector
8265: . funcs   - The functions to evaluate, one per field
8266: - mode    - The insertion mode for values

8268:   Output Parameter:
8269: . localX  - The output vector

8271:    Calling sequence of func:
8272: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8273: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8274: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8275: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8277: +  dim          - The spatial dimension
8278: .  Nf           - The number of input fields
8279: .  NfAux        - The number of input auxiliary fields
8280: .  uOff         - The offset of each field in u[]
8281: .  uOff_x       - The offset of each field in u_x[]
8282: .  u            - The field values at this point in space
8283: .  u_t          - The field time derivative at this point in space (or NULL)
8284: .  u_x          - The field derivatives at this point in space
8285: .  aOff         - The offset of each auxiliary field in u[]
8286: .  aOff_x       - The offset of each auxiliary field in u_x[]
8287: .  a            - The auxiliary field values at this point in space
8288: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8289: .  a_x          - The auxiliary field derivatives at this point in space
8290: .  t            - The current time
8291: .  x            - The coordinates of this point
8292: .  n            - The face normal
8293: .  numConstants - The number of constants
8294: .  constants    - The value of each constant
8295: -  f            - The value of the function at this point in space

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

8303:   Level: intermediate

8305: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8306: @*/
8307: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8308:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8309:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8310:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8311:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8312:                                           InsertMode mode, Vec localX)
8313: {

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

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

8328:   Input Parameters:
8329: + dm    - The DM
8330: . time  - The time
8331: . funcs - The functions to evaluate for each field component
8332: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8333: - X     - The coefficient vector u_h, a global vector

8335:   Output Parameter:
8336: . diff - The diff ||u - u_h||_2

8338:   Level: developer

8340: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8341: @*/
8342: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8343: {

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

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

8357:   Collective on dm

8359:   Input Parameters:
8360: + dm    - The DM
8361: , time  - The time
8362: . funcs - The gradient functions to evaluate for each field component
8363: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8364: . X     - The coefficient vector u_h, a global vector
8365: - n     - The vector to project along

8367:   Output Parameter:
8368: . diff - The diff ||(grad u - grad u_h) . n||_2

8370:   Level: developer

8372: .seealso: DMProjectFunction(), DMComputeL2Diff()
8373: @*/
8374: 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)
8375: {

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

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

8389:   Collective on dm

8391:   Input Parameters:
8392: + dm    - The DM
8393: . time  - The time
8394: . funcs - The functions to evaluate for each field component
8395: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8396: - X     - The coefficient vector u_h, a global vector

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

8401:   Level: developer

8403: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8404: @*/
8405: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8406: {

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

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

8421:   Collective on dm

8423:   Input parameters:
8424: + dm - the pre-adaptation DM object
8425: - label - label with the flags

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

8430:   Level: intermediate

8432: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8433: @*/
8434: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8435: {

8442:   *dmAdapt = NULL;
8443:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8444:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8445:   return(0);
8446: }

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

8451:   Input Parameters:
8452: + dm - The DM object
8453: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8454: - 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_".

8456:   Output Parameter:
8457: . dmAdapt  - Pointer to the DM object containing the adapted mesh

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

8461:   Level: advanced

8463: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8464: @*/
8465: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8466: {

8474:   *dmAdapt = NULL;
8475:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8476:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8477:   return(0);
8478: }

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

8483:  Not Collective

8485:  Input Parameter:
8486: .  dm    - The DM

8488:  Output Parameters:
8489: +  nranks - the number of neighbours
8490: -  ranks - the neighbors ranks

8492:  Notes:
8493:  Do not free the array, it is freed when the DM is destroyed.

8495:  Level: beginner

8497:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8498: @*/
8499: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8500: {

8505:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8506:   (dm->ops->getneighbors)(dm,nranks,ranks);
8507:   return(0);
8508: }

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

8512: /*
8513:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8514:     This has be a different function because it requires DM which is not defined in the Mat library
8515: */
8516: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8517: {

8521:   if (coloring->ctype == IS_COLORING_LOCAL) {
8522:     Vec x1local;
8523:     DM  dm;
8524:     MatGetDM(J,&dm);
8525:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8526:     DMGetLocalVector(dm,&x1local);
8527:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8528:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8529:     x1   = x1local;
8530:   }
8531:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8532:   if (coloring->ctype == IS_COLORING_LOCAL) {
8533:     DM  dm;
8534:     MatGetDM(J,&dm);
8535:     DMRestoreLocalVector(dm,&x1);
8536:   }
8537:   return(0);
8538: }

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

8543:     Input Parameter:
8544: .    coloring - the MatFDColoring object

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

8549:     Level: advanced

8551: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8552: @*/
8553: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8554: {
8556:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8557:   return(0);
8558: }

8560: /*@
8561:     DMGetCompatibility - determine if two DMs are compatible

8563:     Collective

8565:     Input Parameters:
8566: +    dm1 - the first DM
8567: -    dm2 - the second DM

8569:     Output Parameters:
8570: +    compatible - whether or not the two DMs are compatible
8571: -    set - whether or not the compatible value was set

8573:     Notes:
8574:     Two DMs are deemed compatible if they represent the same parallel decomposition
8575:     of the same topology. This implies that the section (field data) on one
8576:     "makes sense" with respect to the topology and parallel decomposition of the other.
8577:     Loosely speaking, compatible DMs represent the same domain and parallel
8578:     decomposition, but hold different data.

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

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

8588:     Consider the operation of summing data living on a 2-dof DMDA to data living
8589:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8590: .vb
8591:   ...
8592:   DMGetCompatibility(da1,da2,&compatible,&set);
8593:   if (set && compatible)  {
8594:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8595:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8596:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8597:     for (j=y; j<y+n; ++j) {
8598:       for (i=x; i<x+m, ++i) {
8599:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8600:       }
8601:     }
8602:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8603:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8604:   } else {
8605:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8606:   }
8607:   ...
8608: .ve

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

8615:     A DM is always compatible with itself.

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

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

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

8634:     Level: advanced

8636: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8637: @*/

8639: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8640: {
8642:   PetscMPIInt    compareResult;
8643:   DMType         type,type2;
8644:   PetscBool      sameType;


8650:   /* Declare a DM compatible with itself */
8651:   if (dm1 == dm2) {
8652:     *set = PETSC_TRUE;
8653:     *compatible = PETSC_TRUE;
8654:     return(0);
8655:   }

8657:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8658:      communicator. Note that this does not preclude compatibility with
8659:      DMs living on "congruent" or "similar" communicators, but this must be
8660:      determined by the implementation-specific logic */
8661:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
8662:   if (compareResult == MPI_UNEQUAL) {
8663:     *set = PETSC_TRUE;
8664:     *compatible = PETSC_FALSE;
8665:     return(0);
8666:   }

8668:   /* Pass to the implementation-specific routine, if one exists. */
8669:   if (dm1->ops->getcompatibility) {
8670:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
8671:     if (*set) return(0);
8672:   }

8674:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8675:      with an implementation of this function from dm2 */
8676:   DMGetType(dm1,&type);
8677:   DMGetType(dm2,&type2);
8678:   PetscStrcmp(type,type2,&sameType);
8679:   if (!sameType && dm2->ops->getcompatibility) {
8680:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
8681:   } else {
8682:     *set = PETSC_FALSE;
8683:   }
8684:   return(0);
8685: }

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

8690:   Logically Collective on DM

8692:   Input Parameters:
8693: + DM - the DM
8694: . f - the monitor function
8695: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8696: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

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

8702:   Notes:
8703:   Several different monitoring routines may be set by calling
8704:   DMMonitorSet() multiple times; all will be called in the
8705:   order in which they were set.

8707:   Fortran Notes:
8708:   Only a single monitor function can be set for each DM object

8710:   Level: intermediate

8712: .seealso: DMMonitorCancel()
8713: @*/
8714: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8715: {
8716:   PetscInt       m;

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

8724:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8725:     if (identical) return(0);
8726:   }
8727:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8728:   dm->monitor[dm->numbermonitors]          = f;
8729:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8730:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8731:   return(0);
8732: }

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

8737:   Logically Collective on DM

8739:   Input Parameter:
8740: . dm - the DM

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

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

8750:   Level: intermediate

8752: .seealso: DMMonitorSet()
8753: @*/
8754: PetscErrorCode DMMonitorCancel(DM dm)
8755: {
8757:   PetscInt       m;

8761:   for (m = 0; m < dm->numbermonitors; ++m) {
8762:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
8763:   }
8764:   dm->numbermonitors = 0;
8765:   return(0);
8766: }

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

8771:   Collective on DM

8773:   Input Parameters:
8774: + dm   - DM object you wish to monitor
8775: . name - the monitor type one is seeking
8776: . help - message indicating what monitoring is done
8777: . manual - manual page for the monitor
8778: . monitor - the monitor function
8779: - 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

8781:   Output Parameter:
8782: . flg - Flag set if the monitor was created

8784:   Level: developer

8786: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8787:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8788:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8789:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8790:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8791:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8792:           PetscOptionsFList(), PetscOptionsEList()
8793: @*/
8794: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8795: {
8796:   PetscViewer       viewer;
8797:   PetscViewerFormat format;
8798:   PetscErrorCode    ierr;

8802:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
8803:   if (*flg) {
8804:     PetscViewerAndFormat *vf;

8806:     PetscViewerAndFormatCreate(viewer, format, &vf);
8807:     PetscObjectDereference((PetscObject) viewer);
8808:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
8809:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
8810:   }
8811:   return(0);
8812: }

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

8817:    Collective on DM

8819:    Input Parameters:
8820: .  dm - The DM

8822:    Level: developer

8824: .seealso: DMMonitorSet()
8825: @*/
8826: PetscErrorCode DMMonitor(DM dm)
8827: {
8828:   PetscInt       m;

8832:   if (!dm) return(0);
8834:   for (m = 0; m < dm->numbermonitors; ++m) {
8835:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8836:   }
8837:   return(0);
8838: }