Actual source code: dm.c

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

 10: #if defined(PETSC_HAVE_VALGRIND)
 11: #  include <valgrind/memcheck.h>
 12: #endif

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

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

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

 27:   Collective

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

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

 35:   Level: beginner

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

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

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

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

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

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

 97:   Collective

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

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

105:   Level: beginner

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

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

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

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

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

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

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

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

187:    Logically Collective on da

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

193:    Options Database:
194: .   -dm_vec_type ctype

196:    Level: intermediate

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

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

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

214:    Logically Collective on da

216:    Input Parameter:
217: .  da - initial distributed array

219:    Output Parameter:
220: .  ctype - the vector type

222:    Level: intermediate

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

234: /*@
235:   VecGetDM - Gets the DM defining the data layout of the vector

237:   Not collective

239:   Input Parameter:
240: . v - The Vec

242:   Output Parameter:
243: . dm - The DM

245:   Level: intermediate

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

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

260: /*@
261:   VecSetDM - Sets the DM defining the data layout of the vector.

263:   Not collective

265:   Input Parameters:
266: + v - The Vec
267: - dm - The DM

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

271:   Level: intermediate

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

282:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
283:   return(0);
284: }

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

289:    Logically Collective on dm

291:    Input Parameters:
292: +  dm - the DM context
293: -  ctype - the matrix type

295:    Options Database:
296: .   -dm_is_coloring_type - global or local

298:    Level: intermediate

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

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

314:    Logically Collective on dm

316:    Input Parameter:
317: .  dm - the DM context

319:    Output Parameter:
320: .  ctype - the matrix type

322:    Options Database:
323: .   -dm_is_coloring_type - global or local

325:    Level: intermediate

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

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

341:    Logically Collective on dm

343:    Input Parameters:
344: +  dm - the DM context
345: -  ctype - the matrix type

347:    Options Database:
348: .   -dm_mat_type ctype

350:    Level: intermediate

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

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

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

368:    Logically Collective on dm

370:    Input Parameter:
371: .  dm - the DM context

373:    Output Parameter:
374: .  ctype - the matrix type

376:    Options Database:
377: .   -dm_mat_type ctype

379:    Level: intermediate

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

391: /*@
392:   MatGetDM - Gets the DM defining the data layout of the matrix

394:   Not collective

396:   Input Parameter:
397: . A - The Mat

399:   Output Parameter:
400: . dm - The DM

402:   Level: intermediate

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

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

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

420: /*@
421:   MatSetDM - Sets the DM defining the data layout of the matrix

423:   Not collective

425:   Input Parameters:
426: + A - The Mat
427: - dm - The DM

429:   Level: intermediate

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


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

444:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
445:   return(0);
446: }

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

452:    Logically Collective on dm

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

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

462:    Level: advanced

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

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

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

486:    Logically Collective on dm

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

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

496:    Level: advanced

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

506:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
507:   return(0);
508: }

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

514:    Not Collective

516:    Input Parameters:
517: .  dm - the DM context

519:    Output Parameters:
520: .  prefix - pointer to the prefix string used is returned

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

526:    Level: advanced

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

536:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
537:   return(0);
538: }

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

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

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

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

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

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

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

589: /*@
590:     DMDestroy - Destroys a vector packer or DM.

592:     Collective on dm

594:     Input Parameter:
595: .   dm - the DM object to destroy

597:     Level: developer

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

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

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

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

619:   DMClearGlobalVectors(*dm);
620:   DMClearLocalVectors(*dm);

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

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

703:       next = b->next;
704:       PetscFree(b);
705:     }
706:   }

708:   PetscObjectDestroy(&(*dm)->dmksp);
709:   PetscObjectDestroy(&(*dm)->dmsnes);
710:   PetscObjectDestroy(&(*dm)->dmts);

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

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

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

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

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

767: /*@
768:     DMSetUp - sets up the data structures inside a DM object

770:     Collective on dm

772:     Input Parameter:
773: .   dm - the DM object to setup

775:     Level: developer

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

779: @*/
780: PetscErrorCode  DMSetUp(DM dm)
781: {

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

794: /*@
795:     DMSetFromOptions - sets parameters in a DM from the options database

797:     Collective on dm

799:     Input Parameter:
800: .   dm - the DM object to set options for

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

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

817:     Level: intermediate

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

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

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

854: /*@C
855:    DMViewFromOptions - View from Options

857:    Collective on DM

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

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

873:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
874:   return(0);
875: }

877: /*@C
878:     DMView - Views a DM

880:     Collective on dm

882:     Input Parameter:
883: +   dm - the DM object to view
884: -   v - the viewer

886:     Level: beginner

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

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

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

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

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

933: /*@
934:     DMCreateGlobalVector - Creates a global vector from a DM object

936:     Collective on dm

938:     Input Parameter:
939: .   dm - the DM object

941:     Output Parameter:
942: .   vec - the global vector

944:     Level: beginner

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

948: @*/
949: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
950: {

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

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

967: /*@
968:     DMCreateLocalVector - Creates a local vector from a DM object

970:     Not Collective

972:     Input Parameter:
973: .   dm - the DM object

975:     Output Parameter:
976: .   vec - the local vector

978:     Level: beginner

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

982: @*/
983: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
984: {

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

995:     VecGetDM(*vec,&vdm);
996:     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);
997:   }
998:   return(0);
999: }

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

1004:    Collective on dm

1006:    Input Parameter:
1007: .  dm - the DM that provides the mapping

1009:    Output Parameter:
1010: .  ltog - the mapping

1012:    Level: intermediate

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

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

1028:   if (!dm->ltogmap) {
1029:     PetscSection section, sectionGlobal;

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

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

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

1082: /*@
1083:    DMGetBlockSize - Gets the inherent block size associated with a DM

1085:    Not Collective

1087:    Input Parameter:
1088: .  dm - the DM with block structure

1090:    Output Parameter:
1091: .  bs - the block size, 1 implies no exploitable block structure

1093:    Level: intermediate

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

1107: /*@
1108:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1110:     Collective on dmc

1112:     Input Parameter:
1113: +   dmc - the DM object
1114: -   dmf - the second, finer DM object

1116:     Output Parameter:
1117: +  mat - the interpolation
1118: -  vec - the scaling (optional)

1120:     Level: developer

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

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


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

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

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

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

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

1156:   Output Parameter:
1157: .    scale - the scaled vector

1159:   Level: developer

1161: .seealso: DMCreateInterpolation()

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

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

1180: /*@
1181:     DMCreateRestriction - Gets restriction matrix between two DM objects

1183:     Collective on dmc

1185:     Input Parameter:
1186: +   dmc - the DM object
1187: -   dmf - the second, finer DM object

1189:     Output Parameter:
1190: .  mat - the restriction


1193:     Level: developer

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


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

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

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

1218: /*@
1219:     DMCreateInjection - Gets injection matrix between two DM objects

1221:     Collective on dac

1223:     Input Parameter:
1224: +   dac - the DM object
1225: -   daf - the second, finer DM object

1227:     Output Parameter:
1228: .   mat - the injection

1230:     Level: developer

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

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

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

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

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

1257:   Collective on dac

1259:   Input Parameter:
1260: + dac - the DM object
1261: - daf - the second, finer DM object

1263:   Output Parameter:
1264: . mat - the interpolation

1266:   Level: developer

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

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

1283: /*@
1284:     DMCreateColoring - Gets coloring for a DM

1286:     Collective on dm

1288:     Input Parameter:
1289: +   dm - the DM object
1290: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1292:     Output Parameter:
1293: .   coloring - the coloring

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

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

1301:     Level: developer

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

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

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

1318: /*@
1319:     DMCreateMatrix - Gets empty Jacobian for a DM

1321:     Collective on dm

1323:     Input Parameter:
1324: .   dm - the DM object

1326:     Output Parameter:
1327: .   mat - the empty Jacobian

1329:     Level: beginner

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

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

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

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

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

1346: @*/
1347: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1348: {

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

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

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

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

1394:   Logically Collective on dm

1396:   Input Parameter:
1397: + dm - the DM
1398: - only - PETSC_TRUE if only want preallocation

1400:   Level: developer
1401: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1402: @*/
1403: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1404: {
1407:   dm->prealloc_only = only;
1408:   return(0);
1409: }

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

1415:   Logically Collective on dm

1417:   Input Parameter:
1418: + dm - the DM
1419: - only - PETSC_TRUE if only want matrix stucture

1421:   Level: developer
1422: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1423: @*/
1424: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1425: {
1428:   dm->structure_only = only;
1429:   return(0);
1430: }

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

1435:   Not Collective

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

1442:   Output Parameter:
1443: . array - the work array

1445:   Level: developer

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

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

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

1483:   Not Collective

1485:   Input Parameters:
1486: + dm - the DM object
1487: . count - The minium size
1488: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1490:   Output Parameter:
1491: . array - the work array

1493:   Level: developer

1495:   Developer Notes:
1496:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1497: .seealso DMDestroy(), DMCreate()
1498: @*/
1499: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1500: {
1501:   DMWorkLink *p,link;

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

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

1521:   Logically collective on DM

1523:   Input Parameters:
1524: + dm     - The DM
1525: . field  - The field number for the nullspace
1526: - nullsp - A callback to create the nullspace

1528:   Notes:
1529:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1530: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1531: $ dm        - The present DM
1532: $ origField - The field number given above, in the original DM
1533: $ field     - The field number in dm
1534: $ nullSpace - The nullspace for the given field

1536:   This function is currently not available from Fortran.

1538: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1539: */
1540: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1541: {
1544:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1545:   dm->nullspaceConstructors[field] = nullsp;
1546:   return(0);
1547: }

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

1552:   Not collective

1554:   Input Parameters:
1555: + dm     - The DM
1556: - field  - The field number for the nullspace

1558:   Output Parameter:
1559: . nullsp - A callback to create the nullspace

1561:   Notes:
1562:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
1563: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1564: $ dm        - The present DM
1565: $ origField - The field number given above, in the original DM
1566: $ field     - The field number in dm
1567: $ nullSpace - The nullspace for the given field

1569:   This function is currently not available from Fortran.

1571: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1572: */
1573: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1574: {
1578:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1579:   *nullsp = dm->nullspaceConstructors[field];
1580:   return(0);
1581: }

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

1586:   Logically collective on DM

1588:   Input Parameters:
1589: + dm     - The DM
1590: . field  - The field number for the nullspace
1591: - nullsp - A callback to create the near-nullspace

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

1601:   This function is currently not available from Fortran.

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

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

1617:   Not collective

1619:   Input Parameters:
1620: + dm     - The DM
1621: - field  - The field number for the nullspace

1623:   Output Parameter:
1624: . nullsp - A callback to create the near-nullspace

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

1634:   This function is currently not available from Fortran.

1636: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1637: */
1638: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1639: {
1643:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1644:   *nullsp = dm->nearnullspaceConstructors[field];
1645:   return(0);
1646: }

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

1651:   Not collective

1653:   Input Parameter:
1654: . dm - the DM object

1656:   Output Parameters:
1657: + numFields  - The number of fields (or NULL if not requested)
1658: . fieldNames - The name for each field (or NULL if not requested)
1659: - fields     - The global indices for each field (or NULL if not requested)

1661:   Level: intermediate

1663:   Notes:
1664:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1665:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1666:   PetscFree().

1668: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1669: @*/
1670: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1671: {
1672:   PetscSection   section, sectionGlobal;

1677:   if (numFields) {
1679:     *numFields = 0;
1680:   }
1681:   if (fieldNames) {
1683:     *fieldNames = NULL;
1684:   }
1685:   if (fields) {
1687:     *fields = NULL;
1688:   }
1689:   DMGetLocalSection(dm, &section);
1690:   if (section) {
1691:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1692:     PetscInt nF, f, pStart, pEnd, p;

1694:     DMGetGlobalSection(dm, &sectionGlobal);
1695:     PetscSectionGetNumFields(section, &nF);
1696:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1697:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1698:     for (f = 0; f < nF; ++f) {
1699:       fieldSizes[f] = 0;
1700:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1701:     }
1702:     for (p = pStart; p < pEnd; ++p) {
1703:       PetscInt gdof;

1705:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1706:       if (gdof > 0) {
1707:         for (f = 0; f < nF; ++f) {
1708:           PetscInt fdof, fcdof, fpdof;

1710:           PetscSectionGetFieldDof(section, p, f, &fdof);
1711:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1712:           fpdof = fdof-fcdof;
1713:           if (fpdof && fpdof != fieldNc[f]) {
1714:             /* Layout does not admit a pointwise block size */
1715:             fieldNc[f] = 1;
1716:           }
1717:           fieldSizes[f] += fpdof;
1718:         }
1719:       }
1720:     }
1721:     for (f = 0; f < nF; ++f) {
1722:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1723:       fieldSizes[f] = 0;
1724:     }
1725:     for (p = pStart; p < pEnd; ++p) {
1726:       PetscInt gdof, goff;

1728:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1729:       if (gdof > 0) {
1730:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1731:         for (f = 0; f < nF; ++f) {
1732:           PetscInt fdof, fcdof, fc;

1734:           PetscSectionGetFieldDof(section, p, f, &fdof);
1735:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1736:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1737:             fieldIndices[f][fieldSizes[f]] = goff++;
1738:           }
1739:         }
1740:       }
1741:     }
1742:     if (numFields) *numFields = nF;
1743:     if (fieldNames) {
1744:       PetscMalloc1(nF, fieldNames);
1745:       for (f = 0; f < nF; ++f) {
1746:         const char *fieldName;

1748:         PetscSectionGetFieldName(section, f, &fieldName);
1749:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1750:       }
1751:     }
1752:     if (fields) {
1753:       PetscMalloc1(nF, fields);
1754:       for (f = 0; f < nF; ++f) {
1755:         PetscInt bs, in[2], out[2];

1757:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1758:         in[0] = -fieldNc[f];
1759:         in[1] = fieldNc[f];
1760:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1761:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1762:         ISSetBlockSize((*fields)[f], bs);
1763:       }
1764:     }
1765:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1766:   } else if (dm->ops->createfieldis) {
1767:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1768:   }
1769:   return(0);
1770: }


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

1779:   Not collective

1781:   Input Parameter:
1782: . dm - the DM object

1784:   Output Parameters:
1785: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1786: . namelist  - The name for each field (or NULL if not requested)
1787: . islist    - The global indices for each field (or NULL if not requested)
1788: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1790:   Level: intermediate

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

1797: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1798: @*/
1799: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1800: {

1805:   if (len) {
1807:     *len = 0;
1808:   }
1809:   if (namelist) {
1811:     *namelist = NULL;
1812:   }
1813:   if (islist) {
1815:     *islist = NULL;
1816:   }
1817:   if (dmlist) {
1819:     *dmlist = NULL;
1820:   }
1821:   /*
1822:    Is it a good idea to apply the following check across all impls?
1823:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1824:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1825:    */
1826:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1827:   if (!dm->ops->createfielddecomposition) {
1828:     PetscSection section;
1829:     PetscInt     numFields, f;

1831:     DMGetLocalSection(dm, &section);
1832:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1833:     if (section && numFields && dm->ops->createsubdm) {
1834:       if (len) *len = numFields;
1835:       if (namelist) {PetscMalloc1(numFields,namelist);}
1836:       if (islist)   {PetscMalloc1(numFields,islist);}
1837:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1838:       for (f = 0; f < numFields; ++f) {
1839:         const char *fieldName;

1841:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1842:         if (namelist) {
1843:           PetscSectionGetFieldName(section, f, &fieldName);
1844:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1845:         }
1846:       }
1847:     } else {
1848:       DMCreateFieldIS(dm, len, namelist, islist);
1849:       /* By default there are no DMs associated with subproblems. */
1850:       if (dmlist) *dmlist = NULL;
1851:     }
1852:   } else {
1853:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1854:   }
1855:   return(0);
1856: }

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

1862:   Not collective

1864:   Input Parameters:
1865: + dm        - The DM object
1866: . numFields - The number of fields in this subproblem
1867: - fields    - The field numbers of the selected fields

1869:   Output Parameters:
1870: + is - The global indices for the subproblem
1871: - subdm - The DM for the subproblem

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

1875:   Level: intermediate

1877: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1878: @*/
1879: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1880: {

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

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

1896:   Not collective

1898:   Input Parameter:
1899: + dms - The DM objects
1900: - len - The number of DMs

1902:   Output Parameters:
1903: + is - The global indices for the subproblem, or NULL
1904: - superdm - The DM for the superproblem

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

1908:   Level: intermediate

1910: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1911: @*/
1912: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1913: {
1914:   PetscInt       i;

1922:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1923:   if (len) {
1924:     DM dm = dms[0];
1925:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1926:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1927:   }
1928:   return(0);
1929: }


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

1939:   Not collective

1941:   Input Parameter:
1942: . dm - the DM object

1944:   Output Parameters:
1945: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1946: . namelist    - The name for each subdomain (or NULL if not requested)
1947: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1948: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1949: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1951:   Level: intermediate

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

1958: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
1959: @*/
1960: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1961: {
1962:   PetscErrorCode      ierr;
1963:   DMSubDomainHookLink link;
1964:   PetscInt            i,l;

1973:   /*
1974:    Is it a good idea to apply the following check across all impls?
1975:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1976:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1977:    */
1978:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1979:   if (dm->ops->createdomaindecomposition) {
1980:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1981:     /* copy subdomain hooks and context over to the subdomain DMs */
1982:     if (dmlist && *dmlist) {
1983:       for (i = 0; i < l; i++) {
1984:         for (link=dm->subdomainhook; link; link=link->next) {
1985:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1986:         }
1987:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1988:       }
1989:     }
1990:     if (len) *len = l;
1991:   }
1992:   return(0);
1993: }


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

1999:   Not collective

2001:   Input Parameters:
2002: + dm - the DM object
2003: . n  - the number of subdomain scatters
2004: - subdms - the local subdomains

2006:   Output Parameters:
2007: + n     - the number of scatters returned
2008: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2009: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2010: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

2018:   Level: developer

2020: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2021: @*/
2022: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2023: {

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

2034: /*@
2035:   DMRefine - Refines a DM object

2037:   Collective on dm

2039:   Input Parameter:
2040: + dm   - the DM object
2041: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2043:   Output Parameter:
2044: . dmf - the refined DM, or NULL

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

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

2051:   Level: developer

2053: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2054: @*/
2055: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2056: {
2057:   PetscErrorCode   ierr;
2058:   DMRefineHookLink link;

2062:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
2063:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
2064:   (*dm->ops->refine)(dm,comm,dmf);
2065:   if (*dmf) {
2066:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2070:     (*dmf)->ctx       = dm->ctx;
2071:     (*dmf)->leveldown = dm->leveldown;
2072:     (*dmf)->levelup   = dm->levelup + 1;

2074:     DMSetMatType(*dmf,dm->mattype);
2075:     for (link=dm->refinehook; link; link=link->next) {
2076:       if (link->refinehook) {
2077:         (*link->refinehook)(dm,*dmf,link->ctx);
2078:       }
2079:     }
2080:   }
2081:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2082:   return(0);
2083: }

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

2088:    Logically Collective

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

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

2099: +  coarse - coarse level DM
2100: .  fine - fine level DM to interpolate problem to
2101: -  ctx - optional user-defined function context

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

2106: +  coarse - coarse level DM
2107: .  interp - matrix interpolating a coarse-level solution to the finer grid
2108: .  fine - fine level DM to update
2109: -  ctx - optional user-defined function context

2111:    Level: advanced

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

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

2118:    This function is currently not available from Fortran.

2120: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2121: @*/
2122: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2123: {
2124:   PetscErrorCode   ierr;
2125:   DMRefineHookLink link,*p;

2129:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2130:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
2131:   }
2132:   PetscNew(&link);
2133:   link->refinehook = refinehook;
2134:   link->interphook = interphook;
2135:   link->ctx        = ctx;
2136:   link->next       = NULL;
2137:   *p               = link;
2138:   return(0);
2139: }

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

2144:    Logically Collective

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

2152:    Level: advanced

2154:    Notes:
2155:    This function does nothing if the hook is not in the list.

2157:    This function is currently not available from Fortran.

2159: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2160: @*/
2161: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2162: {
2163:   PetscErrorCode   ierr;
2164:   DMRefineHookLink link,*p;

2168:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2169:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2170:       link = *p;
2171:       *p = link->next;
2172:       PetscFree(link);
2173:       break;
2174:     }
2175:   }
2176:   return(0);
2177: }

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

2182:    Collective if any hooks are

2184:    Input Arguments:
2185: +  coarse - coarser DM to use as a base
2186: .  interp - interpolation matrix, apply using MatInterpolate()
2187: -  fine - finer DM to update

2189:    Level: developer

2191: .seealso: DMRefineHookAdd(), MatInterpolate()
2192: @*/
2193: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2194: {
2195:   PetscErrorCode   ierr;
2196:   DMRefineHookLink link;

2199:   for (link=fine->refinehook; link; link=link->next) {
2200:     if (link->interphook) {
2201:       (*link->interphook)(coarse,interp,fine,link->ctx);
2202:     }
2203:   }
2204:   return(0);
2205: }

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

2210:     Not Collective

2212:     Input Parameter:
2213: .   dm - the DM object

2215:     Output Parameter:
2216: .   level - number of refinements

2218:     Level: developer

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

2222: @*/
2223: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2224: {
2227:   *level = dm->levelup;
2228:   return(0);
2229: }

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

2234:     Not Collective

2236:     Input Parameter:
2237: +   dm - the DM object
2238: -   level - number of refinements

2240:     Level: advanced

2242:     Notes:
2243:     This value is used by PCMG to determine how many multigrid levels to use

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

2247: @*/
2248: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2249: {
2252:   dm->levelup = level;
2253:   return(0);
2254: }

2256: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2257: {
2261:   *tdm = dm->transformDM;
2262:   return(0);
2263: }

2265: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2266: {
2270:   *tv = dm->transform;
2271:   return(0);
2272: }

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

2277:   Input Parameter:
2278: . dm - The DM

2280:   Output Parameter:
2281: . flg - PETSC_TRUE if a basis transformation should be done

2283:   Level: developer

2285: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2286: @*/
2287: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2288: {
2289:   Vec            tv;

2295:   DMGetBasisTransformVec_Internal(dm, &tv);
2296:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2297:   return(0);
2298: }

2300: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2301: {
2302:   PetscSection   s, ts;
2303:   PetscScalar   *ta;
2304:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2308:   DMGetCoordinateDim(dm, &cdim);
2309:   DMGetLocalSection(dm, &s);
2310:   PetscSectionGetChart(s, &pStart, &pEnd);
2311:   PetscSectionGetNumFields(s, &Nf);
2312:   DMClone(dm, &dm->transformDM);
2313:   DMGetLocalSection(dm->transformDM, &ts);
2314:   PetscSectionSetNumFields(ts, Nf);
2315:   PetscSectionSetChart(ts, pStart, pEnd);
2316:   for (f = 0; f < Nf; ++f) {
2317:     PetscSectionGetFieldComponents(s, f, &Nc);
2318:     /* We could start to label fields by their transformation properties */
2319:     if (Nc != cdim) continue;
2320:     for (p = pStart; p < pEnd; ++p) {
2321:       PetscSectionGetFieldDof(s, p, f, &dof);
2322:       if (!dof) continue;
2323:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2324:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2325:     }
2326:   }
2327:   PetscSectionSetUp(ts);
2328:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2329:   VecGetArray(dm->transform, &ta);
2330:   for (p = pStart; p < pEnd; ++p) {
2331:     for (f = 0; f < Nf; ++f) {
2332:       PetscSectionGetFieldDof(ts, p, f, &dof);
2333:       if (dof) {
2334:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2335:         PetscScalar       *tva;
2336:         const PetscScalar *A;

2338:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2339:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2340:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2341:         PetscArraycpy(tva, A, PetscSqr(cdim));
2342:       }
2343:     }
2344:   }
2345:   VecRestoreArray(dm->transform, &ta);
2346:   return(0);
2347: }

2349: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2350: {

2356:   newdm->transformCtx       = dm->transformCtx;
2357:   newdm->transformSetUp     = dm->transformSetUp;
2358:   newdm->transformDestroy   = NULL;
2359:   newdm->transformGetMatrix = dm->transformGetMatrix;
2360:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2361:   return(0);
2362: }

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

2367:    Logically Collective

2369:    Input Arguments:
2370: +  dm - the DM
2371: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2372: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2373: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2378: +  dm - global DM
2379: .  g - global vector
2380: .  mode - mode
2381: .  l - local vector
2382: -  ctx - optional user-defined function context


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

2388: +  global - global DM
2389: -  ctx - optional user-defined function context

2391:    Level: advanced

2393: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2394: @*/
2395: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2396: {
2397:   PetscErrorCode          ierr;
2398:   DMGlobalToLocalHookLink link,*p;

2402:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2403:   PetscNew(&link);
2404:   link->beginhook = beginhook;
2405:   link->endhook   = endhook;
2406:   link->ctx       = ctx;
2407:   link->next      = NULL;
2408:   *p              = link;
2409:   return(0);
2410: }

2412: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2413: {
2414:   Mat cMat;
2415:   Vec cVec;
2416:   PetscSection section, cSec;
2417:   PetscInt pStart, pEnd, p, dof;

2422:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2423:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2424:     PetscInt nRows;

2426:     MatGetSize(cMat,&nRows,NULL);
2427:     if (nRows <= 0) return(0);
2428:     DMGetLocalSection(dm,&section);
2429:     MatCreateVecs(cMat,NULL,&cVec);
2430:     MatMult(cMat,l,cVec);
2431:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2432:     for (p = pStart; p < pEnd; p++) {
2433:       PetscSectionGetDof(cSec,p,&dof);
2434:       if (dof) {
2435:         PetscScalar *vals;
2436:         VecGetValuesSection(cVec,cSec,p,&vals);
2437:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2438:       }
2439:     }
2440:     VecDestroy(&cVec);
2441:   }
2442:   return(0);
2443: }

2445: /*@
2446:     DMGlobalToLocal - update local vectors from global vector

2448:     Neighbor-wise Collective on dm

2450:     Input Parameters:
2451: +   dm - the DM object
2452: .   g - the global vector
2453: .   mode - INSERT_VALUES or ADD_VALUES
2454: -   l - the local vector

2456:     Notes:
2457:     The communication involved in this update can be overlapped with computation by using
2458:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2460:     Level: beginner

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

2464: @*/
2465: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2466: {

2470:   DMGlobalToLocalBegin(dm,g,mode,l);
2471:   DMGlobalToLocalEnd(dm,g,mode,l);
2472:   return(0);
2473: }

2475: /*@
2476:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2478:     Neighbor-wise Collective on dm

2480:     Input Parameters:
2481: +   dm - the DM object
2482: .   g - the global vector
2483: .   mode - INSERT_VALUES or ADD_VALUES
2484: -   l - the local vector

2486:     Level: intermediate

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

2490: @*/
2491: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2492: {
2493:   PetscSF                 sf;
2494:   PetscErrorCode          ierr;
2495:   DMGlobalToLocalHookLink link;


2500:   for (link=dm->gtolhook; link; link=link->next) {
2501:     if (link->beginhook) {
2502:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2503:     }
2504:   }
2505:   DMGetSectionSF(dm, &sf);
2506:   if (sf) {
2507:     const PetscScalar *gArray;
2508:     PetscScalar       *lArray;
2509:     PetscMemType      lmtype,gmtype;

2511:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2512:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2513:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2514:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray);
2515:     VecRestoreArrayAndMemType(l, &lArray);
2516:     VecRestoreArrayReadAndMemType(g, &gArray);
2517:   } else {
2518:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2519:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2520:   }
2521:   return(0);
2522: }

2524: /*@
2525:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2527:     Neighbor-wise Collective on dm

2529:     Input Parameters:
2530: +   dm - the DM object
2531: .   g - the global vector
2532: .   mode - INSERT_VALUES or ADD_VALUES
2533: -   l - the local vector

2535:     Level: intermediate

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

2539: @*/
2540: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2541: {
2542:   PetscSF                 sf;
2543:   PetscErrorCode          ierr;
2544:   const PetscScalar      *gArray;
2545:   PetscScalar            *lArray;
2546:   PetscBool               transform;
2547:   DMGlobalToLocalHookLink link;
2548:   PetscMemType            lmtype,gmtype;

2552:   DMGetSectionSF(dm, &sf);
2553:   DMHasBasisTransform(dm, &transform);
2554:   if (sf) {
2555:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2557:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2558:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2559:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2560:     VecRestoreArrayAndMemType(l, &lArray);
2561:     VecRestoreArrayReadAndMemType(g, &gArray);
2562:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2563:   } else {
2564:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2565:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2566:   }
2567:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2568:   for (link=dm->gtolhook; link; link=link->next) {
2569:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2570:   }
2571:   return(0);
2572: }

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

2577:    Logically Collective

2579:    Input Arguments:
2580: +  dm - the DM
2581: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2582: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2583: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2588: +  dm - global DM
2589: .  l - local vector
2590: .  mode - mode
2591: .  g - global vector
2592: -  ctx - optional user-defined function context


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

2598: +  global - global DM
2599: .  l - local vector
2600: .  mode - mode
2601: .  g - global vector
2602: -  ctx - optional user-defined function context

2604:    Level: advanced

2606: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2607: @*/
2608: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2609: {
2610:   PetscErrorCode          ierr;
2611:   DMLocalToGlobalHookLink link,*p;

2615:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2616:   PetscNew(&link);
2617:   link->beginhook = beginhook;
2618:   link->endhook   = endhook;
2619:   link->ctx       = ctx;
2620:   link->next      = NULL;
2621:   *p              = link;
2622:   return(0);
2623: }

2625: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2626: {
2627:   Mat cMat;
2628:   Vec cVec;
2629:   PetscSection section, cSec;
2630:   PetscInt pStart, pEnd, p, dof;

2635:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2636:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2637:     PetscInt nRows;

2639:     MatGetSize(cMat,&nRows,NULL);
2640:     if (nRows <= 0) return(0);
2641:     DMGetLocalSection(dm,&section);
2642:     MatCreateVecs(cMat,NULL,&cVec);
2643:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2644:     for (p = pStart; p < pEnd; p++) {
2645:       PetscSectionGetDof(cSec,p,&dof);
2646:       if (dof) {
2647:         PetscInt d;
2648:         PetscScalar *vals;
2649:         VecGetValuesSection(l,section,p,&vals);
2650:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2651:         /* for this to be the true transpose, we have to zero the values that
2652:          * we just extracted */
2653:         for (d = 0; d < dof; d++) {
2654:           vals[d] = 0.;
2655:         }
2656:       }
2657:     }
2658:     MatMultTransposeAdd(cMat,cVec,l,l);
2659:     VecDestroy(&cVec);
2660:   }
2661:   return(0);
2662: }
2663: /*@
2664:     DMLocalToGlobal - updates global vectors from local vectors

2666:     Neighbor-wise Collective on dm

2668:     Input Parameters:
2669: +   dm - the DM object
2670: .   l - the local vector
2671: .   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.
2672: -   g - the global vector

2674:     Notes:
2675:     The communication involved in this update can be overlapped with computation by using
2676:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2681:     Level: beginner

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

2685: @*/
2686: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2687: {

2691:   DMLocalToGlobalBegin(dm,l,mode,g);
2692:   DMLocalToGlobalEnd(dm,l,mode,g);
2693:   return(0);
2694: }

2696: /*@
2697:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2699:     Neighbor-wise Collective on dm

2701:     Input Parameters:
2702: +   dm - the DM object
2703: .   l - the local vector
2704: .   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.
2705: -   g - the global vector

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

2711:     Level: intermediate

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

2715: @*/
2716: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2717: {
2718:   PetscSF                 sf;
2719:   PetscSection            s, gs;
2720:   DMLocalToGlobalHookLink link;
2721:   Vec                     tmpl;
2722:   const PetscScalar      *lArray;
2723:   PetscScalar            *gArray;
2724:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2725:   PetscErrorCode          ierr;
2726:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

2730:   for (link=dm->ltoghook; link; link=link->next) {
2731:     if (link->beginhook) {
2732:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2733:     }
2734:   }
2735:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2736:   DMGetSectionSF(dm, &sf);
2737:   DMGetLocalSection(dm, &s);
2738:   switch (mode) {
2739:   case INSERT_VALUES:
2740:   case INSERT_ALL_VALUES:
2741:   case INSERT_BC_VALUES:
2742:     isInsert = PETSC_TRUE; break;
2743:   case ADD_VALUES:
2744:   case ADD_ALL_VALUES:
2745:   case ADD_BC_VALUES:
2746:     isInsert = PETSC_FALSE; break;
2747:   default:
2748:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2749:   }
2750:   if ((sf && !isInsert) || (s && isInsert)) {
2751:     DMHasBasisTransform(dm, &transform);
2752:     if (transform) {
2753:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2754:       VecCopy(l, tmpl);
2755:       DMPlexLocalToGlobalBasis(dm, tmpl);
2756:       VecGetArrayRead(tmpl, &lArray);
2757:     } else if (isInsert) {
2758:       VecGetArrayRead(l, &lArray);
2759:     } else {
2760:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2761:       l_inplace = PETSC_TRUE;
2762:     }
2763:     if (s && isInsert) {
2764:       VecGetArray(g, &gArray);
2765:     } else {
2766:       VecGetArrayAndMemType(g, &gArray, &gmtype);
2767:       g_inplace = PETSC_TRUE;
2768:     }
2769:     if (sf && !isInsert) {
2770:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2771:     } else if (s && isInsert) {
2772:       PetscInt gStart, pStart, pEnd, p;

2774:       DMGetGlobalSection(dm, &gs);
2775:       PetscSectionGetChart(s, &pStart, &pEnd);
2776:       VecGetOwnershipRange(g, &gStart, NULL);
2777:       for (p = pStart; p < pEnd; ++p) {
2778:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2780:         PetscSectionGetDof(s, p, &dof);
2781:         PetscSectionGetDof(gs, p, &gdof);
2782:         PetscSectionGetConstraintDof(s, p, &cdof);
2783:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2784:         PetscSectionGetOffset(s, p, &off);
2785:         PetscSectionGetOffset(gs, p, &goff);
2786:         /* Ignore off-process data and points with no global data */
2787:         if (!gdof || goff < 0) continue;
2788:         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);
2789:         /* If no constraints are enforced in the global vector */
2790:         if (!gcdof) {
2791:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2792:           /* If constraints are enforced in the global vector */
2793:         } else if (cdof == gcdof) {
2794:           const PetscInt *cdofs;
2795:           PetscInt        cind = 0;

2797:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2798:           for (d = 0, e = 0; d < dof; ++d) {
2799:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2800:             gArray[goff-gStart+e++] = lArray[off+d];
2801:           }
2802:         } 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);
2803:       }
2804:     }
2805:     if (g_inplace) {
2806:       VecRestoreArrayAndMemType(g, &gArray);
2807:     } else {
2808:       VecRestoreArray(g, &gArray);
2809:     }
2810:     if (transform) {
2811:       VecRestoreArrayRead(tmpl, &lArray);
2812:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2813:     } else if (l_inplace) {
2814:       VecRestoreArrayReadAndMemType(l, &lArray);
2815:     } else {
2816:       VecRestoreArrayRead(l, &lArray);
2817:     }
2818:   } else {
2819:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2820:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2821:   }
2822:   return(0);
2823: }

2825: /*@
2826:     DMLocalToGlobalEnd - updates global vectors from local vectors

2828:     Neighbor-wise Collective on dm

2830:     Input Parameters:
2831: +   dm - the DM object
2832: .   l - the local vector
2833: .   mode - INSERT_VALUES or ADD_VALUES
2834: -   g - the global vector

2836:     Level: intermediate

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

2840: @*/
2841: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2842: {
2843:   PetscSF                 sf;
2844:   PetscSection            s;
2845:   DMLocalToGlobalHookLink link;
2846:   PetscBool               isInsert, transform;
2847:   PetscErrorCode          ierr;

2851:   DMGetSectionSF(dm, &sf);
2852:   DMGetLocalSection(dm, &s);
2853:   switch (mode) {
2854:   case INSERT_VALUES:
2855:   case INSERT_ALL_VALUES:
2856:     isInsert = PETSC_TRUE; break;
2857:   case ADD_VALUES:
2858:   case ADD_ALL_VALUES:
2859:     isInsert = PETSC_FALSE; break;
2860:   default:
2861:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2862:   }
2863:   if (sf && !isInsert) {
2864:     const PetscScalar *lArray;
2865:     PetscScalar       *gArray;
2866:     Vec                tmpl;

2868:     DMHasBasisTransform(dm, &transform);
2869:     if (transform) {
2870:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2871:       VecGetArrayRead(tmpl, &lArray);
2872:     } else {
2873:       VecGetArrayReadAndMemType(l, &lArray, NULL);
2874:     }
2875:     VecGetArrayAndMemType(g, &gArray, NULL);
2876:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2877:     if (transform) {
2878:       VecRestoreArrayRead(tmpl, &lArray);
2879:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2880:     } else {
2881:       VecRestoreArrayReadAndMemType(l, &lArray);
2882:     }
2883:     VecRestoreArrayAndMemType(g, &gArray);
2884:   } else if (s && isInsert) {
2885:   } else {
2886:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2887:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2888:   }
2889:   for (link=dm->ltoghook; link; link=link->next) {
2890:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2891:   }
2892:   return(0);
2893: }

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

2900:    Neighbor-wise Collective on dm

2902:    Input Parameters:
2903: +  dm - the DM object
2904: .  g - the original local vector
2905: -  mode - one of INSERT_VALUES or ADD_VALUES

2907:    Output Parameter:
2908: .  l  - the local vector with correct ghost values

2910:    Level: intermediate

2912:    Notes:
2913:    The local vectors used here need not be the same as those
2914:    obtained from DMCreateLocalVector(), BUT they
2915:    must have the same parallel data layout; they could, for example, be
2916:    obtained with VecDuplicate() from the DM originating vectors.

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

2920: @*/
2921: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2922: {
2923:   PetscErrorCode          ierr;

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

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

2937:    Neighbor-wise Collective on dm

2939:    Input Parameters:
2940: +  da - the DM object
2941: .  g - the original local vector
2942: -  mode - one of INSERT_VALUES or ADD_VALUES

2944:    Output Parameter:
2945: .  l  - the local vector with correct ghost values

2947:    Level: intermediate

2949:    Notes:
2950:    The local vectors used here need not be the same as those
2951:    obtained from DMCreateLocalVector(), BUT they
2952:    must have the same parallel data layout; they could, for example, be
2953:    obtained with VecDuplicate() from the DM originating vectors.

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

2957: @*/
2958: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2959: {
2960:   PetscErrorCode          ierr;

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


2970: /*@
2971:     DMCoarsen - Coarsens a DM object

2973:     Collective on dm

2975:     Input Parameter:
2976: +   dm - the DM object
2977: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2979:     Output Parameter:
2980: .   dmc - the coarsened DM

2982:     Level: developer

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

2986: @*/
2987: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2988: {
2989:   PetscErrorCode    ierr;
2990:   DMCoarsenHookLink link;

2994:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
2995:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2996:   (*dm->ops->coarsen)(dm, comm, dmc);
2997:   if (*dmc) {
2998:     DMSetCoarseDM(dm,*dmc);
2999:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3000:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3001:     (*dmc)->ctx               = dm->ctx;
3002:     (*dmc)->levelup           = dm->levelup;
3003:     (*dmc)->leveldown         = dm->leveldown + 1;
3004:     DMSetMatType(*dmc,dm->mattype);
3005:     for (link=dm->coarsenhook; link; link=link->next) {
3006:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
3007:     }
3008:   }
3009:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3010:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3011:   return(0);
3012: }

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

3017:    Logically Collective

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

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

3028: +  fine - fine level DM
3029: .  coarse - coarse level DM to restrict problem to
3030: -  ctx - optional user-defined function context

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

3035: +  fine - fine level DM
3036: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
3037: .  rscale - scaling vector for restriction
3038: .  inject - matrix restricting by injection
3039: .  coarse - coarse level DM to update
3040: -  ctx - optional user-defined function context

3042:    Level: advanced

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

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

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

3052:    This function is currently not available from Fortran.

3054: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3055: @*/
3056: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3057: {
3058:   PetscErrorCode    ierr;
3059:   DMCoarsenHookLink link,*p;

3063:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3064:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3065:   }
3066:   PetscNew(&link);
3067:   link->coarsenhook  = coarsenhook;
3068:   link->restricthook = restricthook;
3069:   link->ctx          = ctx;
3070:   link->next         = NULL;
3071:   *p                 = link;
3072:   return(0);
3073: }

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

3078:    Logically Collective

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

3086:    Level: advanced

3088:    Notes:
3089:    This function does nothing if the hook is not in the list.

3091:    This function is currently not available from Fortran.

3093: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3094: @*/
3095: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3096: {
3097:   PetscErrorCode    ierr;
3098:   DMCoarsenHookLink link,*p;

3102:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3103:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3104:       link = *p;
3105:       *p = link->next;
3106:       PetscFree(link);
3107:       break;
3108:     }
3109:   }
3110:   return(0);
3111: }


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

3117:    Collective if any hooks are

3119:    Input Arguments:
3120: +  fine - finer DM to use as a base
3121: .  restrct - restriction matrix, apply using MatRestrict()
3122: .  rscale - scaling vector for restriction
3123: .  inject - injection matrix, also use MatRestrict()
3124: -  coarse - coarser DM to update

3126:    Level: developer

3128: .seealso: DMCoarsenHookAdd(), MatRestrict()
3129: @*/
3130: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3131: {
3132:   PetscErrorCode    ierr;
3133:   DMCoarsenHookLink link;

3136:   for (link=fine->coarsenhook; link; link=link->next) {
3137:     if (link->restricthook) {
3138:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3139:     }
3140:   }
3141:   return(0);
3142: }

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

3147:    Logically Collective on global

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


3156:    Calling sequence for ddhook:
3157: $    ddhook(DM global,DM block,void *ctx)

3159: +  global - global DM
3160: .  block  - block DM
3161: -  ctx - optional user-defined function context

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

3166: +  global - global DM
3167: .  out    - scatter to the outer (with ghost and overlap points) block vector
3168: .  in     - scatter to block vector values only owned locally
3169: .  block  - block DM
3170: -  ctx - optional user-defined function context

3172:    Level: advanced

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

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

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

3182:    This function is currently not available from Fortran.

3184: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3185: @*/
3186: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3187: {
3188:   PetscErrorCode      ierr;
3189:   DMSubDomainHookLink link,*p;

3193:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3194:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3195:   }
3196:   PetscNew(&link);
3197:   link->restricthook = restricthook;
3198:   link->ddhook       = ddhook;
3199:   link->ctx          = ctx;
3200:   link->next         = NULL;
3201:   *p                 = link;
3202:   return(0);
3203: }

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

3208:    Logically Collective

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

3216:    Level: advanced

3218:    Notes:

3220:    This function is currently not available from Fortran.

3222: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3223: @*/
3224: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3225: {
3226:   PetscErrorCode      ierr;
3227:   DMSubDomainHookLink link,*p;

3231:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3232:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3233:       link = *p;
3234:       *p = link->next;
3235:       PetscFree(link);
3236:       break;
3237:     }
3238:   }
3239:   return(0);
3240: }

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

3245:    Collective if any hooks are

3247:    Input Arguments:
3248: +  fine - finer DM to use as a base
3249: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3250: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3251: -  coarse - coarer DM to update

3253:    Level: developer

3255: .seealso: DMCoarsenHookAdd(), MatRestrict()
3256: @*/
3257: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3258: {
3259:   PetscErrorCode      ierr;
3260:   DMSubDomainHookLink link;

3263:   for (link=global->subdomainhook; link; link=link->next) {
3264:     if (link->restricthook) {
3265:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3266:     }
3267:   }
3268:   return(0);
3269: }

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

3274:     Not Collective

3276:     Input Parameter:
3277: .   dm - the DM object

3279:     Output Parameter:
3280: .   level - number of coarsenings

3282:     Level: developer

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

3286: @*/
3287: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3288: {
3292:   *level = dm->leveldown;
3293:   return(0);
3294: }

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

3299:     Not Collective

3301:     Input Parameters:
3302: +   dm - the DM object
3303: -   level - number of coarsenings

3305:     Level: developer

3307: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3308: @*/
3309: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3310: {
3313:   dm->leveldown = level;
3314:   return(0);
3315: }



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

3322:     Collective on dm

3324:     Input Parameter:
3325: +   dm - the DM object
3326: -   nlevels - the number of levels of refinement

3328:     Output Parameter:
3329: .   dmf - the refined DM hierarchy

3331:     Level: developer

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

3335: @*/
3336: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3337: {

3342:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3343:   if (nlevels == 0) return(0);
3345:   if (dm->ops->refinehierarchy) {
3346:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3347:   } else if (dm->ops->refine) {
3348:     PetscInt i;

3350:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3351:     for (i=1; i<nlevels; i++) {
3352:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3353:     }
3354:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3355:   return(0);
3356: }

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

3361:     Collective on dm

3363:     Input Parameter:
3364: +   dm - the DM object
3365: -   nlevels - the number of levels of coarsening

3367:     Output Parameter:
3368: .   dmc - the coarsened DM hierarchy

3370:     Level: developer

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

3374: @*/
3375: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3376: {

3381:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3382:   if (nlevels == 0) return(0);
3384:   if (dm->ops->coarsenhierarchy) {
3385:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3386:   } else if (dm->ops->coarsen) {
3387:     PetscInt i;

3389:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3390:     for (i=1; i<nlevels; i++) {
3391:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3392:     }
3393:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3394:   return(0);
3395: }

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

3400:     Not Collective

3402:     Input Parameters:
3403: +   dm - the DM object
3404: -   destroy - the destroy function

3406:     Level: intermediate

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

3410: @*/
3411: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3412: {
3415:   dm->ctxdestroy = destroy;
3416:   return(0);
3417: }

3419: /*@
3420:     DMSetApplicationContext - Set a user context into a DM object

3422:     Not Collective

3424:     Input Parameters:
3425: +   dm - the DM object
3426: -   ctx - the user context

3428:     Level: intermediate

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

3432: @*/
3433: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3434: {
3437:   dm->ctx = ctx;
3438:   return(0);
3439: }

3441: /*@
3442:     DMGetApplicationContext - Gets a user context from a DM object

3444:     Not Collective

3446:     Input Parameter:
3447: .   dm - the DM object

3449:     Output Parameter:
3450: .   ctx - the user context

3452:     Level: intermediate

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

3456: @*/
3457: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3458: {
3461:   *(void**)ctx = dm->ctx;
3462:   return(0);
3463: }

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

3468:     Logically Collective on dm

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

3474:     Level: intermediate

3476: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3477:          DMSetJacobian()

3479: @*/
3480: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3481: {
3484:   dm->ops->computevariablebounds = f;
3485:   return(0);
3486: }

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

3491:     Not Collective

3493:     Input Parameter:
3494: .   dm - the DM object to destroy

3496:     Output Parameter:
3497: .   flg - PETSC_TRUE if the variable bounds function exists

3499:     Level: developer

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

3503: @*/
3504: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3505: {
3509:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3510:   return(0);
3511: }

3513: /*@C
3514:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3516:     Logically Collective on dm

3518:     Input Parameters:
3519: .   dm - the DM object

3521:     Output parameters:
3522: +   xl - lower bound
3523: -   xu - upper bound

3525:     Level: advanced

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

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

3532: @*/
3533: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3534: {

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

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

3549:     Not Collective

3551:     Input Parameter:
3552: .   dm - the DM object

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

3557:     Level: developer

3559: .seealso DMCreateColoring()

3561: @*/
3562: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3563: {
3567:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3568:   return(0);
3569: }

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

3574:     Not Collective

3576:     Input Parameter:
3577: .   dm - the DM object

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

3582:     Level: developer

3584: .seealso DMCreateRestriction()

3586: @*/
3587: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3588: {
3592:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3593:   return(0);
3594: }


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

3600:     Not Collective

3602:     Input Parameter:
3603: .   dm - the DM object

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

3608:     Level: developer

3610: .seealso DMCreateInjection()

3612: @*/
3613: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3614: {

3620:   if (dm->ops->hascreateinjection) {
3621:     (*dm->ops->hascreateinjection)(dm,flg);
3622:   } else {
3623:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3624:   }
3625:   return(0);
3626: }

3628: PetscFunctionList DMList              = NULL;
3629: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3631: /*@C
3632:   DMSetType - Builds a DM, for a particular DM implementation.

3634:   Collective on dm

3636:   Input Parameters:
3637: + dm     - The DM object
3638: - method - The name of the DM type

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

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

3646:   Level: intermediate

3648: .seealso: DMGetType(), DMCreate()
3649: @*/
3650: PetscErrorCode  DMSetType(DM dm, DMType method)
3651: {
3652:   PetscErrorCode (*r)(DM);
3653:   PetscBool      match;

3658:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3659:   if (match) return(0);

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

3665:   if (dm->ops->destroy) {
3666:     (*dm->ops->destroy)(dm);
3667:   }
3668:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3669:   PetscObjectChangeTypeName((PetscObject)dm,method);
3670:   (*r)(dm);
3671:   return(0);
3672: }

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

3677:   Not Collective

3679:   Input Parameter:
3680: . dm  - The DM

3682:   Output Parameter:
3683: . type - The DM type name

3685:   Level: intermediate

3687: .seealso: DMSetType(), DMCreate()
3688: @*/
3689: PetscErrorCode  DMGetType(DM dm, DMType *type)
3690: {

3696:   DMRegisterAll();
3697:   *type = ((PetscObject)dm)->type_name;
3698:   return(0);
3699: }

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

3704:   Collective on dm

3706:   Input Parameters:
3707: + dm - the DM
3708: - newtype - new DM type (use "same" for the same type)

3710:   Output Parameter:
3711: . M - pointer to new DM

3713:   Notes:
3714:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3715:   the MPI communicator of the generated DM is always the same as the communicator
3716:   of the input DM.

3718:   Level: intermediate

3720: .seealso: DMCreate()
3721: @*/
3722: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3723: {
3724:   DM             B;
3725:   char           convname[256];
3726:   PetscBool      sametype/*, issame */;

3733:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3734:   /* PetscStrcmp(newtype, "same", &issame); */
3735:   if (sametype) {
3736:     *M   = dm;
3737:     PetscObjectReference((PetscObject) dm);
3738:     return(0);
3739:   } else {
3740:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3742:     /*
3743:        Order of precedence:
3744:        1) See if a specialized converter is known to the current DM.
3745:        2) See if a specialized converter is known to the desired DM class.
3746:        3) See if a good general converter is registered for the desired class
3747:        4) See if a good general converter is known for the current matrix.
3748:        5) Use a really basic converter.
3749:     */

3751:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3752:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3753:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3754:     PetscStrlcat(convname,"_",sizeof(convname));
3755:     PetscStrlcat(convname,newtype,sizeof(convname));
3756:     PetscStrlcat(convname,"_C",sizeof(convname));
3757:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3758:     if (conv) goto foundconv;

3760:     /* 2)  See if a specialized converter is known to the desired DM class. */
3761:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3762:     DMSetType(B, newtype);
3763:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3764:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3765:     PetscStrlcat(convname,"_",sizeof(convname));
3766:     PetscStrlcat(convname,newtype,sizeof(convname));
3767:     PetscStrlcat(convname,"_C",sizeof(convname));
3768:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3769:     if (conv) {
3770:       DMDestroy(&B);
3771:       goto foundconv;
3772:     }

3774: #if 0
3775:     /* 3) See if a good general converter is registered for the desired class */
3776:     conv = B->ops->convertfrom;
3777:     DMDestroy(&B);
3778:     if (conv) goto foundconv;

3780:     /* 4) See if a good general converter is known for the current matrix */
3781:     if (dm->ops->convert) {
3782:       conv = dm->ops->convert;
3783:     }
3784:     if (conv) goto foundconv;
3785: #endif

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

3790: foundconv:
3791:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3792:     (*conv)(dm,newtype,M);
3793:     /* Things that are independent of DM type: We should consult DMClone() here */
3794:     {
3795:       PetscBool             isper;
3796:       const PetscReal      *maxCell, *L;
3797:       const DMBoundaryType *bd;
3798:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3799:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3800:       (*M)->prealloc_only = dm->prealloc_only;
3801:     }
3802:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3803:   }
3804:   PetscObjectStateIncrease((PetscObject) *M);
3805:   return(0);
3806: }

3808: /*--------------------------------------------------------------------------------------------------------------------*/

3810: /*@C
3811:   DMRegister -  Adds a new DM component implementation

3813:   Not Collective

3815:   Input Parameters:
3816: + name        - The name of a new user-defined creation routine
3817: - create_func - The creation routine itself

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


3823:   Sample usage:
3824: .vb
3825:     DMRegister("my_da", MyDMCreate);
3826: .ve

3828:   Then, your DM type can be chosen with the procedural interface via
3829: .vb
3830:     DMCreate(MPI_Comm, DM *);
3831:     DMSetType(DM,"my_da");
3832: .ve
3833:    or at runtime via the option
3834: .vb
3835:     -da_type my_da
3836: .ve

3838:   Level: advanced

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

3842: @*/
3843: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3844: {

3848:   DMInitializePackage();
3849:   PetscFunctionListAdd(&DMList,sname,function);
3850:   return(0);
3851: }

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

3856:   Collective on viewer

3858:   Input Parameters:
3859: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3860:            some related function before a call to DMLoad().
3861: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3862:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3864:    Level: intermediate

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

3869:   Notes for advanced users:
3870:   Most users should not need to know the details of the binary storage
3871:   format, since DMLoad() and DMView() completely hide these details.
3872:   But for anyone who's interested, the standard binary matrix storage
3873:   format is
3874: .vb
3875:      has not yet been determined
3876: .ve

3878: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3879: @*/
3880: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3881: {
3882:   PetscBool      isbinary, ishdf5;

3888:   PetscViewerCheckReadable(viewer);
3889:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3890:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3891:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3892:   if (isbinary) {
3893:     PetscInt classid;
3894:     char     type[256];

3896:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3897:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3898:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3899:     DMSetType(newdm, type);
3900:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3901:   } else if (ishdf5) {
3902:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3903:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3904:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3905:   return(0);
3906: }

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

3911:   Not collective

3913:   Input Parameter:
3914: . dm - the DM

3916:   Output Parameters:
3917: + lmin - local minimum coordinates (length coord dim, optional)
3918: - lmax - local maximim coordinates (length coord dim, optional)

3920:   Level: beginner

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


3925: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3926: @*/
3927: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3928: {
3929:   Vec                coords = NULL;
3930:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3931:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3932:   const PetscScalar *local_coords;
3933:   PetscInt           N, Ni;
3934:   PetscInt           cdim, i, j;
3935:   PetscErrorCode     ierr;

3939:   DMGetCoordinateDim(dm, &cdim);
3940:   DMGetCoordinates(dm, &coords);
3941:   if (coords) {
3942:     VecGetArrayRead(coords, &local_coords);
3943:     VecGetLocalSize(coords, &N);
3944:     Ni   = N/cdim;
3945:     for (i = 0; i < Ni; ++i) {
3946:       for (j = 0; j < 3; ++j) {
3947:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3948:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3949:       }
3950:     }
3951:     VecRestoreArrayRead(coords, &local_coords);
3952:   } else {
3953:     PetscBool isda;

3955:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3956:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3957:   }
3958:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
3959:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
3960:   return(0);
3961: }

3963: /*@
3964:   DMGetBoundingBox - Returns the global bounding box for the DM.

3966:   Collective

3968:   Input Parameter:
3969: . dm - the DM

3971:   Output Parameters:
3972: + gmin - global minimum coordinates (length coord dim, optional)
3973: - gmax - global maximim coordinates (length coord dim, optional)

3975:   Level: beginner

3977: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3978: @*/
3979: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3980: {
3981:   PetscReal      lmin[3], lmax[3];
3982:   PetscInt       cdim;
3983:   PetscMPIInt    count;

3988:   DMGetCoordinateDim(dm, &cdim);
3989:   PetscMPIIntCast(cdim, &count);
3990:   DMGetLocalBoundingBox(dm, lmin, lmax);
3991:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3992:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3993:   return(0);
3994: }

3996: /******************************** FEM Support **********************************/

3998: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3999: {
4000:   PetscInt       f;

4004:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4005:   for (f = 0; f < len; ++f) {
4006:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
4007:   }
4008:   return(0);
4009: }

4011: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4012: {
4013:   PetscInt       f, g;

4017:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4018:   for (f = 0; f < rows; ++f) {
4019:     PetscPrintf(PETSC_COMM_SELF, "  |");
4020:     for (g = 0; g < cols; ++g) {
4021:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4022:     }
4023:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4024:   }
4025:   return(0);
4026: }

4028: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4029: {
4030:   PetscInt          localSize, bs;
4031:   PetscMPIInt       size;
4032:   Vec               x, xglob;
4033:   const PetscScalar *xarray;
4034:   PetscErrorCode    ierr;

4037:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4038:   VecDuplicate(X, &x);
4039:   VecCopy(X, x);
4040:   VecChop(x, tol);
4041:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4042:   if (size > 1) {
4043:     VecGetLocalSize(x,&localSize);
4044:     VecGetArrayRead(x,&xarray);
4045:     VecGetBlockSize(x,&bs);
4046:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4047:   } else {
4048:     xglob = x;
4049:   }
4050:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4051:   if (size > 1) {
4052:     VecDestroy(&xglob);
4053:     VecRestoreArrayRead(x,&xarray);
4054:   }
4055:   VecDestroy(&x);
4056:   return(0);
4057: }

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

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

4065:   Output Parameter:
4066: . section - The PetscSection

4068:   Options Database Keys:
4069: . -dm_petscsection_view - View the Section created by the DM

4071:   Level: advanced

4073:   Notes:
4074:   Use DMGetLocalSection() in new code.

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

4078: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4079: @*/
4080: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4081: {

4085:   DMGetLocalSection(dm,section);
4086:   return(0);
4087: }

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

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

4095:   Output Parameter:
4096: . section - The PetscSection

4098:   Options Database Keys:
4099: . -dm_petscsection_view - View the Section created by the DM

4101:   Level: intermediate

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

4105: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4106: @*/
4107: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4108: {

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

4117:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4118:     (*dm->ops->createlocalsection)(dm);
4119:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4120:   }
4121:   *section = dm->localSection;
4122:   return(0);
4123: }

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

4128:   Input Parameters:
4129: + dm - The DM
4130: - section - The PetscSection

4132:   Level: advanced

4134:   Notes:
4135:   Use DMSetLocalSection() in new code.

4137:   Any existing Section will be destroyed

4139: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4140: @*/
4141: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4142: {

4146:   DMSetLocalSection(dm,section);
4147:   return(0);
4148: }

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

4153:   Input Parameters:
4154: + dm - The DM
4155: - section - The PetscSection

4157:   Level: intermediate

4159:   Note: Any existing Section will be destroyed

4161: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4162: @*/
4163: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4164: {
4165:   PetscInt       numFields = 0;
4166:   PetscInt       f;

4172:   PetscObjectReference((PetscObject)section);
4173:   PetscSectionDestroy(&dm->localSection);
4174:   dm->localSection = section;
4175:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4176:   if (numFields) {
4177:     DMSetNumFields(dm, numFields);
4178:     for (f = 0; f < numFields; ++f) {
4179:       PetscObject disc;
4180:       const char *name;

4182:       PetscSectionGetFieldName(dm->localSection, f, &name);
4183:       DMGetField(dm, f, NULL, &disc);
4184:       PetscObjectSetName(disc, name);
4185:     }
4186:   }
4187:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4188:   PetscSectionDestroy(&dm->globalSection);
4189:   return(0);
4190: }

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

4195:   not collective

4197:   Input Parameter:
4198: . dm - The DM

4200:   Output Parameter:
4201: + 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.
4202: - 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.

4204:   Level: advanced

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

4208: .seealso: DMSetDefaultConstraints()
4209: @*/
4210: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4211: {

4216:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4217:   if (section) {*section = dm->defaultConstraintSection;}
4218:   if (mat) {*mat = dm->defaultConstraintMat;}
4219:   return(0);
4220: }

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

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

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

4229:   collective on dm

4231:   Input Parameters:
4232: + dm - The DM
4233: + 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).
4234: - 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).

4236:   Level: advanced

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

4240: .seealso: DMGetDefaultConstraints()
4241: @*/
4242: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4243: {
4244:   PetscMPIInt result;

4249:   if (section) {
4251:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4252:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4253:   }
4254:   if (mat) {
4256:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4257:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4258:   }
4259:   PetscObjectReference((PetscObject)section);
4260:   PetscSectionDestroy(&dm->defaultConstraintSection);
4261:   dm->defaultConstraintSection = section;
4262:   PetscObjectReference((PetscObject)mat);
4263:   MatDestroy(&dm->defaultConstraintMat);
4264:   dm->defaultConstraintMat = mat;
4265:   return(0);
4266: }

4268: #if defined(PETSC_USE_DEBUG)
4269: /*
4270:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4272:   Input Parameters:
4273: + dm - The DM
4274: . localSection - PetscSection describing the local data layout
4275: - globalSection - PetscSection describing the global data layout

4277:   Level: intermediate

4279: .seealso: DMGetSectionSF(), DMSetSectionSF()
4280: */
4281: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4282: {
4283:   MPI_Comm        comm;
4284:   PetscLayout     layout;
4285:   const PetscInt *ranges;
4286:   PetscInt        pStart, pEnd, p, nroots;
4287:   PetscMPIInt     size, rank;
4288:   PetscBool       valid = PETSC_TRUE, gvalid;
4289:   PetscErrorCode  ierr;

4292:   PetscObjectGetComm((PetscObject)dm,&comm);
4294:   MPI_Comm_size(comm, &size);
4295:   MPI_Comm_rank(comm, &rank);
4296:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4297:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4298:   PetscLayoutCreate(comm, &layout);
4299:   PetscLayoutSetBlockSize(layout, 1);
4300:   PetscLayoutSetLocalSize(layout, nroots);
4301:   PetscLayoutSetUp(layout);
4302:   PetscLayoutGetRanges(layout, &ranges);
4303:   for (p = pStart; p < pEnd; ++p) {
4304:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4306:     PetscSectionGetDof(localSection, p, &dof);
4307:     PetscSectionGetOffset(localSection, p, &off);
4308:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4309:     PetscSectionGetDof(globalSection, p, &gdof);
4310:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4311:     PetscSectionGetOffset(globalSection, p, &goff);
4312:     if (!gdof) continue; /* Censored point */
4313:     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;}
4314:     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;}
4315:     if (gdof < 0) {
4316:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4317:       for (d = 0; d < gsize; ++d) {
4318:         PetscInt offset = -(goff+1) + d, r;

4320:         PetscFindInt(offset,size+1,ranges,&r);
4321:         if (r < 0) r = -(r+2);
4322:         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;}
4323:       }
4324:     }
4325:   }
4326:   PetscLayoutDestroy(&layout);
4327:   PetscSynchronizedFlush(comm, NULL);
4328:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4329:   if (!gvalid) {
4330:     DMView(dm, NULL);
4331:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4332:   }
4333:   return(0);
4334: }
4335: #endif

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

4340:   Collective on dm

4342:   Input Parameter:
4343: . dm - The DM

4345:   Output Parameter:
4346: . section - The PetscSection

4348:   Level: intermediate

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

4352: .seealso: DMSetLocalSection(), DMGetLocalSection()
4353: @*/
4354: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4355: {

4361:   if (!dm->globalSection) {
4362:     PetscSection s;

4364:     DMGetLocalSection(dm, &s);
4365:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4366:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4367:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4368:     PetscLayoutDestroy(&dm->map);
4369:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4370:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4371:   }
4372:   *section = dm->globalSection;
4373:   return(0);
4374: }

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

4379:   Input Parameters:
4380: + dm - The DM
4381: - section - The PetscSection, or NULL

4383:   Level: intermediate

4385:   Note: Any existing Section will be destroyed

4387: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4388: @*/
4389: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4390: {

4396:   PetscObjectReference((PetscObject)section);
4397:   PetscSectionDestroy(&dm->globalSection);
4398:   dm->globalSection = section;
4399: #if defined(PETSC_USE_DEBUG)
4400:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4401: #endif
4402:   return(0);
4403: }

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

4409:   Input Parameter:
4410: . dm - The DM

4412:   Output Parameter:
4413: . sf - The PetscSF

4415:   Level: intermediate

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

4419: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4420: @*/
4421: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4422: {
4423:   PetscInt       nroots;

4429:   if (!dm->sectionSF) {
4430:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4431:   }
4432:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4433:   if (nroots < 0) {
4434:     PetscSection section, gSection;

4436:     DMGetLocalSection(dm, &section);
4437:     if (section) {
4438:       DMGetGlobalSection(dm, &gSection);
4439:       DMCreateSectionSF(dm, section, gSection);
4440:     } else {
4441:       *sf = NULL;
4442:       return(0);
4443:     }
4444:   }
4445:   *sf = dm->sectionSF;
4446:   return(0);
4447: }

4449: /*@
4450:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4452:   Input Parameters:
4453: + dm - The DM
4454: - sf - The PetscSF

4456:   Level: intermediate

4458:   Note: Any previous SF is destroyed

4460: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4461: @*/
4462: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4463: {

4469:   PetscObjectReference((PetscObject) sf);
4470:   PetscSFDestroy(&dm->sectionSF);
4471:   dm->sectionSF = sf;
4472:   return(0);
4473: }

4475: /*@C
4476:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4477:   describing the data layout.

4479:   Input Parameters:
4480: + dm - The DM
4481: . localSection - PetscSection describing the local data layout
4482: - globalSection - PetscSection describing the global data layout

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

4486:   Level: developer

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

4492: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4493: @*/
4494: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4495: {

4500:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4501:   return(0);
4502: }

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

4507:   Input Parameter:
4508: . dm - The DM

4510:   Output Parameter:
4511: . sf - The PetscSF

4513:   Level: intermediate

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

4517: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4518: @*/
4519: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4520: {
4524:   *sf = dm->sf;
4525:   return(0);
4526: }

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

4531:   Input Parameters:
4532: + dm - The DM
4533: - sf - The PetscSF

4535:   Level: intermediate

4537: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4538: @*/
4539: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4540: {

4546:   PetscObjectReference((PetscObject) sf);
4547:   PetscSFDestroy(&dm->sf);
4548:   dm->sf = sf;
4549:   return(0);
4550: }

4552: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4553: {
4554:   PetscClassId   id;

4558:   PetscObjectGetClassId(disc, &id);
4559:   if (id == PETSCFE_CLASSID) {
4560:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4561:   } else if (id == PETSCFV_CLASSID) {
4562:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4563:   } else {
4564:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4565:   }
4566:   return(0);
4567: }

4569: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4570: {
4571:   RegionField   *tmpr;
4572:   PetscInt       Nf = dm->Nf, f;

4576:   if (Nf >= NfNew) return(0);
4577:   PetscMalloc1(NfNew, &tmpr);
4578:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4579:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4580:   PetscFree(dm->fields);
4581:   dm->Nf     = NfNew;
4582:   dm->fields = tmpr;
4583:   return(0);
4584: }

4586: /*@
4587:   DMClearFields - Remove all fields from the DM

4589:   Logically collective on dm

4591:   Input Parameter:
4592: . dm - The DM

4594:   Level: intermediate

4596: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4597: @*/
4598: PetscErrorCode DMClearFields(DM dm)
4599: {
4600:   PetscInt       f;

4605:   for (f = 0; f < dm->Nf; ++f) {
4606:     PetscObjectDestroy(&dm->fields[f].disc);
4607:     DMLabelDestroy(&dm->fields[f].label);
4608:   }
4609:   PetscFree(dm->fields);
4610:   dm->fields = NULL;
4611:   dm->Nf     = 0;
4612:   return(0);
4613: }

4615: /*@
4616:   DMGetNumFields - Get the number of fields in the DM

4618:   Not collective

4620:   Input Parameter:
4621: . dm - The DM

4623:   Output Parameter:
4624: . Nf - The number of fields

4626:   Level: intermediate

4628: .seealso: DMSetNumFields(), DMSetField()
4629: @*/
4630: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4631: {
4635:   *numFields = dm->Nf;
4636:   return(0);
4637: }

4639: /*@
4640:   DMSetNumFields - Set the number of fields in the DM

4642:   Logically collective on dm

4644:   Input Parameters:
4645: + dm - The DM
4646: - Nf - The number of fields

4648:   Level: intermediate

4650: .seealso: DMGetNumFields(), DMSetField()
4651: @*/
4652: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4653: {
4654:   PetscInt       Nf, f;

4659:   DMGetNumFields(dm, &Nf);
4660:   for (f = Nf; f < numFields; ++f) {
4661:     PetscContainer obj;

4663:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4664:     DMAddField(dm, NULL, (PetscObject) obj);
4665:     PetscContainerDestroy(&obj);
4666:   }
4667:   return(0);
4668: }

4670: /*@
4671:   DMGetField - Return the discretization object for a given DM field

4673:   Not collective

4675:   Input Parameters:
4676: + dm - The DM
4677: - f  - The field number

4679:   Output Parameters:
4680: + label - The label indicating the support of the field, or NULL for the entire mesh
4681: - field - The discretization object

4683:   Level: intermediate

4685: .seealso: DMAddField(), DMSetField()
4686: @*/
4687: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4688: {
4692:   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);
4693:   if (label) *label = dm->fields[f].label;
4694:   if (field) *field = dm->fields[f].disc;
4695:   return(0);
4696: }

4698: /* Does not clear the DS */
4699: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4700: {

4704:   DMFieldEnlarge_Static(dm, f+1);
4705:   DMLabelDestroy(&dm->fields[f].label);
4706:   PetscObjectDestroy(&dm->fields[f].disc);
4707:   dm->fields[f].label = label;
4708:   dm->fields[f].disc  = field;
4709:   PetscObjectReference((PetscObject) label);
4710:   PetscObjectReference((PetscObject) field);
4711:   return(0);
4712: }

4714: /*@
4715:   DMSetField - Set the discretization object for a given DM field

4717:   Logically collective on dm

4719:   Input Parameters:
4720: + dm    - The DM
4721: . f     - The field number
4722: . label - The label indicating the support of the field, or NULL for the entire mesh
4723: - field - The discretization object

4725:   Level: intermediate

4727: .seealso: DMAddField(), DMGetField()
4728: @*/
4729: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4730: {

4737:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4738:   DMSetField_Internal(dm, f, label, field);
4739:   DMSetDefaultAdjacency_Private(dm, f, field);
4740:   DMClearDS(dm);
4741:   return(0);
4742: }

4744: /*@
4745:   DMAddField - Add the discretization object for the given DM field

4747:   Logically collective on dm

4749:   Input Parameters:
4750: + dm    - The DM
4751: . label - The label indicating the support of the field, or NULL for the entire mesh
4752: - field - The discretization object

4754:   Level: intermediate

4756: .seealso: DMSetField(), DMGetField()
4757: @*/
4758: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4759: {
4760:   PetscInt       Nf = dm->Nf;

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

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

4780:   Logically collective on dm

4782:   Input Parameters:
4783: + dm          - The DM
4784: . f           - The field index
4785: - avoidTensor - The flag to avoid defining the field on tensor cells

4787:   Level: intermediate

4789: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4790: @*/
4791: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4792: {
4794:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4795:   dm->fields[f].avoidTensor = avoidTensor;
4796:   return(0);
4797: }

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

4802:   Logically collective on dm

4804:   Input Parameters:
4805: + dm          - The DM
4806: - f           - The field index

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

4811:   Level: intermediate

4813: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4814: @*/
4815: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4816: {
4818:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4819:   *avoidTensor = dm->fields[f].avoidTensor;
4820:   return(0);
4821: }

4823: /*@
4824:   DMCopyFields - Copy the discretizations for the DM into another DM

4826:   Collective on dm

4828:   Input Parameter:
4829: . dm - The DM

4831:   Output Parameter:
4832: . newdm - The DM

4834:   Level: advanced

4836: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4837: @*/
4838: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4839: {
4840:   PetscInt       Nf, f;

4844:   if (dm == newdm) return(0);
4845:   DMGetNumFields(dm, &Nf);
4846:   DMClearFields(newdm);
4847:   for (f = 0; f < Nf; ++f) {
4848:     DMLabel     label;
4849:     PetscObject field;
4850:     PetscBool   useCone, useClosure;

4852:     DMGetField(dm, f, &label, &field);
4853:     DMSetField(newdm, f, label, field);
4854:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4855:     DMSetAdjacency(newdm, f, useCone, useClosure);
4856:   }
4857:   return(0);
4858: }

4860: /*@
4861:   DMGetAdjacency - Returns the flags for determining variable influence

4863:   Not collective

4865:   Input Parameters:
4866: + dm - The DM object
4867: - f  - The field number, or PETSC_DEFAULT for the default adjacency

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

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

4879:   Level: developer

4881: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4882: @*/
4883: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4884: {
4889:   if (f < 0) {
4890:     if (useCone)    *useCone    = dm->adjacency[0];
4891:     if (useClosure) *useClosure = dm->adjacency[1];
4892:   } else {
4893:     PetscInt       Nf;

4896:     DMGetNumFields(dm, &Nf);
4897:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4898:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4899:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4900:   }
4901:   return(0);
4902: }

4904: /*@
4905:   DMSetAdjacency - Set the flags for determining variable influence

4907:   Not collective

4909:   Input Parameters:
4910: + dm         - The DM object
4911: . f          - The field number
4912: . useCone    - Flag for variable influence starting with the cone operation
4913: - useClosure - Flag for variable influence using transitive closure

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

4921:   Level: developer

4923: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4924: @*/
4925: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4926: {
4929:   if (f < 0) {
4930:     dm->adjacency[0] = useCone;
4931:     dm->adjacency[1] = useClosure;
4932:   } else {
4933:     PetscInt       Nf;

4936:     DMGetNumFields(dm, &Nf);
4937:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4938:     dm->fields[f].adjacency[0] = useCone;
4939:     dm->fields[f].adjacency[1] = useClosure;
4940:   }
4941:   return(0);
4942: }

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

4947:   Not collective

4949:   Input Parameters:
4950: . dm - The DM object

4952:   Output Parameter:
4953: + useCone    - Flag for variable influence starting with the cone operation
4954: - useClosure - Flag for variable influence using transitive closure

4956:   Notes:
4957: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4958: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4959: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4961:   Level: developer

4963: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4964: @*/
4965: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4966: {
4967:   PetscInt       Nf;

4974:   DMGetNumFields(dm, &Nf);
4975:   if (!Nf) {
4976:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4977:   } else {
4978:     DMGetAdjacency(dm, 0, useCone, useClosure);
4979:   }
4980:   return(0);
4981: }

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

4986:   Not collective

4988:   Input Parameters:
4989: + dm         - The DM object
4990: . useCone    - Flag for variable influence starting with the cone operation
4991: - useClosure - Flag for variable influence using transitive closure

4993:   Notes:
4994: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4995: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4996: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4998:   Level: developer

5000: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5001: @*/
5002: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5003: {
5004:   PetscInt       Nf;

5009:   DMGetNumFields(dm, &Nf);
5010:   if (!Nf) {
5011:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5012:   } else {
5013:     DMSetAdjacency(dm, 0, useCone, useClosure);
5014:   }
5015:   return(0);
5016: }

5018: /* Complete labels that are being used for FEM BC */
5019: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5020: {
5021:   DMLabel        label;
5022:   PetscObject    obj;
5023:   PetscClassId   id;
5024:   PetscInt       Nbd, bd;
5025:   PetscBool      isFE      = PETSC_FALSE;
5026:   PetscBool      duplicate = PETSC_FALSE;

5030:   DMGetField(dm, field, NULL, &obj);
5031:   PetscObjectGetClassId(obj, &id);
5032:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5033:   DMGetLabel(dm, labelname, &label);
5034:   if (isFE && label) {
5035:     /* Only want to modify label once */
5036:     PetscDSGetNumBoundary(ds, &Nbd);
5037:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5038:       const char *lname;

5040:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5041:       PetscStrcmp(lname, labelname, &duplicate);
5042:       if (duplicate) break;
5043:     }
5044:     if (!duplicate) {
5045:       DM plex;

5047:       DMConvert(dm, DMPLEX, &plex);
5048:       if (plex) {DMPlexLabelComplete(plex, label);}
5049:       DMDestroy(&plex);
5050:     }
5051:   }
5052:   return(0);
5053: }

5055: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5056: {
5057:   DMSpace       *tmpd;
5058:   PetscInt       Nds = dm->Nds, s;

5062:   if (Nds >= NdsNew) return(0);
5063:   PetscMalloc1(NdsNew, &tmpd);
5064:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5065:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5066:   PetscFree(dm->probs);
5067:   dm->Nds   = NdsNew;
5068:   dm->probs = tmpd;
5069:   return(0);
5070: }

5072: /*@
5073:   DMGetNumDS - Get the number of discrete systems in the DM

5075:   Not collective

5077:   Input Parameter:
5078: . dm - The DM

5080:   Output Parameter:
5081: . Nds - The number of PetscDS objects

5083:   Level: intermediate

5085: .seealso: DMGetDS(), DMGetCellDS()
5086: @*/
5087: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5088: {
5092:   *Nds = dm->Nds;
5093:   return(0);
5094: }

5096: /*@
5097:   DMClearDS - Remove all discrete systems from the DM

5099:   Logically collective on dm

5101:   Input Parameter:
5102: . dm - The DM

5104:   Level: intermediate

5106: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5107: @*/
5108: PetscErrorCode DMClearDS(DM dm)
5109: {
5110:   PetscInt       s;

5115:   for (s = 0; s < dm->Nds; ++s) {
5116:     PetscDSDestroy(&dm->probs[s].ds);
5117:     DMLabelDestroy(&dm->probs[s].label);
5118:     ISDestroy(&dm->probs[s].fields);
5119:   }
5120:   PetscFree(dm->probs);
5121:   dm->probs = NULL;
5122:   dm->Nds   = 0;
5123:   return(0);
5124: }

5126: /*@
5127:   DMGetDS - Get the default PetscDS

5129:   Not collective

5131:   Input Parameter:
5132: . dm    - The DM

5134:   Output Parameter:
5135: . prob - The default PetscDS

5137:   Level: intermediate

5139: .seealso: DMGetCellDS(), DMGetRegionDS()
5140: @*/
5141: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5142: {

5148:   if (dm->Nds <= 0) {
5149:     PetscDS ds;

5151:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5152:     DMSetRegionDS(dm, NULL, NULL, ds);
5153:     PetscDSDestroy(&ds);
5154:   }
5155:   *prob = dm->probs[0].ds;
5156:   return(0);
5157: }

5159: /*@
5160:   DMGetCellDS - Get the PetscDS defined on a given cell

5162:   Not collective

5164:   Input Parameters:
5165: + dm    - The DM
5166: - point - Cell for the DS

5168:   Output Parameter:
5169: . prob - The PetscDS defined on the given cell

5171:   Level: developer

5173: .seealso: DMGetDS(), DMSetRegionDS()
5174: @*/
5175: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5176: {
5177:   PetscDS        probDef = NULL;
5178:   PetscInt       s;

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

5189:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5190:     else {
5191:       DMLabelGetValue(dm->probs[s].label, point, &val);
5192:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5193:     }
5194:   }
5195:   if (!*prob) *prob = probDef;
5196:   return(0);
5197: }

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

5202:   Not collective

5204:   Input Parameters:
5205: + dm    - The DM
5206: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5214:   Level: advanced

5216: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5217: @*/
5218: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5219: {
5220:   PetscInt Nds = dm->Nds, s;

5227:   for (s = 0; s < Nds; ++s) {
5228:     if (dm->probs[s].label == label) {
5229:       if (fields) *fields = dm->probs[s].fields;
5230:       if (ds)     *ds     = dm->probs[s].ds;
5231:       return(0);
5232:     }
5233:   }
5234:   return(0);
5235: }

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

5240:   Collective on dm

5242:   Input Parameters:
5243: + dm     - The DM
5244: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5245: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5246: - prob   - The PetscDS defined on the given cell

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

5251:   Level: advanced

5253: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5254: @*/
5255: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5256: {
5257:   PetscInt       Nds = dm->Nds, s;

5264:   for (s = 0; s < Nds; ++s) {
5265:     if (dm->probs[s].label == label) {
5266:       PetscDSDestroy(&dm->probs[s].ds);
5267:       dm->probs[s].ds = ds;
5268:       return(0);
5269:     }
5270:   }
5271:   DMDSEnlarge_Static(dm, Nds+1);
5272:   PetscObjectReference((PetscObject) label);
5273:   PetscObjectReference((PetscObject) fields);
5274:   PetscObjectReference((PetscObject) ds);
5275:   if (!label) {
5276:     /* Put the NULL label at the front, so it is returned as the default */
5277:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5278:     Nds = 0;
5279:   }
5280:   dm->probs[Nds].label  = label;
5281:   dm->probs[Nds].fields = fields;
5282:   dm->probs[Nds].ds     = ds;
5283:   return(0);
5284: }

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

5289:   Not collective

5291:   Input Parameters:
5292: + dm  - The DM
5293: - num - The region number, in [0, Nds)

5295:   Output Parameters:
5296: + label  - The region label, or NULL
5297: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5298: - ds     - The PetscDS defined on the given region, or NULL

5300:   Level: advanced

5302: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5303: @*/
5304: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5305: {
5306:   PetscInt       Nds;

5311:   DMGetNumDS(dm, &Nds);
5312:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5313:   if (label) {
5315:     *label = dm->probs[num].label;
5316:   }
5317:   if (fields) {
5319:     *fields = dm->probs[num].fields;
5320:   }
5321:   if (ds) {
5323:     *ds = dm->probs[num].ds;
5324:   }
5325:   return(0);
5326: }

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

5331:   Not collective

5333:   Input Parameters:
5334: + dm     - The DM
5335: . num    - The region number, in [0, Nds)
5336: . label  - The region label, or NULL
5337: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5338: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5340:   Level: advanced

5342: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5343: @*/
5344: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5345: {
5346:   PetscInt       Nds;

5352:   DMGetNumDS(dm, &Nds);
5353:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5354:   PetscObjectReference((PetscObject) label);
5355:   DMLabelDestroy(&dm->probs[num].label);
5356:   dm->probs[num].label = label;
5357:   if (fields) {
5359:     PetscObjectReference((PetscObject) fields);
5360:     ISDestroy(&dm->probs[num].fields);
5361:     dm->probs[num].fields = fields;
5362:   }
5363:   if (ds) {
5365:     PetscObjectReference((PetscObject) ds);
5366:     PetscDSDestroy(&dm->probs[num].ds);
5367:     dm->probs[num].ds = ds;
5368:   }
5369:   return(0);
5370: }

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

5375:   Not collective

5377:   Input Parameters:
5378: + dm  - The DM
5379: - ds  - The PetscDS defined on the given region

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

5384:   Level: advanced

5386: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5387: @*/
5388: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5389: {
5390:   PetscInt       Nds, n;

5397:   DMGetNumDS(dm, &Nds);
5398:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5399:   if (n >= Nds) *num = -1;
5400:   else          *num = n;
5401:   return(0);
5402: }

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

5407:   Collective on dm

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

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

5414:   Level: intermediate

5416: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5417: @*/
5418: PetscErrorCode DMCreateDS(DM dm)
5419: {
5420:   MPI_Comm       comm;
5421:   PetscDS        dsDef;
5422:   DMLabel       *labelSet;
5423:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5424:   PetscBool      doSetup = PETSC_TRUE;

5429:   if (!dm->fields) return(0);
5430:   PetscObjectGetComm((PetscObject) dm, &comm);
5431:   DMGetCoordinateDim(dm, &dE);
5432:   /* Determine how many regions we have */
5433:   PetscMalloc1(Nf, &labelSet);
5434:   Nl   = 0;
5435:   Ndef = 0;
5436:   for (f = 0; f < Nf; ++f) {
5437:     DMLabel  label = dm->fields[f].label;
5438:     PetscInt l;

5440:     if (!label) {++Ndef; continue;}
5441:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5442:     if (l < Nl) continue;
5443:     labelSet[Nl++] = label;
5444:   }
5445:   /* Create default DS if there are no labels to intersect with */
5446:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5447:   if (!dsDef && Ndef && !Nl) {
5448:     IS        fields;
5449:     PetscInt *fld, nf;

5451:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5452:     if (nf) {
5453:       PetscMalloc1(nf, &fld);
5454:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5455:       ISCreate(PETSC_COMM_SELF, &fields);
5456:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5457:       ISSetType(fields, ISGENERAL);
5458:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5460:       PetscDSCreate(comm, &dsDef);
5461:       DMSetRegionDS(dm, NULL, fields, dsDef);
5462:       PetscDSDestroy(&dsDef);
5463:       ISDestroy(&fields);
5464:     }
5465:   }
5466:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5467:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5468:   /* Intersect labels with default fields */
5469:   if (Ndef && Nl) {
5470:     DM              plex;
5471:     DMLabel         cellLabel;
5472:     IS              fieldIS, allcellIS, defcellIS = NULL;
5473:     PetscInt       *fields;
5474:     const PetscInt *cells;
5475:     PetscInt        depth, nf = 0, n, c;

5477:     DMConvert(dm, DMPLEX, &plex);
5478:     DMPlexGetDepth(plex, &depth);
5479:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5480:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5481:     for (l = 0; l < Nl; ++l) {
5482:       DMLabel label = labelSet[l];
5483:       IS      pointIS;

5485:       ISDestroy(&defcellIS);
5486:       DMLabelGetStratumIS(label, 1, &pointIS);
5487:       ISDifference(allcellIS, pointIS, &defcellIS);
5488:       ISDestroy(&pointIS);
5489:     }
5490:     ISDestroy(&allcellIS);

5492:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5493:     ISGetLocalSize(defcellIS, &n);
5494:     ISGetIndices(defcellIS, &cells);
5495:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5496:     ISRestoreIndices(defcellIS, &cells);
5497:     ISDestroy(&defcellIS);
5498:     DMPlexLabelComplete(plex, cellLabel);

5500:     PetscMalloc1(Ndef, &fields);
5501:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5502:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5503:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5504:     ISSetType(fieldIS, ISGENERAL);
5505:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5507:     PetscDSCreate(comm, &dsDef);
5508:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5509:     DMLabelDestroy(&cellLabel);
5510:     PetscDSSetCoordinateDimension(dsDef, dE);
5511:     PetscDSDestroy(&dsDef);
5512:     ISDestroy(&fieldIS);
5513:     DMDestroy(&plex);
5514:   }
5515:   /* Create label DSes
5516:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5517:   */
5518:   /* TODO Should check that labels are disjoint */
5519:   for (l = 0; l < Nl; ++l) {
5520:     DMLabel   label = labelSet[l];
5521:     PetscDS   ds;
5522:     IS        fields;
5523:     PetscInt *fld, nf;

5525:     PetscDSCreate(comm, &ds);
5526:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5527:     PetscMalloc1(nf, &fld);
5528:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5529:     ISCreate(PETSC_COMM_SELF, &fields);
5530:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5531:     ISSetType(fields, ISGENERAL);
5532:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5533:     DMSetRegionDS(dm, label, fields, ds);
5534:     ISDestroy(&fields);
5535:     PetscDSSetCoordinateDimension(ds, dE);
5536:     {
5537:       DMPolytopeType ct;
5538:       PetscInt       lStart, lEnd;
5539:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5541:       DMLabelGetBounds(label, &lStart, &lEnd);
5542:       if (lStart >= 0) {
5543:         DMPlexGetCellType(dm, lStart, &ct);
5544:         switch (ct) {
5545:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5546:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5547:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5548:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5549:             isHybridLocal = PETSC_TRUE;break;
5550:           default: break;
5551:         }
5552:       }
5553:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5554:       PetscDSSetHybrid(ds, isHybrid);
5555:     }
5556:     PetscDSDestroy(&ds);
5557:   }
5558:   PetscFree(labelSet);
5559:   /* Set fields in DSes */
5560:   for (s = 0; s < dm->Nds; ++s) {
5561:     PetscDS         ds     = dm->probs[s].ds;
5562:     IS              fields = dm->probs[s].fields;
5563:     const PetscInt *fld;
5564:     PetscInt        nf;

5566:     ISGetLocalSize(fields, &nf);
5567:     ISGetIndices(fields, &fld);
5568:     for (f = 0; f < nf; ++f) {
5569:       PetscObject  disc  = dm->fields[fld[f]].disc;
5570:       PetscBool    isHybrid;
5571:       PetscClassId id;

5573:       PetscDSGetHybrid(ds, &isHybrid);
5574:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5575:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5576:       PetscDSSetDiscretization(ds, f, disc);
5577:       /* We allow people to have placeholder fields and construct the Section by hand */
5578:       PetscObjectGetClassId(disc, &id);
5579:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5580:     }
5581:     ISRestoreIndices(fields, &fld);
5582:   }
5583:   /* Setup DSes */
5584:   if (doSetup) {
5585:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5586:   }
5587:   return(0);
5588: }

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

5593:   Collective on DM

5595:   Input Parameters:
5596: + dm   - The DM
5597: - time - The time

5599:   Output Parameters:
5600: + u    - The vector will be filled with exact solution values, or NULL
5601: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

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

5605:   Level: developer

5607: .seealso: PetscDSSetExactSolution()
5608: @*/
5609: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5610: {
5611:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5612:   void            **ectxs;
5613:   PetscInt          Nf, Nds, s;
5614:   PetscErrorCode    ierr;

5620:   DMGetNumFields(dm, &Nf);
5621:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5622:   DMGetNumDS(dm, &Nds);
5623:   for (s = 0; s < Nds; ++s) {
5624:     PetscDS         ds;
5625:     DMLabel         label;
5626:     IS              fieldIS;
5627:     const PetscInt *fields, id = 1;
5628:     PetscInt        dsNf, f;

5630:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5631:     PetscDSGetNumFields(ds, &dsNf);
5632:     ISGetIndices(fieldIS, &fields);
5633:     PetscArrayzero(exacts, Nf);
5634:     PetscArrayzero(ectxs, Nf);
5635:     if (u) {
5636:       for (f = 0; f < dsNf; ++f) {
5637:         const PetscInt field = fields[f];
5638:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5639:       }
5640:       ISRestoreIndices(fieldIS, &fields);
5641:       if (label) {
5642:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5643:       } else {
5644:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5645:       }
5646:     }
5647:     if (u_t) {
5648:       PetscArrayzero(exacts, Nf);
5649:       PetscArrayzero(ectxs, Nf);
5650:       for (f = 0; f < dsNf; ++f) {
5651:         const PetscInt field = fields[f];
5652:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5653:       }
5654:       ISRestoreIndices(fieldIS, &fields);
5655:       if (label) {
5656:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5657:       } else {
5658:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5659:       }
5660:     }
5661:   }
5662:   if (u) {
5663:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5664:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5665:   }
5666:   if (u_t) {
5667:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5668:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5669:   }
5670:   PetscFree2(exacts, ectxs);
5671:   return(0);
5672: }

5674: /*@
5675:   DMCopyDS - Copy the discrete systems for the DM into another DM

5677:   Collective on dm

5679:   Input Parameter:
5680: . dm - The DM

5682:   Output Parameter:
5683: . newdm - The DM

5685:   Level: advanced

5687: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5688: @*/
5689: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5690: {
5691:   PetscInt       Nds, s;

5695:   if (dm == newdm) return(0);
5696:   DMGetNumDS(dm, &Nds);
5697:   DMClearDS(newdm);
5698:   for (s = 0; s < Nds; ++s) {
5699:     DMLabel  label;
5700:     IS       fields;
5701:     PetscDS  ds;
5702:     PetscInt Nbd, bd;

5704:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5705:     DMSetRegionDS(newdm, label, fields, ds);
5706:     PetscDSGetNumBoundary(ds, &Nbd);
5707:     for (bd = 0; bd < Nbd; ++bd) {
5708:       const char *labelname, *name;
5709:       PetscInt    field;

5711:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5712:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5713:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5714:     }
5715:   }
5716:   return(0);
5717: }

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

5722:   Collective on dm

5724:   Input Parameter:
5725: . dm - The DM

5727:   Output Parameter:
5728: . newdm - The DM

5730:   Level: advanced

5732: .seealso: DMCopyFields(), DMCopyDS()
5733: @*/
5734: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5735: {

5739:   DMCopyFields(dm, newdm);
5740:   DMCopyDS(dm, newdm);
5741:   return(0);
5742: }

5744: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5745: {
5746:   DM dm_coord,dmc_coord;
5748:   Vec coords,ccoords;
5749:   Mat inject;
5751:   DMGetCoordinateDM(dm,&dm_coord);
5752:   DMGetCoordinateDM(dmc,&dmc_coord);
5753:   DMGetCoordinates(dm,&coords);
5754:   DMGetCoordinates(dmc,&ccoords);
5755:   if (coords && !ccoords) {
5756:     DMCreateGlobalVector(dmc_coord,&ccoords);
5757:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5758:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5759:     MatRestrict(inject,coords,ccoords);
5760:     MatDestroy(&inject);
5761:     DMSetCoordinates(dmc,ccoords);
5762:     VecDestroy(&ccoords);
5763:   }
5764:   return(0);
5765: }

5767: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5768: {
5769:   DM dm_coord,subdm_coord;
5771:   Vec coords,ccoords,clcoords;
5772:   VecScatter *scat_i,*scat_g;
5774:   DMGetCoordinateDM(dm,&dm_coord);
5775:   DMGetCoordinateDM(subdm,&subdm_coord);
5776:   DMGetCoordinates(dm,&coords);
5777:   DMGetCoordinates(subdm,&ccoords);
5778:   if (coords && !ccoords) {
5779:     DMCreateGlobalVector(subdm_coord,&ccoords);
5780:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5781:     DMCreateLocalVector(subdm_coord,&clcoords);
5782:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5783:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5784:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5785:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5786:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5787:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5788:     DMSetCoordinates(subdm,ccoords);
5789:     DMSetCoordinatesLocal(subdm,clcoords);
5790:     VecScatterDestroy(&scat_i[0]);
5791:     VecScatterDestroy(&scat_g[0]);
5792:     VecDestroy(&ccoords);
5793:     VecDestroy(&clcoords);
5794:     PetscFree(scat_i);
5795:     PetscFree(scat_g);
5796:   }
5797:   return(0);
5798: }

5800: /*@
5801:   DMGetDimension - Return the topological dimension of the DM

5803:   Not collective

5805:   Input Parameter:
5806: . dm - The DM

5808:   Output Parameter:
5809: . dim - The topological dimension

5811:   Level: beginner

5813: .seealso: DMSetDimension(), DMCreate()
5814: @*/
5815: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5816: {
5820:   *dim = dm->dim;
5821:   return(0);
5822: }

5824: /*@
5825:   DMSetDimension - Set the topological dimension of the DM

5827:   Collective on dm

5829:   Input Parameters:
5830: + dm - The DM
5831: - dim - The topological dimension

5833:   Level: beginner

5835: .seealso: DMGetDimension(), DMCreate()
5836: @*/
5837: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5838: {
5839:   PetscDS        ds;

5845:   dm->dim = dim;
5846:   DMGetDS(dm, &ds);
5847:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5848:   return(0);
5849: }

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

5854:   Collective on dm

5856:   Input Parameters:
5857: + dm - the DM
5858: - dim - the dimension

5860:   Output Parameters:
5861: + pStart - The first point of the given dimension
5862: - pEnd - The first point following points of the given dimension

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

5869:   Level: intermediate

5871: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5872: @*/
5873: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5874: {
5875:   PetscInt       d;

5880:   DMGetDimension(dm, &d);
5881:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5882:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5883:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5884:   return(0);
5885: }

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

5890:   Collective on dm

5892:   Input Parameters:
5893: + dm - the DM
5894: - c - coordinate vector

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

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

5901:   Level: intermediate

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

5912:   PetscObjectReference((PetscObject) c);
5913:   VecDestroy(&dm->coordinates);
5914:   dm->coordinates = c;
5915:   VecDestroy(&dm->coordinatesLocal);
5916:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5917:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5918:   return(0);
5919: }

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

5924:   Not collective

5926:    Input Parameters:
5927: +  dm - the DM
5928: -  c - coordinate vector

5930:   Notes:
5931:   The coordinates of ghost points can be set using DMSetCoordinates()
5932:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5933:   setting of ghost coordinates outside of the domain.

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

5937:   Level: intermediate

5939: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5940: @*/
5941: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5942: {

5948:   PetscObjectReference((PetscObject) c);
5949:   VecDestroy(&dm->coordinatesLocal);

5951:   dm->coordinatesLocal = c;

5953:   VecDestroy(&dm->coordinates);
5954:   return(0);
5955: }

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

5960:   Collective on dm

5962:   Input Parameter:
5963: . dm - the DM

5965:   Output Parameter:
5966: . c - global coordinate vector

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

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

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

5976:   Level: intermediate

5978: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5979: @*/
5980: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5981: {

5987:   if (!dm->coordinates && dm->coordinatesLocal) {
5988:     DM        cdm = NULL;
5989:     PetscBool localized;

5991:     DMGetCoordinateDM(dm, &cdm);
5992:     DMCreateGlobalVector(cdm, &dm->coordinates);
5993:     DMGetCoordinatesLocalized(dm, &localized);
5994:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5995:     if (localized) {
5996:       PetscInt cdim;

5998:       DMGetCoordinateDim(dm, &cdim);
5999:       VecSetBlockSize(dm->coordinates, cdim);
6000:     }
6001:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6002:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6003:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6004:   }
6005:   *c = dm->coordinates;
6006:   return(0);
6007: }

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

6012:   Collective on dm

6014:   Input Parameter:
6015: . dm - the DM

6017:   Level: advanced

6019: .seealso: DMGetCoordinatesLocalNoncollective()
6020: @*/
6021: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6022: {

6027:   if (!dm->coordinatesLocal && dm->coordinates) {
6028:     DM        cdm = NULL;
6029:     PetscBool localized;

6031:     DMGetCoordinateDM(dm, &cdm);
6032:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6033:     DMGetCoordinatesLocalized(dm, &localized);
6034:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6035:     if (localized) {
6036:       PetscInt cdim;

6038:       DMGetCoordinateDim(dm, &cdim);
6039:       VecSetBlockSize(dm->coordinates, cdim);
6040:     }
6041:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6042:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6043:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6044:   }
6045:   return(0);
6046: }

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

6051:   Collective on dm

6053:   Input Parameter:
6054: . dm - the DM

6056:   Output Parameter:
6057: . c - coordinate vector

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

6062:   Each process has the local and ghost coordinates

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

6067:   Level: intermediate

6069: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6070: @*/
6071: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6072: {

6078:   DMGetCoordinatesLocalSetUp(dm);
6079:   *c = dm->coordinatesLocal;
6080:   return(0);
6081: }

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

6086:   Not collective

6088:   Input Parameter:
6089: . dm - the DM

6091:   Output Parameter:
6092: . c - coordinate vector

6094:   Level: advanced

6096: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6097: @*/
6098: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6099: {
6103:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6104:   *c = dm->coordinatesLocal;
6105:   return(0);
6106: }

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

6111:   Not collective

6113:   Input Parameter:
6114: + dm - the DM
6115: - p - the IS of points whose coordinates will be returned

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

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

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

6126:   Each process has the local and ghost coordinates

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

6131:   Level: advanced

6133: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6134: @*/
6135: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6136: {
6137:   PetscSection        cs, newcs;
6138:   Vec                 coords;
6139:   const PetscScalar   *arr;
6140:   PetscScalar         *newarr=NULL;
6141:   PetscInt            n;
6142:   PetscErrorCode      ierr;

6149:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6150:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6151:   cs = dm->coordinateDM->localSection;
6152:   coords = dm->coordinatesLocal;
6153:   VecGetArrayRead(coords, &arr);
6154:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6155:   VecRestoreArrayRead(coords, &arr);
6156:   if (pCoord) {
6157:     PetscSectionGetStorageSize(newcs, &n);
6158:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6159:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6160:     VecReplaceArray(*pCoord, newarr);
6161:   } else {
6162:     PetscFree(newarr);
6163:   }
6164:   if (pCoordSection) {*pCoordSection = newcs;}
6165:   else               {PetscSectionDestroy(&newcs);}
6166:   return(0);
6167: }

6169: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6170: {

6176:   if (!dm->coordinateField) {
6177:     if (dm->ops->createcoordinatefield) {
6178:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6179:     }
6180:   }
6181:   *field = dm->coordinateField;
6182:   return(0);
6183: }

6185: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6186: {

6192:   PetscObjectReference((PetscObject)field);
6193:   DMFieldDestroy(&dm->coordinateField);
6194:   dm->coordinateField = field;
6195:   return(0);
6196: }

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

6201:   Collective on dm

6203:   Input Parameter:
6204: . dm - the DM

6206:   Output Parameter:
6207: . cdm - coordinate DM

6209:   Level: intermediate

6211: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6212: @*/
6213: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6214: {

6220:   if (!dm->coordinateDM) {
6221:     DM cdm;

6223:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6224:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6225:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6226:      * until the call to CreateCoordinateDM) */
6227:     DMDestroy(&dm->coordinateDM);
6228:     dm->coordinateDM = cdm;
6229:   }
6230:   *cdm = dm->coordinateDM;
6231:   return(0);
6232: }

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

6237:   Logically Collective on dm

6239:   Input Parameters:
6240: + dm - the DM
6241: - cdm - coordinate DM

6243:   Level: intermediate

6245: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6246: @*/
6247: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6248: {

6254:   PetscObjectReference((PetscObject)cdm);
6255:   DMDestroy(&dm->coordinateDM);
6256:   dm->coordinateDM = cdm;
6257:   return(0);
6258: }

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

6263:   Not Collective

6265:   Input Parameter:
6266: . dm - The DM object

6268:   Output Parameter:
6269: . dim - The embedding dimension

6271:   Level: intermediate

6273: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6274: @*/
6275: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6276: {
6280:   if (dm->dimEmbed == PETSC_DEFAULT) {
6281:     dm->dimEmbed = dm->dim;
6282:   }
6283:   *dim = dm->dimEmbed;
6284:   return(0);
6285: }

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

6290:   Not Collective

6292:   Input Parameters:
6293: + dm  - The DM object
6294: - dim - The embedding dimension

6296:   Level: intermediate

6298: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6299: @*/
6300: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6301: {
6302:   PetscDS        ds;

6307:   dm->dimEmbed = dim;
6308:   DMGetDS(dm, &ds);
6309:   PetscDSSetCoordinateDimension(ds, dim);
6310:   return(0);
6311: }

6313: /*@
6314:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6316:   Collective on dm

6318:   Input Parameter:
6319: . dm - The DM object

6321:   Output Parameter:
6322: . section - The PetscSection object

6324:   Level: intermediate

6326: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6327: @*/
6328: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6329: {
6330:   DM             cdm;

6336:   DMGetCoordinateDM(dm, &cdm);
6337:   DMGetLocalSection(cdm, section);
6338:   return(0);
6339: }

6341: /*@
6342:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6344:   Not Collective

6346:   Input Parameters:
6347: + dm      - The DM object
6348: . dim     - The embedding dimension, or PETSC_DETERMINE
6349: - section - The PetscSection object

6351:   Level: intermediate

6353: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6354: @*/
6355: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6356: {
6357:   DM             cdm;

6363:   DMGetCoordinateDM(dm, &cdm);
6364:   DMSetLocalSection(cdm, section);
6365:   if (dim == PETSC_DETERMINE) {
6366:     PetscInt d = PETSC_DEFAULT;
6367:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6369:     PetscSectionGetChart(section, &pStart, &pEnd);
6370:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6371:     pStart = PetscMax(vStart, pStart);
6372:     pEnd   = PetscMin(vEnd, pEnd);
6373:     for (v = pStart; v < pEnd; ++v) {
6374:       PetscSectionGetDof(section, v, &dd);
6375:       if (dd) {d = dd; break;}
6376:     }
6377:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6378:   }
6379:   return(0);
6380: }

6382: /*@
6383:   DMProjectCoordinates - Project coordinates to a different space

6385:   Input Parameters:
6386: + dm      - The DM object
6387: - disc    - The new coordinate discretization

6389:   Level: intermediate

6391: .seealso: DMGetCoordinateField()
6392: @*/
6393: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6394: {
6395:   PetscObject    discOld;
6396:   PetscClassId   classid;
6397:   DM             cdmOld,cdmNew;
6398:   Vec            coordsOld,coordsNew;
6399:   Mat            matInterp;


6406:   DMGetCoordinateDM(dm, &cdmOld);
6407:   /* Check current discretization is compatible */
6408:   DMGetField(cdmOld, 0, NULL, &discOld);
6409:   PetscObjectGetClassId(discOld, &classid);
6410:   if (classid != PETSCFE_CLASSID) {
6411:     if (classid == PETSC_CONTAINER_CLASSID) {
6412:       PetscFE        feLinear;
6413:       DMPolytopeType ct;
6414:       PetscInt       dim, dE, cStart;
6415:       PetscBool      simplex;

6417:       /* Assume linear vertex coordinates */
6418:       DMGetDimension(dm, &dim);
6419:       DMGetCoordinateDim(dm, &dE);
6420:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
6421:       DMPlexGetCellType(dm, cStart, &ct);
6422:       switch (ct) {
6423:         case DM_POLYTOPE_TRI_PRISM:
6424:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6425:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6426:         default: break;
6427:       }
6428:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6429:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6430:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6431:       PetscFEDestroy(&feLinear);
6432:       DMCreateDS(cdmOld);
6433:     } else {
6434:       const char *discname;

6436:       PetscObjectGetType(discOld, &discname);
6437:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6438:     }
6439:   }
6440:   /* Make a fresh clone of the coordinate DM */
6441:   DMClone(cdmOld, &cdmNew);
6442:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6443:   DMCreateDS(cdmNew);
6444:   /* Project the coordinate vector from old to new space  */
6445:   DMGetCoordinates(dm, &coordsOld);
6446:   DMCreateGlobalVector(cdmNew, &coordsNew);
6447:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6448:   MatInterpolate(matInterp, coordsOld, coordsNew);
6449:   MatDestroy(&matInterp);
6450:   /* Set new coordinate structures */
6451:   DMSetCoordinateField(dm, NULL);
6452:   DMSetCoordinateDM(dm, cdmNew);
6453:   DMSetCoordinates(dm, coordsNew);
6454:   VecDestroy(&coordsNew);
6455:   DMDestroy(&cdmNew);
6456:   return(0);
6457: }

6459: /*@C
6460:   DMGetPeriodicity - Get the description of mesh periodicity

6462:   Input Parameters:
6463: . dm      - The DM object

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

6471:   Level: developer

6473: .seealso: DMGetPeriodicity()
6474: @*/
6475: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6476: {
6479:   if (per)     *per     = dm->periodic;
6480:   if (L)       *L       = dm->L;
6481:   if (maxCell) *maxCell = dm->maxCell;
6482:   if (bd)      *bd      = dm->bdtype;
6483:   return(0);
6484: }

6486: /*@C
6487:   DMSetPeriodicity - Set the description of mesh periodicity

6489:   Input Parameters:
6490: + dm      - The DM object
6491: . per     - Whether the DM is periodic or not.
6492: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
6493: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6494: - bd      - This describes the type of periodicity in each topological dimension

6496:   Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.

6498:   Level: developer

6500: .seealso: DMGetPeriodicity()
6501: @*/
6502: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6503: {
6504:   PetscInt       dim, d;

6513:   DMGetDimension(dm, &dim);
6514:   if (maxCell) {
6515:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6516:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6517:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6518:     PetscFree(dm->maxCell);
6519:   }

6521:   if (L) {
6522:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6523:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6524:   }
6525:   if (bd) {
6526:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6527:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6528:   }
6529:   dm->periodic = per;
6530:   return(0);
6531: }

6533: /*@
6534:   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.

6536:   Input Parameters:
6537: + dm     - The DM
6538: . in     - The input coordinate point (dim numbers)
6539: - endpoint - Include the endpoint L_i

6541:   Output Parameter:
6542: . out - The localized coordinate point

6544:   Level: developer

6546: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6547: @*/
6548: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6549: {
6550:   PetscInt       dim, d;

6554:   DMGetCoordinateDim(dm, &dim);
6555:   if (!dm->maxCell) {
6556:     for (d = 0; d < dim; ++d) out[d] = in[d];
6557:   } else {
6558:     if (endpoint) {
6559:       for (d = 0; d < dim; ++d) {
6560:         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)) {
6561:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6562:         } else {
6563:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6564:         }
6565:       }
6566:     } else {
6567:       for (d = 0; d < dim; ++d) {
6568:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6569:       }
6570:     }
6571:   }
6572:   return(0);
6573: }

6575: /*
6576:   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.

6578:   Input Parameters:
6579: + dm     - The DM
6580: . dim    - The spatial dimension
6581: . anchor - The anchor point, the input point can be no more than maxCell away from it
6582: - in     - The input coordinate point (dim numbers)

6584:   Output Parameter:
6585: . out - The localized coordinate point

6587:   Level: developer

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

6591: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6592: */
6593: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6594: {
6595:   PetscInt d;

6598:   if (!dm->maxCell) {
6599:     for (d = 0; d < dim; ++d) out[d] = in[d];
6600:   } else {
6601:     for (d = 0; d < dim; ++d) {
6602:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6603:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6604:       } else {
6605:         out[d] = in[d];
6606:       }
6607:     }
6608:   }
6609:   return(0);
6610: }

6612: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6613: {
6614:   PetscInt d;

6617:   if (!dm->maxCell) {
6618:     for (d = 0; d < dim; ++d) out[d] = in[d];
6619:   } else {
6620:     for (d = 0; d < dim; ++d) {
6621:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6622:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6623:       } else {
6624:         out[d] = in[d];
6625:       }
6626:     }
6627:   }
6628:   return(0);
6629: }

6631: /*
6632:   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.

6634:   Input Parameters:
6635: + dm     - The DM
6636: . dim    - The spatial dimension
6637: . anchor - The anchor point, the input point can be no more than maxCell away from it
6638: . in     - The input coordinate delta (dim numbers)
6639: - out    - The input coordinate point (dim numbers)

6641:   Output Parameter:
6642: . out    - The localized coordinate in + out

6644:   Level: developer

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

6648: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6649: */
6650: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6651: {
6652:   PetscInt d;

6655:   if (!dm->maxCell) {
6656:     for (d = 0; d < dim; ++d) out[d] += in[d];
6657:   } else {
6658:     for (d = 0; d < dim; ++d) {
6659:       const PetscReal maxC = dm->maxCell[d];

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

6664:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6665:           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]));
6666:         out[d] += newCoord;
6667:       } else {
6668:         out[d] += in[d];
6669:       }
6670:     }
6671:   }
6672:   return(0);
6673: }

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

6678:   Not collective

6680:   Input Parameter:
6681: . dm - The DM

6683:   Output Parameter:
6684:   areLocalized - True if localized

6686:   Level: developer

6688: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6689: @*/
6690: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6691: {
6692:   DM             cdm;
6693:   PetscSection   coordSection;
6694:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6695:   PetscBool      isPlex, alreadyLocalized;

6701:   *areLocalized = PETSC_FALSE;

6703:   /* We need some generic way of refering to cells/vertices */
6704:   DMGetCoordinateDM(dm, &cdm);
6705:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6706:   if (!isPlex) return(0);

6708:   DMGetCoordinateSection(dm, &coordSection);
6709:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6710:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6711:   alreadyLocalized = PETSC_FALSE;
6712:   for (c = cStart; c < cEnd; ++c) {
6713:     if (c < sStart || c >= sEnd) continue;
6714:     PetscSectionGetDof(coordSection, c, &dof);
6715:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6716:   }
6717:   *areLocalized = alreadyLocalized;
6718:   return(0);
6719: }

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

6724:   Collective on dm

6726:   Input Parameter:
6727: . dm - The DM

6729:   Output Parameter:
6730:   areLocalized - True if localized

6732:   Level: developer

6734: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6735: @*/
6736: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6737: {
6738:   PetscBool      localized;

6744:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6745:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6746:   return(0);
6747: }

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

6752:   Collective on dm

6754:   Input Parameter:
6755: . dm - The DM

6757:   Level: developer

6759: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6760: @*/
6761: PetscErrorCode DMLocalizeCoordinates(DM dm)
6762: {
6763:   DM             cdm;
6764:   PetscSection   coordSection, cSection;
6765:   Vec            coordinates,  cVec;
6766:   PetscScalar   *coords, *coords2, *anchor, *localized;
6767:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6768:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6769:   PetscInt       maxHeight = 0, h;
6770:   PetscInt       *pStart = NULL, *pEnd = NULL;

6775:   if (!dm->periodic) return(0);
6776:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6777:   if (alreadyLocalized) return(0);

6779:   /* We need some generic way of refering to cells/vertices */
6780:   DMGetCoordinateDM(dm, &cdm);
6781:   {
6782:     PetscBool isplex;

6784:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6785:     if (isplex) {
6786:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6787:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6788:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6789:       pEnd = &pStart[maxHeight + 1];
6790:       newStart = vStart;
6791:       newEnd   = vEnd;
6792:       for (h = 0; h <= maxHeight; h++) {
6793:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6794:         newStart = PetscMin(newStart,pStart[h]);
6795:         newEnd   = PetscMax(newEnd,pEnd[h]);
6796:       }
6797:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6798:   }
6799:   DMGetCoordinatesLocal(dm, &coordinates);
6800:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6801:   DMGetCoordinateSection(dm, &coordSection);
6802:   VecGetBlockSize(coordinates, &bs);
6803:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6805:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6806:   PetscSectionSetNumFields(cSection, 1);
6807:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6808:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6809:   PetscSectionSetChart(cSection, newStart, newEnd);

6811:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6812:   localized = &anchor[bs];
6813:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6814:   for (h = 0; h <= maxHeight; h++) {
6815:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6817:     for (c = cStart; c < cEnd; ++c) {
6818:       PetscScalar *cellCoords = NULL;
6819:       PetscInt     b;

6821:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6822:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6823:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6824:       for (d = 0; d < dof/bs; ++d) {
6825:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6826:         for (b = 0; b < bs; b++) {
6827:           if (cellCoords[d*bs + b] != localized[b]) break;
6828:         }
6829:         if (b < bs) break;
6830:       }
6831:       if (d < dof/bs) {
6832:         if (c >= sStart && c < sEnd) {
6833:           PetscInt cdof;

6835:           PetscSectionGetDof(coordSection, c, &cdof);
6836:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6837:         }
6838:         PetscSectionSetDof(cSection, c, dof);
6839:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6840:       }
6841:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6842:     }
6843:   }
6844:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6845:   if (alreadyLocalizedGlobal) {
6846:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6847:     PetscSectionDestroy(&cSection);
6848:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6849:     return(0);
6850:   }
6851:   for (v = vStart; v < vEnd; ++v) {
6852:     PetscSectionGetDof(coordSection, v, &dof);
6853:     PetscSectionSetDof(cSection, v, dof);
6854:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6855:   }
6856:   PetscSectionSetUp(cSection);
6857:   PetscSectionGetStorageSize(cSection, &coordSize);
6858:   VecCreate(PETSC_COMM_SELF, &cVec);
6859:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6860:   VecSetBlockSize(cVec, bs);
6861:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6862:   VecSetType(cVec, VECSTANDARD);
6863:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6864:   VecGetArray(cVec, &coords2);
6865:   for (v = vStart; v < vEnd; ++v) {
6866:     PetscSectionGetDof(coordSection, v, &dof);
6867:     PetscSectionGetOffset(coordSection, v, &off);
6868:     PetscSectionGetOffset(cSection,     v, &off2);
6869:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6870:   }
6871:   for (h = 0; h <= maxHeight; h++) {
6872:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6874:     for (c = cStart; c < cEnd; ++c) {
6875:       PetscScalar *cellCoords = NULL;
6876:       PetscInt     b, cdof;

6878:       PetscSectionGetDof(cSection,c,&cdof);
6879:       if (!cdof) continue;
6880:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6881:       PetscSectionGetOffset(cSection, c, &off2);
6882:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6883:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6884:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6885:     }
6886:   }
6887:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6888:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6889:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6890:   VecRestoreArray(cVec, &coords2);
6891:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6892:   DMSetCoordinatesLocal(dm, cVec);
6893:   VecDestroy(&cVec);
6894:   PetscSectionDestroy(&cSection);
6895:   return(0);
6896: }

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

6901:   Collective on v (see explanation below)

6903:   Input Parameters:
6904: + dm - The DM
6905: . v - The Vec of points
6906: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6907: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6909:   Output Parameter:
6910: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6911: - cells - The PetscSF containing the ranks and local indices of the containing points.


6914:   Level: developer

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

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

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

6925: $    const PetscSFNode *cells;
6926: $    PetscInt           nFound;
6927: $    const PetscInt    *found;
6928: $
6929: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

6934: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6935: @*/
6936: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6937: {

6944:   if (*cellSF) {
6945:     PetscMPIInt result;

6948:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6949:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6950:   } else {
6951:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6952:   }
6953:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6954:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6955:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6956:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6957:   return(0);
6958: }

6960: /*@
6961:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6963:   Collective on dm

6965:   Input Parameter:
6966: . dm - The original DM

6968:   Output Parameter:
6969: . odm - The DM which provides the layout for output

6971:   Level: intermediate

6973: .seealso: VecView(), DMGetGlobalSection()
6974: @*/
6975: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6976: {
6977:   PetscSection   section;
6978:   PetscBool      hasConstraints, ghasConstraints;

6984:   DMGetLocalSection(dm, &section);
6985:   PetscSectionHasConstraints(section, &hasConstraints);
6986:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6987:   if (!ghasConstraints) {
6988:     *odm = dm;
6989:     return(0);
6990:   }
6991:   if (!dm->dmBC) {
6992:     PetscSection newSection, gsection;
6993:     PetscSF      sf;

6995:     DMClone(dm, &dm->dmBC);
6996:     DMCopyDisc(dm, dm->dmBC);
6997:     PetscSectionClone(section, &newSection);
6998:     DMSetLocalSection(dm->dmBC, newSection);
6999:     PetscSectionDestroy(&newSection);
7000:     DMGetPointSF(dm->dmBC, &sf);
7001:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7002:     DMSetGlobalSection(dm->dmBC, gsection);
7003:     PetscSectionDestroy(&gsection);
7004:   }
7005:   *odm = dm->dmBC;
7006:   return(0);
7007: }

7009: /*@
7010:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7012:   Input Parameter:
7013: . dm - The original DM

7015:   Output Parameters:
7016: + num - The output sequence number
7017: - val - The output sequence value

7019:   Level: intermediate

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

7024: .seealso: VecView()
7025: @*/
7026: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7027: {
7032:   return(0);
7033: }

7035: /*@
7036:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7038:   Input Parameters:
7039: + dm - The original DM
7040: . num - The output sequence number
7041: - val - The output sequence value

7043:   Level: intermediate

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

7048: .seealso: VecView()
7049: @*/
7050: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7051: {
7054:   dm->outputSequenceNum = num;
7055:   dm->outputSequenceVal = val;
7056:   return(0);
7057: }

7059: /*@C
7060:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7062:   Input Parameters:
7063: + dm   - The original DM
7064: . name - The sequence name
7065: - num  - The output sequence number

7067:   Output Parameter:
7068: . val  - The output sequence value

7070:   Level: intermediate

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

7075: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7076: @*/
7077: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7078: {
7079:   PetscBool      ishdf5;

7086:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7087:   if (ishdf5) {
7088: #if defined(PETSC_HAVE_HDF5)
7089:     PetscScalar value;

7091:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7092:     *val = PetscRealPart(value);
7093: #endif
7094:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7095:   return(0);
7096: }

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

7101:   Not collective

7103:   Input Parameter:
7104: . dm - The DM

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

7109:   Level: beginner

7111: .seealso: DMSetUseNatural(), DMCreate()
7112: @*/
7113: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7114: {
7118:   *useNatural = dm->useNatural;
7119:   return(0);
7120: }

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

7125:   Collective on dm

7127:   Input Parameters:
7128: + dm - The DM
7129: - useNatural - The flag to build the mapping to a natural order during distribution

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

7133:   Level: beginner

7135: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7136: @*/
7137: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7138: {
7142:   dm->useNatural = useNatural;
7143:   return(0);
7144: }


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

7150:   Not Collective

7152:   Input Parameters:
7153: + dm   - The DM object
7154: - name - The label name

7156:   Level: intermediate

7158: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7159: @*/
7160: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7161: {
7162:   PetscBool      flg;
7163:   DMLabel        label;

7169:   DMHasLabel(dm, name, &flg);
7170:   if (!flg) {
7171:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7172:     DMAddLabel(dm, label);
7173:     DMLabelDestroy(&label);
7174:   }
7175:   return(0);
7176: }

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

7181:   Not Collective

7183:   Input Parameters:
7184: + dm   - The DM object
7185: . l    - The index for the label
7186: - name - The label name

7188:   Level: intermediate

7190: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7191: @*/
7192: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7193: {
7194:   DMLabelLink    orig, prev = NULL;
7195:   DMLabel        label;
7196:   PetscInt       Nl, m;
7197:   PetscBool      flg, match;
7198:   const char    *lname;

7204:   DMHasLabel(dm, name, &flg);
7205:   if (!flg) {
7206:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7207:     DMAddLabel(dm, label);
7208:     DMLabelDestroy(&label);
7209:   }
7210:   DMGetNumLabels(dm, &Nl);
7211:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7212:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7213:     PetscObjectGetName((PetscObject) orig->label, &lname);
7214:     PetscStrcmp(name, lname, &match);
7215:     if (match) break;
7216:   }
7217:   if (m == l) return(0);
7218:   if (!m) dm->labels = orig->next;
7219:   else    prev->next = orig->next;
7220:   if (!l) {
7221:     orig->next = dm->labels;
7222:     dm->labels = orig;
7223:   } else {
7224:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7225:     orig->next = prev->next;
7226:     prev->next = orig;
7227:   }
7228:   return(0);
7229: }

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

7234:   Not Collective

7236:   Input Parameters:
7237: + dm   - The DM object
7238: . name - The label name
7239: - point - The mesh point

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

7244:   Level: beginner

7246: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7247: @*/
7248: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7249: {
7250:   DMLabel        label;

7256:   DMGetLabel(dm, name, &label);
7257:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7258:   DMLabelGetValue(label, point, value);
7259:   return(0);
7260: }

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

7265:   Not Collective

7267:   Input Parameters:
7268: + dm   - The DM object
7269: . name - The label name
7270: . point - The mesh point
7271: - value - The label value for this point

7273:   Output Parameter:

7275:   Level: beginner

7277: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7278: @*/
7279: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7280: {
7281:   DMLabel        label;

7287:   DMGetLabel(dm, name, &label);
7288:   if (!label) {
7289:     DMCreateLabel(dm, name);
7290:     DMGetLabel(dm, name, &label);
7291:   }
7292:   DMLabelSetValue(label, point, value);
7293:   return(0);
7294: }

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

7299:   Not Collective

7301:   Input Parameters:
7302: + dm   - The DM object
7303: . name - The label name
7304: . point - The mesh point
7305: - value - The label value for this point

7307:   Output Parameter:

7309:   Level: beginner

7311: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7312: @*/
7313: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7314: {
7315:   DMLabel        label;

7321:   DMGetLabel(dm, name, &label);
7322:   if (!label) return(0);
7323:   DMLabelClearValue(label, point, value);
7324:   return(0);
7325: }

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

7330:   Not Collective

7332:   Input Parameters:
7333: + dm   - The DM object
7334: - name - The label name

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

7339:   Level: beginner

7341: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7342: @*/
7343: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7344: {
7345:   DMLabel        label;

7352:   DMGetLabel(dm, name, &label);
7353:   *size = 0;
7354:   if (!label) return(0);
7355:   DMLabelGetNumValues(label, size);
7356:   return(0);
7357: }

7359: /*@C
7360:   DMGetLabelIdIS - Get the integer ids in a label

7362:   Not Collective

7364:   Input Parameters:
7365: + mesh - The DM object
7366: - name - The label name

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

7371:   Level: beginner

7373: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7374: @*/
7375: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7376: {
7377:   DMLabel        label;

7384:   DMGetLabel(dm, name, &label);
7385:   *ids = NULL;
7386:  if (label) {
7387:     DMLabelGetValueIS(label, ids);
7388:   } else {
7389:     /* returning an empty IS */
7390:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7391:   }
7392:   return(0);
7393: }

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

7398:   Not Collective

7400:   Input Parameters:
7401: + dm - The DM object
7402: . name - The label name
7403: - value - The stratum value

7405:   Output Parameter:
7406: . size - The stratum size

7408:   Level: beginner

7410: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7411: @*/
7412: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7413: {
7414:   DMLabel        label;

7421:   DMGetLabel(dm, name, &label);
7422:   *size = 0;
7423:   if (!label) return(0);
7424:   DMLabelGetStratumSize(label, value, size);
7425:   return(0);
7426: }

7428: /*@C
7429:   DMGetStratumIS - Get the points in a label stratum

7431:   Not Collective

7433:   Input Parameters:
7434: + dm - The DM object
7435: . name - The label name
7436: - value - The stratum value

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

7441:   Level: beginner

7443: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7444: @*/
7445: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7446: {
7447:   DMLabel        label;

7454:   DMGetLabel(dm, name, &label);
7455:   *points = NULL;
7456:   if (!label) return(0);
7457:   DMLabelGetStratumIS(label, value, points);
7458:   return(0);
7459: }

7461: /*@C
7462:   DMSetStratumIS - Set the points in a label stratum

7464:   Not Collective

7466:   Input Parameters:
7467: + dm - The DM object
7468: . name - The label name
7469: . value - The stratum value
7470: - points - The stratum points

7472:   Level: beginner

7474: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7475: @*/
7476: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7477: {
7478:   DMLabel        label;

7485:   DMGetLabel(dm, name, &label);
7486:   if (!label) return(0);
7487:   DMLabelSetStratumIS(label, value, points);
7488:   return(0);
7489: }

7491: /*@C
7492:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7494:   Not Collective

7496:   Input Parameters:
7497: + dm   - The DM object
7498: . name - The label name
7499: - value - The label value for this point

7501:   Output Parameter:

7503:   Level: beginner

7505: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7506: @*/
7507: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7508: {
7509:   DMLabel        label;

7515:   DMGetLabel(dm, name, &label);
7516:   if (!label) return(0);
7517:   DMLabelClearStratum(label, value);
7518:   return(0);
7519: }

7521: /*@
7522:   DMGetNumLabels - Return the number of labels defined by the mesh

7524:   Not Collective

7526:   Input Parameter:
7527: . dm   - The DM object

7529:   Output Parameter:
7530: . numLabels - the number of Labels

7532:   Level: intermediate

7534: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7535: @*/
7536: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7537: {
7538:   DMLabelLink next = dm->labels;
7539:   PetscInt  n    = 0;

7544:   while (next) {++n; next = next->next;}
7545:   *numLabels = n;
7546:   return(0);
7547: }

7549: /*@C
7550:   DMGetLabelName - Return the name of nth label

7552:   Not Collective

7554:   Input Parameters:
7555: + dm - The DM object
7556: - n  - the label number

7558:   Output Parameter:
7559: . name - the label name

7561:   Level: intermediate

7563: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7564: @*/
7565: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7566: {
7567:   DMLabelLink    next = dm->labels;
7568:   PetscInt       l    = 0;

7574:   while (next) {
7575:     if (l == n) {
7576:       PetscObjectGetName((PetscObject) next->label, name);
7577:       return(0);
7578:     }
7579:     ++l;
7580:     next = next->next;
7581:   }
7582:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7583: }

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

7588:   Not Collective

7590:   Input Parameters:
7591: + dm   - The DM object
7592: - name - The label name

7594:   Output Parameter:
7595: . hasLabel - PETSC_TRUE if the label is present

7597:   Level: intermediate

7599: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7600: @*/
7601: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7602: {
7603:   DMLabelLink    next = dm->labels;
7604:   const char    *lname;

7611:   *hasLabel = PETSC_FALSE;
7612:   while (next) {
7613:     PetscObjectGetName((PetscObject) next->label, &lname);
7614:     PetscStrcmp(name, lname, hasLabel);
7615:     if (*hasLabel) break;
7616:     next = next->next;
7617:   }
7618:   return(0);
7619: }

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

7624:   Not Collective

7626:   Input Parameters:
7627: + dm   - The DM object
7628: - name - The label name

7630:   Output Parameter:
7631: . label - The DMLabel, or NULL if the label is absent

7633:   Level: intermediate

7635: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7636: @*/
7637: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7638: {
7639:   DMLabelLink    next = dm->labels;
7640:   PetscBool      hasLabel;
7641:   const char    *lname;

7648:   *label = NULL;
7649:   while (next) {
7650:     PetscObjectGetName((PetscObject) next->label, &lname);
7651:     PetscStrcmp(name, lname, &hasLabel);
7652:     if (hasLabel) {
7653:       *label = next->label;
7654:       break;
7655:     }
7656:     next = next->next;
7657:   }
7658:   return(0);
7659: }

7661: /*@C
7662:   DMGetLabelByNum - Return the nth label

7664:   Not Collective

7666:   Input Parameters:
7667: + dm - The DM object
7668: - n  - the label number

7670:   Output Parameter:
7671: . label - the label

7673:   Level: intermediate

7675: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7676: @*/
7677: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7678: {
7679:   DMLabelLink next = dm->labels;
7680:   PetscInt    l    = 0;

7685:   while (next) {
7686:     if (l == n) {
7687:       *label = next->label;
7688:       return(0);
7689:     }
7690:     ++l;
7691:     next = next->next;
7692:   }
7693:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7694: }

7696: /*@C
7697:   DMAddLabel - Add the label to this mesh

7699:   Not Collective

7701:   Input Parameters:
7702: + dm   - The DM object
7703: - label - The DMLabel

7705:   Level: developer

7707: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7708: @*/
7709: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7710: {
7711:   DMLabelLink    l, *p, tmpLabel;
7712:   PetscBool      hasLabel;
7713:   const char    *lname;
7714:   PetscBool      flg;

7719:   PetscObjectGetName((PetscObject) label, &lname);
7720:   DMHasLabel(dm, lname, &hasLabel);
7721:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7722:   PetscCalloc1(1, &tmpLabel);
7723:   tmpLabel->label  = label;
7724:   tmpLabel->output = PETSC_TRUE;
7725:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7726:   *p = tmpLabel;
7727:   PetscObjectReference((PetscObject)label);
7728:   PetscStrcmp(lname, "depth", &flg);
7729:   if (flg) dm->depthLabel = label;
7730:   PetscStrcmp(lname, "celltype", &flg);
7731:   if (flg) dm->celltypeLabel = label;
7732:   return(0);
7733: }

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

7738:   Not Collective

7740:   Input Parameters:
7741: + dm   - The DM object
7742: - name - The label name

7744:   Output Parameter:
7745: . label - The DMLabel, or NULL if the label is absent

7747:   Level: developer

7749:   Notes:
7750:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7751:   DMLabelDestroy() on the label.

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

7757: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7758: @*/
7759: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7760: {
7761:   DMLabelLink    link, *pnext;
7762:   PetscBool      hasLabel;
7763:   const char    *lname;

7769:   if (label) {
7771:     *label = NULL;
7772:   }
7773:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7774:     PetscObjectGetName((PetscObject) link->label, &lname);
7775:     PetscStrcmp(name, lname, &hasLabel);
7776:     if (hasLabel) {
7777:       *pnext = link->next; /* Remove from list */
7778:       PetscStrcmp(name, "depth", &hasLabel);
7779:       if (hasLabel) dm->depthLabel = NULL;
7780:       PetscStrcmp(name, "celltype", &hasLabel);
7781:       if (hasLabel) dm->celltypeLabel = NULL;
7782:       if (label) *label = link->label;
7783:       else       {DMLabelDestroy(&link->label);}
7784:       PetscFree(link);
7785:       break;
7786:     }
7787:   }
7788:   return(0);
7789: }

7791: /*@
7792:   DMRemoveLabelBySelf - Remove the label from this mesh

7794:   Not Collective

7796:   Input Parameters:
7797: + dm   - The DM object
7798: . label - (Optional) The DMLabel to be removed from the DM
7799: - failNotFound - Should it fail if the label is not found in the DM?

7801:   Level: developer

7803:   Notes:
7804:   Only exactly the same instance is removed if found, name match is ignored.
7805:   If the DM has an exclusive reference to the label, it gets destroyed and
7806:   *label nullified.

7808: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7809: @*/
7810: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7811: {
7812:   DMLabelLink    link, *pnext;
7813:   PetscBool      hasLabel = PETSC_FALSE;

7819:   if (!*label && !failNotFound) return(0);
7822:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7823:     if (*label == link->label) {
7824:       hasLabel = PETSC_TRUE;
7825:       *pnext = link->next; /* Remove from list */
7826:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7827:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7828:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7829:       DMLabelDestroy(&link->label);
7830:       PetscFree(link);
7831:       break;
7832:     }
7833:   }
7834:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7835:   return(0);
7836: }

7838: /*@C
7839:   DMGetLabelOutput - Get the output flag for a given label

7841:   Not Collective

7843:   Input Parameters:
7844: + dm   - The DM object
7845: - name - The label name

7847:   Output Parameter:
7848: . output - The flag for output

7850:   Level: developer

7852: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7853: @*/
7854: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7855: {
7856:   DMLabelLink    next = dm->labels;
7857:   const char    *lname;

7864:   while (next) {
7865:     PetscBool flg;

7867:     PetscObjectGetName((PetscObject) next->label, &lname);
7868:     PetscStrcmp(name, lname, &flg);
7869:     if (flg) {*output = next->output; return(0);}
7870:     next = next->next;
7871:   }
7872:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7873: }

7875: /*@C
7876:   DMSetLabelOutput - Set the output flag for a given label

7878:   Not Collective

7880:   Input Parameters:
7881: + dm     - The DM object
7882: . name   - The label name
7883: - output - The flag for output

7885:   Level: developer

7887: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7888: @*/
7889: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7890: {
7891:   DMLabelLink    next = dm->labels;
7892:   const char    *lname;

7898:   while (next) {
7899:     PetscBool flg;

7901:     PetscObjectGetName((PetscObject) next->label, &lname);
7902:     PetscStrcmp(name, lname, &flg);
7903:     if (flg) {next->output = output; return(0);}
7904:     next = next->next;
7905:   }
7906:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7907: }

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

7912:   Collective on dmA

7914:   Input Parameter:
7915: + dmA - The DM object with initial labels
7916: . dmB - The DM object with copied labels
7917: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7918: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7920:   Level: intermediate

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

7924: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7925: @*/
7926: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7927: {
7928:   DMLabel        label, labelNew;
7929:   const char    *name;
7930:   PetscBool      flg;
7931:   DMLabelLink    link;

7939:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7940:   if (dmA == dmB) return(0);
7941:   for (link=dmA->labels; link; link=link->next) {
7942:     label=link->label;
7943:     PetscObjectGetName((PetscObject)label, &name);
7944:     if (!all) {
7945:       PetscStrcmp(name, "depth", &flg);
7946:       if (flg) continue;
7947:       PetscStrcmp(name, "dim", &flg);
7948:       if (flg) continue;
7949:       PetscStrcmp(name, "celltype", &flg);
7950:       if (flg) continue;
7951:     }
7952:     if (mode==PETSC_COPY_VALUES) {
7953:       DMLabelDuplicate(label, &labelNew);
7954:     } else {
7955:       labelNew = label;
7956:     }
7957:     DMAddLabel(dmB, labelNew);
7958:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7959:   }
7960:   return(0);
7961: }
7962: /*
7963:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7964:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7965:   (label, id) pair in the DM.

7967:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7968:   each label.
7969: */
7970: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7971: {
7972:   DMUniversalLabel ul;
7973:   PetscBool       *active;
7974:   PetscInt         pStart, pEnd, p, Nl, l, m;
7975:   PetscErrorCode   ierr;

7978:   PetscMalloc1(1, &ul);
7979:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
7980:   DMGetNumLabels(dm, &Nl);
7981:   PetscCalloc1(Nl, &active);
7982:   ul->Nl = 0;
7983:   for (l = 0; l < Nl; ++l) {
7984:     PetscBool   isdepth, iscelltype;
7985:     const char *name;

7987:     DMGetLabelName(dm, l, &name);
7988:     PetscStrncmp(name, "depth", 6, &isdepth);
7989:     PetscStrncmp(name, "celltype", 9, &iscelltype);
7990:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7991:     if (active[l]) ++ul->Nl;
7992:   }
7993:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
7994:   ul->Nv = 0;
7995:   for (l = 0, m = 0; l < Nl; ++l) {
7996:     DMLabel     label;
7997:     PetscInt    nv;
7998:     const char *name;

8000:     if (!active[l]) continue;
8001:     DMGetLabelName(dm, l, &name);
8002:     DMGetLabelByNum(dm, l, &label);
8003:     DMLabelGetNumValues(label, &nv);
8004:     PetscStrallocpy(name, &ul->names[m]);
8005:     ul->indices[m]   = l;
8006:     ul->Nv          += nv;
8007:     ul->offsets[m+1] = nv;
8008:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8009:     ++m;
8010:   }
8011:   for (l = 1; l <= ul->Nl; ++l) {
8012:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8013:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8014:   }
8015:   for (l = 0; l < ul->Nl; ++l) {
8016:     PetscInt b;

8018:     ul->masks[l] = 0;
8019:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8020:   }
8021:   PetscMalloc1(ul->Nv, &ul->values);
8022:   for (l = 0, m = 0; l < Nl; ++l) {
8023:     DMLabel         label;
8024:     IS              valueIS;
8025:     const PetscInt *varr;
8026:     PetscInt        nv, v;

8028:     if (!active[l]) continue;
8029:     DMGetLabelByNum(dm, l, &label);
8030:     DMLabelGetNumValues(label, &nv);
8031:     DMLabelGetValueIS(label, &valueIS);
8032:     ISGetIndices(valueIS, &varr);
8033:     for (v = 0; v < nv; ++v) {
8034:       ul->values[ul->offsets[m]+v] = varr[v];
8035:     }
8036:     ISRestoreIndices(valueIS, &varr);
8037:     ISDestroy(&valueIS);
8038:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8039:     ++m;
8040:   }
8041:   DMPlexGetChart(dm, &pStart, &pEnd);
8042:   for (p = pStart; p < pEnd; ++p) {
8043:     PetscInt  uval = 0;
8044:     PetscBool marked = PETSC_FALSE;

8046:     for (l = 0, m = 0; l < Nl; ++l) {
8047:       DMLabel  label;
8048:       PetscInt val, defval, loc, nv = ul->offsets[m+1]-ul->offsets[m];

8050:       if (!active[l]) continue;
8051:       DMGetLabelByNum(dm, l, &label);
8052:       DMLabelGetValue(label, p, &val);
8053:       DMLabelGetDefaultValue(label, &defval);
8054:       if (val == defval) {++m; continue;}
8055:       marked = PETSC_TRUE;
8056:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8057:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8058:       uval += (loc+1) << ul->bits[m];
8059:       ++m;
8060:     }
8061:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
8062:   }
8063:   PetscFree(active);
8064:   *universal = ul;
8065:   return(0);
8066: }

8068: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8069: {
8070:   PetscInt       l;

8074:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
8075:   DMLabelDestroy(&(*universal)->label);
8076:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8077:   PetscFree((*universal)->values);
8078:   PetscFree(*universal);
8079:   *universal = NULL;
8080:   return(0);
8081: }

8083: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8084: {
8087:   *ulabel = ul->label;
8088:   return(0);
8089: }

8091: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8092: {
8093:   PetscInt       Nl = ul->Nl, l;

8098:   for (l = 0; l < Nl; ++l) {
8099:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
8100:     else               {DMCreateLabel(dm, ul->names[l]);}
8101:   }
8102:   if (preserveOrder) {
8103:     for (l = 0; l < ul->Nl; ++l) {
8104:       const char *name;
8105:       PetscBool   match;

8107:       DMGetLabelName(dm, ul->indices[l], &name);
8108:       PetscStrcmp(name, ul->names[l], &match);
8109:       if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8110:     }
8111:   }
8112:   return(0);
8113: }

8115: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8116: {
8117:   PetscInt       l;

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

8125:     if (lval) {
8126:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
8127:       else          {DMGetLabel(dm, ul->names[l], &label);}
8128:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8129:     }
8130:   }
8131:   return(0);
8132: }

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

8137:   Input Parameter:
8138: . dm - The DM object

8140:   Output Parameter:
8141: . cdm - The coarse DM

8143:   Level: intermediate

8145: .seealso: DMSetCoarseDM()
8146: @*/
8147: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8148: {
8152:   *cdm = dm->coarseMesh;
8153:   return(0);
8154: }

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

8159:   Input Parameters:
8160: + dm - The DM object
8161: - cdm - The coarse DM

8163:   Level: intermediate

8165: .seealso: DMGetCoarseDM()
8166: @*/
8167: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8168: {

8174:   PetscObjectReference((PetscObject)cdm);
8175:   DMDestroy(&dm->coarseMesh);
8176:   dm->coarseMesh = cdm;
8177:   return(0);
8178: }

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

8183:   Input Parameter:
8184: . dm - The DM object

8186:   Output Parameter:
8187: . fdm - The fine DM

8189:   Level: intermediate

8191: .seealso: DMSetFineDM()
8192: @*/
8193: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8194: {
8198:   *fdm = dm->fineMesh;
8199:   return(0);
8200: }

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

8205:   Input Parameters:
8206: + dm - The DM object
8207: - fdm - The fine DM

8209:   Level: intermediate

8211: .seealso: DMGetFineDM()
8212: @*/
8213: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8214: {

8220:   PetscObjectReference((PetscObject)fdm);
8221:   DMDestroy(&dm->fineMesh);
8222:   dm->fineMesh = fdm;
8223:   return(0);
8224: }

8226: /*=== DMBoundary code ===*/

8228: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
8229: {
8230:   PetscInt       d;

8234:   for (d = 0; d < dm->Nds; ++d) {
8235:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
8236:   }
8237:   return(0);
8238: }

8240: /*@C
8241:   DMAddBoundary - Add a boundary condition to the model

8243:   Collective on dm

8245:   Input Parameters:
8246: + dm          - The DM, with a PetscDS that matches the problem being constrained
8247: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8248: . name        - The BC name
8249: . labelname   - The label defining constrained points
8250: . field       - The field to constrain
8251: . numcomps    - The number of constrained field components (0 will constrain all fields)
8252: . comps       - An array of constrained component numbers
8253: . bcFunc      - A pointwise function giving boundary values
8254: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8255: . numids      - The number of DMLabel ids for constrained points
8256: . ids         - An array of ids for constrained points
8257: - ctx         - An optional user context for bcFunc

8259:   Options Database Keys:
8260: + -bc_<boundary name> <num> - Overrides the boundary ids
8261: - -bc_<boundary name>_comp <num> - Overrides the boundary components

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

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

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

8270: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8271: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8272: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8273: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8275: + dim - the spatial dimension
8276: . Nf - the number of fields
8277: . uOff - the offset into u[] and u_t[] for each field
8278: . uOff_x - the offset into u_x[] for each field
8279: . u - each field evaluated at the current point
8280: . u_t - the time derivative of each field evaluated at the current point
8281: . u_x - the gradient of each field evaluated at the current point
8282: . aOff - the offset into a[] and a_t[] for each auxiliary field
8283: . aOff_x - the offset into a_x[] for each auxiliary field
8284: . a - each auxiliary field evaluated at the current point
8285: . a_t - the time derivative of each auxiliary field evaluated at the current point
8286: . a_x - the gradient of auxiliary each field evaluated at the current point
8287: . t - current time
8288: . x - coordinates of the current point
8289: . numConstants - number of constant parameters
8290: . constants - constant parameters
8291: - bcval - output values at the current point

8293:   Level: developer

8295: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8296: @*/
8297: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
8298: {
8299:   PetscDS        ds;

8308:   DMGetDS(dm, &ds);
8309:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8310:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8311:   return(0);
8312: }

8314: /*@
8315:   DMGetNumBoundary - Get the number of registered BC

8317:   Input Parameters:
8318: . dm - The mesh object

8320:   Output Parameters:
8321: . numBd - The number of BC

8323:   Level: intermediate

8325: .seealso: DMAddBoundary(), DMGetBoundary()
8326: @*/
8327: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8328: {
8329:   PetscDS        ds;

8334:   DMGetDS(dm, &ds);
8335:   PetscDSGetNumBoundary(ds, numBd);
8336:   return(0);
8337: }

8339: /*@C
8340:   DMGetBoundary - Get a model boundary condition

8342:   Input Parameters:
8343: + dm          - The mesh object
8344: - bd          - The BC number

8346:   Output Parameters:
8347: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8348: . name        - The BC name
8349: . labelname   - The label defining constrained points
8350: . field       - The field to constrain
8351: . numcomps    - The number of constrained field components
8352: . comps       - An array of constrained component numbers
8353: . bcFunc      - A pointwise function giving boundary values
8354: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8355: . numids      - The number of DMLabel ids for constrained points
8356: . ids         - An array of ids for constrained points
8357: - ctx         - An optional user context for bcFunc

8359:   Options Database Keys:
8360: + -bc_<boundary name> <num> - Overrides the boundary ids
8361: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8363:   Level: developer

8365: .seealso: DMAddBoundary()
8366: @*/
8367: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
8368: {
8369:   PetscDS        ds;

8374:   DMGetDS(dm, &ds);
8375:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8376:   return(0);
8377: }

8379: static PetscErrorCode DMPopulateBoundary(DM dm)
8380: {
8381:   PetscDS        ds;
8382:   DMBoundary    *lastnext;
8383:   DSBoundary     dsbound;

8387:   DMGetDS(dm, &ds);
8388:   dsbound = ds->boundary;
8389:   if (dm->boundary) {
8390:     DMBoundary next = dm->boundary;

8392:     /* quick check to see if the PetscDS has changed */
8393:     if (next->dsboundary == dsbound) return(0);
8394:     /* the PetscDS has changed: tear down and rebuild */
8395:     while (next) {
8396:       DMBoundary b = next;

8398:       next = b->next;
8399:       PetscFree(b);
8400:     }
8401:     dm->boundary = NULL;
8402:   }

8404:   lastnext = &(dm->boundary);
8405:   while (dsbound) {
8406:     DMBoundary dmbound;

8408:     PetscNew(&dmbound);
8409:     dmbound->dsboundary = dsbound;
8410:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8411:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8412:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8413:     *lastnext = dmbound;
8414:     lastnext = &(dmbound->next);
8415:     dsbound = dsbound->next;
8416:   }
8417:   return(0);
8418: }

8420: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8421: {
8422:   DMBoundary     b;

8428:   *isBd = PETSC_FALSE;
8429:   DMPopulateBoundary(dm);
8430:   b = dm->boundary;
8431:   while (b && !(*isBd)) {
8432:     DMLabel    label = b->label;
8433:     DSBoundary dsb = b->dsboundary;

8435:     if (label) {
8436:       PetscInt i;

8438:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8439:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8440:       }
8441:     }
8442:     b = b->next;
8443:   }
8444:   return(0);
8445: }

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

8450:   Collective on DM

8452:   Input Parameters:
8453: + dm      - The DM
8454: . time    - The time
8455: . funcs   - The coordinate functions to evaluate, one per field
8456: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8457: - mode    - The insertion mode for values

8459:   Output Parameter:
8460: . X - vector

8462:    Calling sequence of func:
8463: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8465: +  dim - The spatial dimension
8466: .  time - The time at which to sample
8467: .  x   - The coordinates
8468: .  Nf  - The number of fields
8469: .  u   - The output field values
8470: -  ctx - optional user-defined function context

8472:   Level: developer

8474: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8475: @*/
8476: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8477: {
8478:   Vec            localX;

8483:   DMGetLocalVector(dm, &localX);
8484:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8485:   DMLocalToGlobalBegin(dm, localX, mode, X);
8486:   DMLocalToGlobalEnd(dm, localX, mode, X);
8487:   DMRestoreLocalVector(dm, &localX);
8488:   return(0);
8489: }

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

8494:   Not collective

8496:   Input Parameters:
8497: + dm      - The DM
8498: . time    - The time
8499: . funcs   - The coordinate functions to evaluate, one per field
8500: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8501: - mode    - The insertion mode for values

8503:   Output Parameter:
8504: . localX - vector

8506:    Calling sequence of func:
8507: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8509: +  dim - The spatial dimension
8510: .  x   - The coordinates
8511: .  Nf  - The number of fields
8512: .  u   - The output field values
8513: -  ctx - optional user-defined function context

8515:   Level: developer

8517: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8518: @*/
8519: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8520: {

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

8531: /*@C
8532:   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.

8534:   Collective on DM

8536:   Input Parameters:
8537: + dm      - The DM
8538: . time    - The time
8539: . label   - The DMLabel selecting the portion of the mesh for projection
8540: . funcs   - The coordinate functions to evaluate, one per field
8541: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8542: - mode    - The insertion mode for values

8544:   Output Parameter:
8545: . X - vector

8547:    Calling sequence of func:
8548: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8550: +  dim - The spatial dimension
8551: .  x   - The coordinates
8552: .  Nf  - The number of fields
8553: .  u   - The output field values
8554: -  ctx - optional user-defined function context

8556:   Level: developer

8558: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8559: @*/
8560: 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)
8561: {
8562:   Vec            localX;

8567:   DMGetLocalVector(dm, &localX);
8568:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8569:   DMLocalToGlobalBegin(dm, localX, mode, X);
8570:   DMLocalToGlobalEnd(dm, localX, mode, X);
8571:   DMRestoreLocalVector(dm, &localX);
8572:   return(0);
8573: }

8575: /*@C
8576:   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.

8578:   Not collective

8580:   Input Parameters:
8581: + dm      - The DM
8582: . time    - The time
8583: . label   - The DMLabel selecting the portion of the mesh for projection
8584: . funcs   - The coordinate functions to evaluate, one per field
8585: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8586: - mode    - The insertion mode for values

8588:   Output Parameter:
8589: . localX - vector

8591:    Calling sequence of func:
8592: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8594: +  dim - The spatial dimension
8595: .  x   - The coordinates
8596: .  Nf  - The number of fields
8597: .  u   - The output field values
8598: -  ctx - optional user-defined function context

8600:   Level: developer

8602: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8603: @*/
8604: 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)
8605: {

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

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

8619:   Not collective

8621:   Input Parameters:
8622: + dm      - The DM
8623: . time    - The time
8624: . localU  - The input field vector
8625: . funcs   - The functions to evaluate, one per field
8626: - mode    - The insertion mode for values

8628:   Output Parameter:
8629: . localX  - The output vector

8631:    Calling sequence of func:
8632: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8633: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8634: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8635: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8637: +  dim          - The spatial dimension
8638: .  Nf           - The number of input fields
8639: .  NfAux        - The number of input auxiliary fields
8640: .  uOff         - The offset of each field in u[]
8641: .  uOff_x       - The offset of each field in u_x[]
8642: .  u            - The field values at this point in space
8643: .  u_t          - The field time derivative at this point in space (or NULL)
8644: .  u_x          - The field derivatives at this point in space
8645: .  aOff         - The offset of each auxiliary field in u[]
8646: .  aOff_x       - The offset of each auxiliary field in u_x[]
8647: .  a            - The auxiliary field values at this point in space
8648: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8649: .  a_x          - The auxiliary field derivatives at this point in space
8650: .  t            - The current time
8651: .  x            - The coordinates of this point
8652: .  numConstants - The number of constants
8653: .  constants    - The value of each constant
8654: -  f            - The value of the function at this point in space

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

8661:   Level: intermediate

8663: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8664: @*/
8665: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8666:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8667:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8668:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8669:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8670:                                    InsertMode mode, Vec localX)
8671: {

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

8683: /*@C
8684:   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.

8686:   Not collective

8688:   Input Parameters:
8689: + dm      - The DM
8690: . time    - The time
8691: . label   - The DMLabel marking the portion of the domain to output
8692: . numIds  - The number of label ids to use
8693: . ids     - The label ids to use for marking
8694: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8695: . comps   - The components to set in the output, or NULL for all components
8696: . localU  - The input field vector
8697: . funcs   - The functions to evaluate, one per field
8698: - mode    - The insertion mode for values

8700:   Output Parameter:
8701: . localX  - The output vector

8703:    Calling sequence of func:
8704: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8705: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8706: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8707: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8709: +  dim          - The spatial dimension
8710: .  Nf           - The number of input fields
8711: .  NfAux        - The number of input auxiliary fields
8712: .  uOff         - The offset of each field in u[]
8713: .  uOff_x       - The offset of each field in u_x[]
8714: .  u            - The field values at this point in space
8715: .  u_t          - The field time derivative at this point in space (or NULL)
8716: .  u_x          - The field derivatives at this point in space
8717: .  aOff         - The offset of each auxiliary field in u[]
8718: .  aOff_x       - The offset of each auxiliary field in u_x[]
8719: .  a            - The auxiliary field values at this point in space
8720: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8721: .  a_x          - The auxiliary field derivatives at this point in space
8722: .  t            - The current time
8723: .  x            - The coordinates of this point
8724: .  numConstants - The number of constants
8725: .  constants    - The value of each constant
8726: -  f            - The value of the function at this point in space

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

8733:   Level: intermediate

8735: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8736: @*/
8737: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8738:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8739:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8740:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8741:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8742:                                         InsertMode mode, Vec localX)
8743: {

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

8755: /*@C
8756:   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.

8758:   Not collective

8760:   Input Parameters:
8761: + dm      - The DM
8762: . time    - The time
8763: . label   - The DMLabel marking the portion of the domain boundary to output
8764: . numIds  - The number of label ids to use
8765: . ids     - The label ids to use for marking
8766: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8767: . comps   - The components to set in the output, or NULL for all components
8768: . localU  - The input field vector
8769: . funcs   - The functions to evaluate, one per field
8770: - mode    - The insertion mode for values

8772:   Output Parameter:
8773: . localX  - The output vector

8775:    Calling sequence of func:
8776: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8777: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8778: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8779: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8781: +  dim          - The spatial dimension
8782: .  Nf           - The number of input fields
8783: .  NfAux        - The number of input auxiliary fields
8784: .  uOff         - The offset of each field in u[]
8785: .  uOff_x       - The offset of each field in u_x[]
8786: .  u            - The field values at this point in space
8787: .  u_t          - The field time derivative at this point in space (or NULL)
8788: .  u_x          - The field derivatives at this point in space
8789: .  aOff         - The offset of each auxiliary field in u[]
8790: .  aOff_x       - The offset of each auxiliary field in u_x[]
8791: .  a            - The auxiliary field values at this point in space
8792: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8793: .  a_x          - The auxiliary field derivatives at this point in space
8794: .  t            - The current time
8795: .  x            - The coordinates of this point
8796: .  n            - The face normal
8797: .  numConstants - The number of constants
8798: .  constants    - The value of each constant
8799: -  f            - The value of the function at this point in space

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

8807:   Level: intermediate

8809: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8810: @*/
8811: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8812:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8813:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8814:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8815:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8816:                                           InsertMode mode, Vec localX)
8817: {

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

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

8832:   Input Parameters:
8833: + dm    - The DM
8834: . time  - The time
8835: . funcs - The functions to evaluate for each field component
8836: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8837: - X     - The coefficient vector u_h, a global vector

8839:   Output Parameter:
8840: . diff - The diff ||u - u_h||_2

8842:   Level: developer

8844: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8845: @*/
8846: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8847: {

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

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

8861:   Collective on dm

8863:   Input Parameters:
8864: + dm    - The DM
8865: , time  - The time
8866: . funcs - The gradient functions to evaluate for each field component
8867: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8868: . X     - The coefficient vector u_h, a global vector
8869: - n     - The vector to project along

8871:   Output Parameter:
8872: . diff - The diff ||(grad u - grad u_h) . n||_2

8874:   Level: developer

8876: .seealso: DMProjectFunction(), DMComputeL2Diff()
8877: @*/
8878: 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)
8879: {

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

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

8893:   Collective on dm

8895:   Input Parameters:
8896: + dm    - The DM
8897: . time  - The time
8898: . funcs - The functions to evaluate for each field component
8899: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8900: - X     - The coefficient vector u_h, a global vector

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

8905:   Level: developer

8907: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8908: @*/
8909: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8910: {

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

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

8925:   Collective on dm

8927:   Input parameters:
8928: + dm - the pre-adaptation DM object
8929: - label - label with the flags

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

8934:   Level: intermediate

8936: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8937: @*/
8938: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8939: {

8946:   *dmAdapt = NULL;
8947:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8948:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8949:   if (*dmAdapt) (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
8950:   return(0);
8951: }

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

8956:   Input Parameters:
8957: + dm - The DM object
8958: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8959: - 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_".

8961:   Output Parameter:
8962: . dmAdapt  - Pointer to the DM object containing the adapted mesh

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

8966:   Level: advanced

8968: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8969: @*/
8970: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8971: {

8979:   *dmAdapt = NULL;
8980:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8981:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8982:   return(0);
8983: }

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

8988:  Not Collective

8990:  Input Parameter:
8991: .  dm    - The DM

8993:  Output Parameters:
8994: +  nranks - the number of neighbours
8995: -  ranks - the neighbors ranks

8997:  Notes:
8998:  Do not free the array, it is freed when the DM is destroyed.

9000:  Level: beginner

9002:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9003: @*/
9004: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9005: {

9010:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9011:   (dm->ops->getneighbors)(dm,nranks,ranks);
9012:   return(0);
9013: }

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

9017: /*
9018:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9019:     This has be a different function because it requires DM which is not defined in the Mat library
9020: */
9021: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9022: {

9026:   if (coloring->ctype == IS_COLORING_LOCAL) {
9027:     Vec x1local;
9028:     DM  dm;
9029:     MatGetDM(J,&dm);
9030:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9031:     DMGetLocalVector(dm,&x1local);
9032:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9033:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9034:     x1   = x1local;
9035:   }
9036:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9037:   if (coloring->ctype == IS_COLORING_LOCAL) {
9038:     DM  dm;
9039:     MatGetDM(J,&dm);
9040:     DMRestoreLocalVector(dm,&x1);
9041:   }
9042:   return(0);
9043: }

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

9048:     Input Parameter:
9049: .    coloring - the MatFDColoring object

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

9054:     Level: advanced

9056: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9057: @*/
9058: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9059: {
9061:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9062:   return(0);
9063: }

9065: /*@
9066:     DMGetCompatibility - determine if two DMs are compatible

9068:     Collective

9070:     Input Parameters:
9071: +    dm1 - the first DM
9072: -    dm2 - the second DM

9074:     Output Parameters:
9075: +    compatible - whether or not the two DMs are compatible
9076: -    set - whether or not the compatible value was set

9078:     Notes:
9079:     Two DMs are deemed compatible if they represent the same parallel decomposition
9080:     of the same topology. This implies that the section (field data) on one
9081:     "makes sense" with respect to the topology and parallel decomposition of the other.
9082:     Loosely speaking, compatible DMs represent the same domain and parallel
9083:     decomposition, but hold different data.

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

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

9093:     Consider the operation of summing data living on a 2-dof DMDA to data living
9094:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9095: .vb
9096:   ...
9097:   DMGetCompatibility(da1,da2,&compatible,&set);
9098:   if (set && compatible)  {
9099:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9100:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9101:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9102:     for (j=y; j<y+n; ++j) {
9103:       for (i=x; i<x+m, ++i) {
9104:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9105:       }
9106:     }
9107:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9108:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9109:   } else {
9110:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9111:   }
9112:   ...
9113: .ve

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

9120:     A DM is always compatible with itself.

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

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

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

9139:     Level: advanced

9141: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9142: @*/

9144: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9145: {
9147:   PetscMPIInt    compareResult;
9148:   DMType         type,type2;
9149:   PetscBool      sameType;


9155:   /* Declare a DM compatible with itself */
9156:   if (dm1 == dm2) {
9157:     *set = PETSC_TRUE;
9158:     *compatible = PETSC_TRUE;
9159:     return(0);
9160:   }

9162:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9163:      communicator. Note that this does not preclude compatibility with
9164:      DMs living on "congruent" or "similar" communicators, but this must be
9165:      determined by the implementation-specific logic */
9166:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9167:   if (compareResult == MPI_UNEQUAL) {
9168:     *set = PETSC_TRUE;
9169:     *compatible = PETSC_FALSE;
9170:     return(0);
9171:   }

9173:   /* Pass to the implementation-specific routine, if one exists. */
9174:   if (dm1->ops->getcompatibility) {
9175:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9176:     if (*set) return(0);
9177:   }

9179:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9180:      with an implementation of this function from dm2 */
9181:   DMGetType(dm1,&type);
9182:   DMGetType(dm2,&type2);
9183:   PetscStrcmp(type,type2,&sameType);
9184:   if (!sameType && dm2->ops->getcompatibility) {
9185:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9186:   } else {
9187:     *set = PETSC_FALSE;
9188:   }
9189:   return(0);
9190: }

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

9195:   Logically Collective on DM

9197:   Input Parameters:
9198: + DM - the DM
9199: . f - the monitor function
9200: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9201: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

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

9207:   Notes:
9208:   Several different monitoring routines may be set by calling
9209:   DMMonitorSet() multiple times; all will be called in the
9210:   order in which they were set.

9212:   Fortran Notes:
9213:   Only a single monitor function can be set for each DM object

9215:   Level: intermediate

9217: .seealso: DMMonitorCancel()
9218: @*/
9219: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9220: {
9221:   PetscInt       m;

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

9229:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9230:     if (identical) return(0);
9231:   }
9232:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9233:   dm->monitor[dm->numbermonitors]          = f;
9234:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9235:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9236:   return(0);
9237: }

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

9242:   Logically Collective on DM

9244:   Input Parameter:
9245: . dm - the DM

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

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

9255:   Level: intermediate

9257: .seealso: DMMonitorSet()
9258: @*/
9259: PetscErrorCode DMMonitorCancel(DM dm)
9260: {
9262:   PetscInt       m;

9266:   for (m = 0; m < dm->numbermonitors; ++m) {
9267:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9268:   }
9269:   dm->numbermonitors = 0;
9270:   return(0);
9271: }

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

9276:   Collective on DM

9278:   Input Parameters:
9279: + dm   - DM object you wish to monitor
9280: . name - the monitor type one is seeking
9281: . help - message indicating what monitoring is done
9282: . manual - manual page for the monitor
9283: . monitor - the monitor function
9284: - 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

9286:   Output Parameter:
9287: . flg - Flag set if the monitor was created

9289:   Level: developer

9291: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9292:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9293:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9294:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9295:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9296:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9297:           PetscOptionsFList(), PetscOptionsEList()
9298: @*/
9299: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9300: {
9301:   PetscViewer       viewer;
9302:   PetscViewerFormat format;
9303:   PetscErrorCode    ierr;

9307:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9308:   if (*flg) {
9309:     PetscViewerAndFormat *vf;

9311:     PetscViewerAndFormatCreate(viewer, format, &vf);
9312:     PetscObjectDereference((PetscObject) viewer);
9313:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9314:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9315:   }
9316:   return(0);
9317: }

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

9322:    Collective on DM

9324:    Input Parameters:
9325: .  dm - The DM

9327:    Level: developer

9329: .seealso: DMMonitorSet()
9330: @*/
9331: PetscErrorCode DMMonitor(DM dm)
9332: {
9333:   PetscInt       m;

9337:   if (!dm) return(0);
9339:   for (m = 0; m < dm->numbermonitors; ++m) {
9340:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9341:   }
9342:   return(0);
9343: }