Actual source code: dm.c

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

  9: PetscClassId  DM_CLASSID;
 10: PetscClassId  DMLABEL_CLASSID;
 11: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load;

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

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

 22:   Collective

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

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

 30:   Level: beginner

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

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

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

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

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

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

 92:   Collective

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

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

100:   Level: beginner

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

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

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

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

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

169:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
170:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
171:   }
172:   return(0);
173: }

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

178:    Logically Collective on da

180:    Input Parameter:
181: +  da - initial distributed array
182: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

184:    Options Database:
185: .   -dm_vec_type ctype

187:    Level: intermediate

189: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
190: @*/
191: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
192: {

197:   PetscFree(da->vectype);
198:   PetscStrallocpy(ctype,(char**)&da->vectype);
199:   return(0);
200: }

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

205:    Logically Collective on da

207:    Input Parameter:
208: .  da - initial distributed array

210:    Output Parameter:
211: .  ctype - the vector type

213:    Level: intermediate

215: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
216: @*/
217: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
218: {
221:   *ctype = da->vectype;
222:   return(0);
223: }

225: /*@
226:   VecGetDM - Gets the DM defining the data layout of the vector

228:   Not collective

230:   Input Parameter:
231: . v - The Vec

233:   Output Parameter:
234: . dm - The DM

236:   Level: intermediate

238: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
239: @*/
240: PetscErrorCode VecGetDM(Vec v, DM *dm)
241: {

247:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
248:   return(0);
249: }

251: /*@
252:   VecSetDM - Sets the DM defining the data layout of the vector.

254:   Not collective

256:   Input Parameters:
257: + v - The Vec
258: - dm - The DM

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

262:   Level: intermediate

264: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
265: @*/
266: PetscErrorCode VecSetDM(Vec v, DM dm)
267: {

273:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
274:   return(0);
275: }

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

280:    Logically Collective on dm

282:    Input Parameters:
283: +  dm - the DM context
284: -  ctype - the matrix type

286:    Options Database:
287: .   -dm_is_coloring_type - global or local

289:    Level: intermediate

291: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
292:           DMGetISColoringType()
293: @*/
294: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
295: {
298:   dm->coloringtype = ctype;
299:   return(0);
300: }

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

305:    Logically Collective on dm

307:    Input Parameter:
308: .  dm - the DM context

310:    Output Parameter:
311: .  ctype - the matrix type

313:    Options Database:
314: .   -dm_is_coloring_type - global or local

316:    Level: intermediate

318: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
319:           DMGetISColoringType()
320: @*/
321: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
322: {
325:   *ctype = dm->coloringtype;
326:   return(0);
327: }

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

332:    Logically Collective on dm

334:    Input Parameters:
335: +  dm - the DM context
336: -  ctype - the matrix type

338:    Options Database:
339: .   -dm_mat_type ctype

341:    Level: intermediate

343: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
344: @*/
345: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
346: {

351:   PetscFree(dm->mattype);
352:   PetscStrallocpy(ctype,(char**)&dm->mattype);
353:   return(0);
354: }

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

359:    Logically Collective on dm

361:    Input Parameter:
362: .  dm - the DM context

364:    Output Parameter:
365: .  ctype - the matrix type

367:    Options Database:
368: .   -dm_mat_type ctype

370:    Level: intermediate

372: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType(), DMSetMatType(), DMGetMatType()
373: @*/
374: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
375: {
378:   *ctype = dm->mattype;
379:   return(0);
380: }

382: /*@
383:   MatGetDM - Gets the DM defining the data layout of the matrix

385:   Not collective

387:   Input Parameter:
388: . A - The Mat

390:   Output Parameter:
391: . dm - The DM

393:   Level: intermediate

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

398: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
399: @*/
400: PetscErrorCode MatGetDM(Mat A, DM *dm)
401: {

407:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
408:   return(0);
409: }

411: /*@
412:   MatSetDM - Sets the DM defining the data layout of the matrix

414:   Not collective

416:   Input Parameters:
417: + A - The Mat
418: - dm - The DM

420:   Level: intermediate

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


426: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
427: @*/
428: PetscErrorCode MatSetDM(Mat A, DM dm)
429: {

435:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
436:   return(0);
437: }

439: /*@C
440:    DMSetOptionsPrefix - Sets the prefix used for searching for all
441:    DM options in the database.

443:    Logically Collective on dm

445:    Input Parameter:
446: +  da - the DM context
447: -  prefix - the prefix to prepend to all option names

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

453:    Level: advanced

455: .seealso: DMSetFromOptions()
456: @*/
457: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
458: {

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

473: /*@C
474:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
475:    DM options in the database.

477:    Logically Collective on dm

479:    Input Parameters:
480: +  dm - the DM context
481: -  prefix - the prefix string to prepend to all DM option requests

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

487:    Level: advanced

489: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
490: @*/
491: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
492: {

497:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
498:   return(0);
499: }

501: /*@C
502:    DMGetOptionsPrefix - Gets the prefix used for searching for all
503:    DM options in the database.

505:    Not Collective

507:    Input Parameters:
508: .  dm - the DM context

510:    Output Parameters:
511: .  prefix - pointer to the prefix string used is returned

513:    Notes:
514:     On the fortran side, the user should pass in a string 'prefix' of
515:    sufficient length to hold the prefix.

517:    Level: advanced

519: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
520: @*/
521: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
522: {

527:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
528:   return(0);
529: }

531: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
532: {
533:   PetscInt i, refct = ((PetscObject) dm)->refct;
534:   DMNamedVecLink nlink;

538:   *ncrefct = 0;
539:   /* count all the circular references of DM and its contained Vecs */
540:   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
541:     if (dm->localin[i])  refct--;
542:     if (dm->globalin[i]) refct--;
543:   }
544:   for (nlink=dm->namedglobal; nlink; nlink=nlink->next) refct--;
545:   for (nlink=dm->namedlocal; nlink; nlink=nlink->next) refct--;
546:   if (dm->x) {
547:     DM obj;
548:     VecGetDM(dm->x, &obj);
549:     if (obj == dm) refct--;
550:   }
551:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
552:     refct--;
553:     if (recurseCoarse) {
554:       PetscInt coarseCount;

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

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

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

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

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

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

596:     Collective on dm

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

601:     Level: developer

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

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

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

616:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
617:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
618:   --((PetscObject)(*dm))->refct;
619:   if (--cnt > 0) {*dm = 0; return(0);}
620:   /*
621:      Need this test because the dm references the vectors that
622:      reference the dm, so destroying the dm calls destroy on the
623:      vectors that cause another destroy on the dm
624:   */
625:   if (((PetscObject)(*dm))->refct < 0) return(0);
626:   ((PetscObject) (*dm))->refct = 0;
627:   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
628:     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
629:     VecDestroy(&(*dm)->localin[i]);
630:   }
631:   nnext=(*dm)->namedglobal;
632:   (*dm)->namedglobal = NULL;
633:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
634:     nnext = nlink->next;
635:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
636:     PetscFree(nlink->name);
637:     VecDestroy(&nlink->X);
638:     PetscFree(nlink);
639:   }
640:   nnext=(*dm)->namedlocal;
641:   (*dm)->namedlocal = NULL;
642:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
643:     nnext = nlink->next;
644:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
645:     PetscFree(nlink->name);
646:     VecDestroy(&nlink->X);
647:     PetscFree(nlink);
648:   }

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

712:       next = b->next;
713:       PetscFree(b);
714:     }
715:   }

717:   PetscObjectDestroy(&(*dm)->dmksp);
718:   PetscObjectDestroy(&(*dm)->dmsnes);
719:   PetscObjectDestroy(&(*dm)->dmts);

721:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
722:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
723:   }
724:   VecDestroy(&(*dm)->x);
725:   MatFDColoringDestroy(&(*dm)->fd);
726:   DMClearGlobalVectors(*dm);
727:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
728:   PetscFree((*dm)->vectype);
729:   PetscFree((*dm)->mattype);

731:   PetscSectionDestroy(&(*dm)->localSection);
732:   PetscSectionDestroy(&(*dm)->globalSection);
733:   PetscLayoutDestroy(&(*dm)->map);
734:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
735:   MatDestroy(&(*dm)->defaultConstraintMat);
736:   PetscSFDestroy(&(*dm)->sf);
737:   PetscSFDestroy(&(*dm)->sectionSF);
738:   if ((*dm)->useNatural) {
739:     if ((*dm)->sfNatural) {
740:       PetscSFDestroy(&(*dm)->sfNatural);
741:     }
742:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
743:   }
744:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
745:     DMSetFineDM((*dm)->coarseMesh,NULL);
746:   }
747:   DMDestroy(&(*dm)->coarseMesh);
748:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
749:     DMSetCoarseDM((*dm)->fineMesh,NULL);
750:   }
751:   DMDestroy(&(*dm)->fineMesh);
752:   DMFieldDestroy(&(*dm)->coordinateField);
753:   DMDestroy(&(*dm)->coordinateDM);
754:   VecDestroy(&(*dm)->coordinates);
755:   VecDestroy(&(*dm)->coordinatesLocal);
756:   PetscFree3((*dm)->L,(*dm)->maxCell,(*dm)->bdtype);
757:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
758:   DMDestroy(&(*dm)->transformDM);
759:   VecDestroy(&(*dm)->transform);

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

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

775: /*@
776:     DMSetUp - sets up the data structures inside a DM object

778:     Collective on dm

780:     Input Parameter:
781: .   dm - the DM object to setup

783:     Level: developer

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

787: @*/
788: PetscErrorCode  DMSetUp(DM dm)
789: {

794:   if (dm->setupcalled) return(0);
795:   if (dm->ops->setup) {
796:     (*dm->ops->setup)(dm);
797:   }
798:   dm->setupcalled = PETSC_TRUE;
799:   return(0);
800: }

802: /*@
803:     DMSetFromOptions - sets parameters in a DM from the options database

805:     Collective on dm

807:     Input Parameter:
808: .   dm - the DM object to set options for

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

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

825:     Level: intermediate

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

830: @*/
831: PetscErrorCode DMSetFromOptions(DM dm)
832: {
833:   char           typeName[256];
834:   PetscBool      flg;

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

862: /*@C
863:    DMViewFromOptions - View from Options

865:    Collective on DM

867:    Input Parameters:
868: +  dm - the DM object
869: .  obj - Optional object
870: -  name - command line option

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

881:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
882:   return(0);
883: }

885: /*@C
886:     DMView - Views a DM

888:     Collective on dm

890:     Input Parameter:
891: +   dm - the DM object to view
892: -   v - the viewer

894:     Level: beginner

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

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

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

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

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

941: /*@
942:     DMCreateGlobalVector - Creates a global vector from a DM object

944:     Collective on dm

946:     Input Parameter:
947: .   dm - the DM object

949:     Output Parameter:
950: .   vec - the global vector

952:     Level: beginner

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

956: @*/
957: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
958: {

964:   if (!dm->ops->createglobalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateGlobalVector",((PetscObject)dm)->type_name);
965:   (*dm->ops->createglobalvector)(dm,vec);
966:   return(0);
967: }

969: /*@
970:     DMCreateLocalVector - Creates a local vector from a DM object

972:     Not Collective

974:     Input Parameter:
975: .   dm - the DM object

977:     Output Parameter:
978: .   vec - the local vector

980:     Level: beginner

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

984: @*/
985: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
986: {

992:   if (!dm->ops->createlocalvector) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateLocalVector",((PetscObject)dm)->type_name);
993:   (*dm->ops->createlocalvector)(dm,vec);
994:   return(0);
995: }

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

1000:    Collective on dm

1002:    Input Parameter:
1003: .  dm - the DM that provides the mapping

1005:    Output Parameter:
1006: .  ltog - the mapping

1008:    Level: intermediate

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

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

1024:   if (!dm->ltogmap) {
1025:     PetscSection section, sectionGlobal;

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

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

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

1078: /*@
1079:    DMGetBlockSize - Gets the inherent block size associated with a DM

1081:    Not Collective

1083:    Input Parameter:
1084: .  dm - the DM with block structure

1086:    Output Parameter:
1087: .  bs - the block size, 1 implies no exploitable block structure

1089:    Level: intermediate

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

1103: /*@
1104:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1106:     Collective on dm1

1108:     Input Parameter:
1109: +   dm1 - the DM object
1110: -   dm2 - the second, finer DM object

1112:     Output Parameter:
1113: +  mat - the interpolation
1114: -  vec - the scaling (optional)

1116:     Level: developer

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

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


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

1128: @*/
1129: PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
1130: {

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

1144: /*@
1145:     DMCreateRestriction - Gets restriction matrix between two DM objects

1147:     Collective on dm1

1149:     Input Parameter:
1150: +   dm1 - the DM object
1151: -   dm2 - the second, finer DM object

1153:     Output Parameter:
1154: .  mat - the restriction


1157:     Level: developer

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


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

1166: @*/
1167: PetscErrorCode  DMCreateRestriction(DM dm1,DM dm2,Mat *mat)
1168: {

1175:   if (!dm1->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dm1)->type_name);
1176:   PetscLogEventBegin(DM_CreateRestriction,dm1,dm2,0,0);
1177:   (*dm1->ops->createrestriction)(dm1,dm2,mat);
1178:   PetscLogEventEnd(DM_CreateRestriction,dm1,dm2,0,0);
1179:   return(0);
1180: }

1182: /*@
1183:     DMCreateInjection - Gets injection matrix between two DM objects

1185:     Collective on dm1

1187:     Input Parameter:
1188: +   dm1 - the DM object
1189: -   dm2 - the second, finer DM object

1191:     Output Parameter:
1192: .   mat - the injection

1194:     Level: developer

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

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

1202: @*/
1203: PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,Mat *mat)
1204: {

1211:   if (!dm1->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dm1)->type_name);
1212:   PetscLogEventBegin(DM_CreateInjection,dm1,dm2,0,0);
1213:   (*dm1->ops->createinjection)(dm1,dm2,mat);
1214:   PetscLogEventEnd(DM_CreateInjection,dm1,dm2,0,0);
1215:   return(0);
1216: }

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

1221:   Collective on dm1

1223:   Input Parameter:
1224: + dm1 - the DM object
1225: - dm2 - the second, finer DM object

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

1230:   Level: developer

1232: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1233: @*/
1234: PetscErrorCode DMCreateMassMatrix(DM dm1, DM dm2, Mat *mat)
1235: {

1242:   if (!dm1->ops->createmassmatrix) SETERRQ1(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMassMatrix",((PetscObject)dm1)->type_name);
1243:   (*dm1->ops->createmassmatrix)(dm1, dm2, mat);
1244:   return(0);
1245: }

1247: /*@
1248:     DMCreateColoring - Gets coloring for a DM

1250:     Collective on dm

1252:     Input Parameter:
1253: +   dm - the DM object
1254: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1256:     Output Parameter:
1257: .   coloring - the coloring

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

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

1265:     Level: developer

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

1269: @*/
1270: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1271: {

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

1282: /*@
1283:     DMCreateMatrix - Gets empty Jacobian for a DM

1285:     Collective on dm

1287:     Input Parameter:
1288: .   dm - the DM object

1290:     Output Parameter:
1291: .   mat - the empty Jacobian

1293:     Level: beginner

1295:     Notes:
1296:     This properly preallocates the number of nonzeros in the sparse matrix so you
1297:        do not need to do it yourself.

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

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

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

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

1310: @*/
1311: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1312: {

1318:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
1319:   MatInitializePackage();
1320:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1321:   (*dm->ops->creatematrix)(dm,mat);
1322:   /* Handle nullspace and near nullspace */
1323:   if (dm->Nf) {
1324:     MatNullSpace nullSpace;
1325:     PetscInt     Nf;

1327:     DMGetNumFields(dm, &Nf);
1328:     if (Nf == 1) {
1329:       if (dm->nullspaceConstructors[0]) {
1330:         (*dm->nullspaceConstructors[0])(dm, 0, &nullSpace);
1331:         MatSetNullSpace(*mat, nullSpace);
1332:         MatNullSpaceDestroy(&nullSpace);
1333:       }
1334:       if (dm->nearnullspaceConstructors[0]) {
1335:         (*dm->nearnullspaceConstructors[0])(dm, 0, &nullSpace);
1336:         MatSetNearNullSpace(*mat, nullSpace);
1337:         MatNullSpaceDestroy(&nullSpace);
1338:       }
1339:     }
1340:   }
1341:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1342:   return(0);
1343: }

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

1349:   Logically Collective on dm

1351:   Input Parameter:
1352: + dm - the DM
1353: - only - PETSC_TRUE if only want preallocation

1355:   Level: developer
1356: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1357: @*/
1358: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1359: {
1362:   dm->prealloc_only = only;
1363:   return(0);
1364: }

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

1370:   Logically Collective on dm

1372:   Input Parameter:
1373: + dm - the DM
1374: - only - PETSC_TRUE if only want matrix stucture

1376:   Level: developer
1377: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1378: @*/
1379: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1380: {
1383:   dm->structure_only = only;
1384:   return(0);
1385: }

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

1390:   Not Collective

1392:   Input Parameters:
1393: + dm - the DM object
1394: . count - The minium size
1395: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1397:   Output Parameter:
1398: . array - the work array

1400:   Level: developer

1402: .seealso DMDestroy(), DMCreate()
1403: @*/
1404: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1405: {
1407:   DMWorkLink     link;
1408:   PetscMPIInt    dsize;

1413:   if (dm->workin) {
1414:     link       = dm->workin;
1415:     dm->workin = dm->workin->next;
1416:   } else {
1417:     PetscNewLog(dm,&link);
1418:   }
1419:   MPI_Type_size(dtype,&dsize);
1420:   if (((size_t)dsize*count) > link->bytes) {
1421:     PetscFree(link->mem);
1422:     PetscMalloc(dsize*count,&link->mem);
1423:     link->bytes = dsize*count;
1424:   }
1425:   link->next   = dm->workout;
1426:   dm->workout  = link;
1427:   *(void**)mem = link->mem;
1428:   return(0);
1429: }

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

1434:   Not Collective

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

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

1444:   Level: developer

1446:   Developer Notes:
1447:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1448: .seealso DMDestroy(), DMCreate()
1449: @*/
1450: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1451: {
1452:   DMWorkLink *p,link;

1457:   for (p=&dm->workout; (link=*p); p=&link->next) {
1458:     if (link->mem == *(void**)mem) {
1459:       *p           = link->next;
1460:       link->next   = dm->workin;
1461:       dm->workin   = link;
1462:       *(void**)mem = NULL;
1463:       return(0);
1464:     }
1465:   }
1466:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1467: }

1469: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1470: {
1473:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1474:   dm->nullspaceConstructors[field] = nullsp;
1475:   return(0);
1476: }

1478: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1479: {
1483:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1484:   *nullsp = dm->nullspaceConstructors[field];
1485:   return(0);
1486: }

1488: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1489: {
1492:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1493:   dm->nearnullspaceConstructors[field] = nullsp;
1494:   return(0);
1495: }

1497: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1498: {
1502:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1503:   *nullsp = dm->nearnullspaceConstructors[field];
1504:   return(0);
1505: }

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

1510:   Not collective

1512:   Input Parameter:
1513: . dm - the DM object

1515:   Output Parameters:
1516: + numFields  - The number of fields (or NULL if not requested)
1517: . fieldNames - The name for each field (or NULL if not requested)
1518: - fields     - The global indices for each field (or NULL if not requested)

1520:   Level: intermediate

1522:   Notes:
1523:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1524:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1525:   PetscFree().

1527: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1528: @*/
1529: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1530: {
1531:   PetscSection   section, sectionGlobal;

1536:   if (numFields) {
1538:     *numFields = 0;
1539:   }
1540:   if (fieldNames) {
1542:     *fieldNames = NULL;
1543:   }
1544:   if (fields) {
1546:     *fields = NULL;
1547:   }
1548:   DMGetLocalSection(dm, &section);
1549:   if (section) {
1550:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1551:     PetscInt nF, f, pStart, pEnd, p;

1553:     DMGetGlobalSection(dm, &sectionGlobal);
1554:     PetscSectionGetNumFields(section, &nF);
1555:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1556:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1557:     for (f = 0; f < nF; ++f) {
1558:       fieldSizes[f] = 0;
1559:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1560:     }
1561:     for (p = pStart; p < pEnd; ++p) {
1562:       PetscInt gdof;

1564:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1565:       if (gdof > 0) {
1566:         for (f = 0; f < nF; ++f) {
1567:           PetscInt fdof, fcdof, fpdof;

1569:           PetscSectionGetFieldDof(section, p, f, &fdof);
1570:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1571:           fpdof = fdof-fcdof;
1572:           if (fpdof && fpdof != fieldNc[f]) {
1573:             /* Layout does not admit a pointwise block size */
1574:             fieldNc[f] = 1;
1575:           }
1576:           fieldSizes[f] += fpdof;
1577:         }
1578:       }
1579:     }
1580:     for (f = 0; f < nF; ++f) {
1581:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1582:       fieldSizes[f] = 0;
1583:     }
1584:     for (p = pStart; p < pEnd; ++p) {
1585:       PetscInt gdof, goff;

1587:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1588:       if (gdof > 0) {
1589:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1590:         for (f = 0; f < nF; ++f) {
1591:           PetscInt fdof, fcdof, fc;

1593:           PetscSectionGetFieldDof(section, p, f, &fdof);
1594:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1595:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1596:             fieldIndices[f][fieldSizes[f]] = goff++;
1597:           }
1598:         }
1599:       }
1600:     }
1601:     if (numFields) *numFields = nF;
1602:     if (fieldNames) {
1603:       PetscMalloc1(nF, fieldNames);
1604:       for (f = 0; f < nF; ++f) {
1605:         const char *fieldName;

1607:         PetscSectionGetFieldName(section, f, &fieldName);
1608:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1609:       }
1610:     }
1611:     if (fields) {
1612:       PetscMalloc1(nF, fields);
1613:       for (f = 0; f < nF; ++f) {
1614:         PetscInt bs, in[2], out[2];

1616:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1617:         in[0] = -fieldNc[f];
1618:         in[1] = fieldNc[f];
1619:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1620:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1621:         ISSetBlockSize((*fields)[f], bs);
1622:       }
1623:     }
1624:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1625:   } else if (dm->ops->createfieldis) {
1626:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1627:   }
1628:   return(0);
1629: }


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

1638:   Not collective

1640:   Input Parameter:
1641: . dm - the DM object

1643:   Output Parameters:
1644: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1645: . namelist  - The name for each field (or NULL if not requested)
1646: . islist    - The global indices for each field (or NULL if not requested)
1647: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1649:   Level: intermediate

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

1656: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1657: @*/
1658: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1659: {

1664:   if (len) {
1666:     *len = 0;
1667:   }
1668:   if (namelist) {
1670:     *namelist = 0;
1671:   }
1672:   if (islist) {
1674:     *islist = 0;
1675:   }
1676:   if (dmlist) {
1678:     *dmlist = 0;
1679:   }
1680:   /*
1681:    Is it a good idea to apply the following check across all impls?
1682:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1683:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1684:    */
1685:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1686:   if (!dm->ops->createfielddecomposition) {
1687:     PetscSection section;
1688:     PetscInt     numFields, f;

1690:     DMGetLocalSection(dm, &section);
1691:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1692:     if (section && numFields && dm->ops->createsubdm) {
1693:       if (len) *len = numFields;
1694:       if (namelist) {PetscMalloc1(numFields,namelist);}
1695:       if (islist)   {PetscMalloc1(numFields,islist);}
1696:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1697:       for (f = 0; f < numFields; ++f) {
1698:         const char *fieldName;

1700:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1701:         if (namelist) {
1702:           PetscSectionGetFieldName(section, f, &fieldName);
1703:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1704:         }
1705:       }
1706:     } else {
1707:       DMCreateFieldIS(dm, len, namelist, islist);
1708:       /* By default there are no DMs associated with subproblems. */
1709:       if (dmlist) *dmlist = NULL;
1710:     }
1711:   } else {
1712:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1713:   }
1714:   return(0);
1715: }

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

1721:   Not collective

1723:   Input Parameters:
1724: + dm        - The DM object
1725: . numFields - The number of fields in this subproblem
1726: - fields    - The field numbers of the selected fields

1728:   Output Parameters:
1729: + is - The global indices for the subproblem
1730: - subdm - The DM for the subproblem

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

1734:   Level: intermediate

1736: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1737: @*/
1738: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1739: {

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

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

1755:   Not collective

1757:   Input Parameter:
1758: + dms - The DM objects
1759: - len - The number of DMs

1761:   Output Parameters:
1762: + is - The global indices for the subproblem, or NULL
1763: - superdm - The DM for the superproblem

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

1767:   Level: intermediate

1769: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1770: @*/
1771: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1772: {
1773:   PetscInt       i;

1781:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1782:   if (len) {
1783:     DM dm = dms[0];
1784:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
1785:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1786:   }
1787:   return(0);
1788: }


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

1798:   Not collective

1800:   Input Parameter:
1801: . dm - the DM object

1803:   Output Parameters:
1804: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1805: . namelist    - The name for each subdomain (or NULL if not requested)
1806: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1807: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1808: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1810:   Level: intermediate

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

1817: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1818: @*/
1819: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1820: {
1821:   PetscErrorCode      ierr;
1822:   DMSubDomainHookLink link;
1823:   PetscInt            i,l;

1832:   /*
1833:    Is it a good idea to apply the following check across all impls?
1834:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1835:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1836:    */
1837:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1838:   if (dm->ops->createdomaindecomposition) {
1839:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1840:     /* copy subdomain hooks and context over to the subdomain DMs */
1841:     if (dmlist && *dmlist) {
1842:       for (i = 0; i < l; i++) {
1843:         for (link=dm->subdomainhook; link; link=link->next) {
1844:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1845:         }
1846:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1847:       }
1848:     }
1849:     if (len) *len = l;
1850:   }
1851:   return(0);
1852: }


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

1858:   Not collective

1860:   Input Parameters:
1861: + dm - the DM object
1862: . n  - the number of subdomain scatters
1863: - subdms - the local subdomains

1865:   Output Parameters:
1866: + n     - the number of scatters returned
1867: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1868: . oscat - scatter from global vector to overlapping global vector entries on subdomain
1869: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

1877:   Level: developer

1879: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1880: @*/
1881: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1882: {

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

1893: /*@
1894:   DMRefine - Refines a DM object

1896:   Collective on dm

1898:   Input Parameter:
1899: + dm   - the DM object
1900: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

1902:   Output Parameter:
1903: . dmf - the refined DM, or NULL

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

1907:   Level: developer

1909: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1910: @*/
1911: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1912: {
1913:   PetscErrorCode   ierr;
1914:   DMRefineHookLink link;

1918:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
1919:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
1920:   (*dm->ops->refine)(dm,comm,dmf);
1921:   if (*dmf) {
1922:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

1926:     (*dmf)->ctx       = dm->ctx;
1927:     (*dmf)->leveldown = dm->leveldown;
1928:     (*dmf)->levelup   = dm->levelup + 1;

1930:     DMSetMatType(*dmf,dm->mattype);
1931:     for (link=dm->refinehook; link; link=link->next) {
1932:       if (link->refinehook) {
1933:         (*link->refinehook)(dm,*dmf,link->ctx);
1934:       }
1935:     }
1936:   }
1937:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
1938:   return(0);
1939: }

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

1944:    Logically Collective

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

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

1955: +  coarse - coarse level DM
1956: .  fine - fine level DM to interpolate problem to
1957: -  ctx - optional user-defined function context

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

1962: +  coarse - coarse level DM
1963: .  interp - matrix interpolating a coarse-level solution to the finer grid
1964: .  fine - fine level DM to update
1965: -  ctx - optional user-defined function context

1967:    Level: advanced

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

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

1974:    This function is currently not available from Fortran.

1976: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1977: @*/
1978: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1979: {
1980:   PetscErrorCode   ierr;
1981:   DMRefineHookLink link,*p;

1985:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
1986:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
1987:   }
1988:   PetscNew(&link);
1989:   link->refinehook = refinehook;
1990:   link->interphook = interphook;
1991:   link->ctx        = ctx;
1992:   link->next       = NULL;
1993:   *p               = link;
1994:   return(0);
1995: }

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

2000:    Logically Collective

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

2008:    Level: advanced

2010:    Notes:
2011:    This function does nothing if the hook is not in the list.

2013:    This function is currently not available from Fortran.

2015: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2016: @*/
2017: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2018: {
2019:   PetscErrorCode   ierr;
2020:   DMRefineHookLink link,*p;

2024:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2025:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2026:       link = *p;
2027:       *p = link->next;
2028:       PetscFree(link);
2029:       break;
2030:     }
2031:   }
2032:   return(0);
2033: }

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

2038:    Collective if any hooks are

2040:    Input Arguments:
2041: +  coarse - coarser DM to use as a base
2042: .  interp - interpolation matrix, apply using MatInterpolate()
2043: -  fine - finer DM to update

2045:    Level: developer

2047: .seealso: DMRefineHookAdd(), MatInterpolate()
2048: @*/
2049: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2050: {
2051:   PetscErrorCode   ierr;
2052:   DMRefineHookLink link;

2055:   for (link=fine->refinehook; link; link=link->next) {
2056:     if (link->interphook) {
2057:       (*link->interphook)(coarse,interp,fine,link->ctx);
2058:     }
2059:   }
2060:   return(0);
2061: }

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

2066:     Not Collective

2068:     Input Parameter:
2069: .   dm - the DM object

2071:     Output Parameter:
2072: .   level - number of refinements

2074:     Level: developer

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

2078: @*/
2079: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2080: {
2083:   *level = dm->levelup;
2084:   return(0);
2085: }

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

2090:     Not Collective

2092:     Input Parameter:
2093: +   dm - the DM object
2094: -   level - number of refinements

2096:     Level: advanced

2098:     Notes:
2099:     This value is used by PCMG to determine how many multigrid levels to use

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

2103: @*/
2104: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2105: {
2108:   dm->levelup = level;
2109:   return(0);
2110: }

2112: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2113: {
2117:   *tdm = dm->transformDM;
2118:   return(0);
2119: }

2121: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2122: {
2126:   *tv = dm->transform;
2127:   return(0);
2128: }

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

2133:   Input Parameter:
2134: . dm - The DM

2136:   Output Parameter:
2137: . flg - PETSC_TRUE if a basis transformation should be done

2139:   Level: developer

2141: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()()
2142: @*/
2143: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2144: {
2145:   Vec            tv;

2151:   DMGetBasisTransformVec_Internal(dm, &tv);
2152:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2153:   return(0);
2154: }

2156: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2157: {
2158:   PetscSection   s, ts;
2159:   PetscScalar   *ta;
2160:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2164:   DMGetCoordinateDim(dm, &cdim);
2165:   DMGetLocalSection(dm, &s);
2166:   PetscSectionGetChart(s, &pStart, &pEnd);
2167:   PetscSectionGetNumFields(s, &Nf);
2168:   DMClone(dm, &dm->transformDM);
2169:   DMGetLocalSection(dm->transformDM, &ts);
2170:   PetscSectionSetNumFields(ts, Nf);
2171:   PetscSectionSetChart(ts, pStart, pEnd);
2172:   for (f = 0; f < Nf; ++f) {
2173:     PetscSectionGetFieldComponents(s, f, &Nc);
2174:     /* We could start to label fields by their transformation properties */
2175:     if (Nc != cdim) continue;
2176:     for (p = pStart; p < pEnd; ++p) {
2177:       PetscSectionGetFieldDof(s, p, f, &dof);
2178:       if (!dof) continue;
2179:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2180:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2181:     }
2182:   }
2183:   PetscSectionSetUp(ts);
2184:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2185:   VecGetArray(dm->transform, &ta);
2186:   for (p = pStart; p < pEnd; ++p) {
2187:     for (f = 0; f < Nf; ++f) {
2188:       PetscSectionGetFieldDof(ts, p, f, &dof);
2189:       if (dof) {
2190:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2191:         PetscScalar       *tva;
2192:         const PetscScalar *A;

2194:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2195:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2196:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2197:         PetscArraycpy(tva, A, PetscSqr(cdim));
2198:       }
2199:     }
2200:   }
2201:   VecRestoreArray(dm->transform, &ta);
2202:   return(0);
2203: }

2205: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2206: {

2212:   newdm->transformCtx       = dm->transformCtx;
2213:   newdm->transformSetUp     = dm->transformSetUp;
2214:   newdm->transformDestroy   = NULL;
2215:   newdm->transformGetMatrix = dm->transformGetMatrix;
2216:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2217:   return(0);
2218: }

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

2223:    Logically Collective

2225:    Input Arguments:
2226: +  dm - the DM
2227: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2228: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2229: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2234: +  dm - global DM
2235: .  g - global vector
2236: .  mode - mode
2237: .  l - local vector
2238: -  ctx - optional user-defined function context


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

2244: +  global - global DM
2245: -  ctx - optional user-defined function context

2247:    Level: advanced

2249: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2250: @*/
2251: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2252: {
2253:   PetscErrorCode          ierr;
2254:   DMGlobalToLocalHookLink link,*p;

2258:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2259:   PetscNew(&link);
2260:   link->beginhook = beginhook;
2261:   link->endhook   = endhook;
2262:   link->ctx       = ctx;
2263:   link->next      = NULL;
2264:   *p              = link;
2265:   return(0);
2266: }

2268: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2269: {
2270:   Mat cMat;
2271:   Vec cVec;
2272:   PetscSection section, cSec;
2273:   PetscInt pStart, pEnd, p, dof;

2278:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2279:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2280:     PetscInt nRows;

2282:     MatGetSize(cMat,&nRows,NULL);
2283:     if (nRows <= 0) return(0);
2284:     DMGetLocalSection(dm,&section);
2285:     MatCreateVecs(cMat,NULL,&cVec);
2286:     MatMult(cMat,l,cVec);
2287:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2288:     for (p = pStart; p < pEnd; p++) {
2289:       PetscSectionGetDof(cSec,p,&dof);
2290:       if (dof) {
2291:         PetscScalar *vals;
2292:         VecGetValuesSection(cVec,cSec,p,&vals);
2293:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2294:       }
2295:     }
2296:     VecDestroy(&cVec);
2297:   }
2298:   return(0);
2299: }

2301: /*@
2302:     DMGlobalToLocal - update local vectors from global vector

2304:     Neighbor-wise Collective on dm

2306:     Input Parameters:
2307: +   dm - the DM object
2308: .   g - the global vector
2309: .   mode - INSERT_VALUES or ADD_VALUES
2310: -   l - the local vector

2312:     Notes:
2313:     The communication involved in this update can be overlapped with computation by using
2314:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2316:     Level: beginner

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

2320: @*/
2321: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2322: {

2326:   DMGlobalToLocalBegin(dm,g,mode,l);
2327:   DMGlobalToLocalEnd(dm,g,mode,l);
2328:   return(0);
2329: }

2331: /*@
2332:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2334:     Neighbor-wise Collective on dm

2336:     Input Parameters:
2337: +   dm - the DM object
2338: .   g - the global vector
2339: .   mode - INSERT_VALUES or ADD_VALUES
2340: -   l - the local vector

2342:     Level: intermediate

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

2346: @*/
2347: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2348: {
2349:   PetscSF                 sf;
2350:   PetscErrorCode          ierr;
2351:   DMGlobalToLocalHookLink link;

2355:   for (link=dm->gtolhook; link; link=link->next) {
2356:     if (link->beginhook) {
2357:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2358:     }
2359:   }
2360:   DMGetSectionSF(dm, &sf);
2361:   if (sf) {
2362:     const PetscScalar *gArray;
2363:     PetscScalar       *lArray;

2365:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2366:     VecGetArray(l, &lArray);
2367:     VecGetArrayRead(g, &gArray);
2368:     PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
2369:     VecRestoreArray(l, &lArray);
2370:     VecRestoreArrayRead(g, &gArray);
2371:   } else {
2372:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2373:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2374:   }
2375:   return(0);
2376: }

2378: /*@
2379:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2381:     Neighbor-wise Collective on dm

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

2389:     Level: intermediate

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

2393: @*/
2394: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2395: {
2396:   PetscSF                 sf;
2397:   PetscErrorCode          ierr;
2398:   const PetscScalar      *gArray;
2399:   PetscScalar            *lArray;
2400:   PetscBool               transform;
2401:   DMGlobalToLocalHookLink link;

2405:   DMGetSectionSF(dm, &sf);
2406:   DMHasBasisTransform(dm, &transform);
2407:   if (sf) {
2408:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2410:     VecGetArray(l, &lArray);
2411:     VecGetArrayRead(g, &gArray);
2412:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2413:     VecRestoreArray(l, &lArray);
2414:     VecRestoreArrayRead(g, &gArray);
2415:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
2416:   } else {
2417:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
2418:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2419:   }
2420:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2421:   for (link=dm->gtolhook; link; link=link->next) {
2422:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2423:   }
2424:   return(0);
2425: }

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

2430:    Logically Collective

2432:    Input Arguments:
2433: +  dm - the DM
2434: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2435: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2436: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2441: +  dm - global DM
2442: .  l - local vector
2443: .  mode - mode
2444: .  g - global vector
2445: -  ctx - optional user-defined function context


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

2451: +  global - global DM
2452: .  l - local vector
2453: .  mode - mode
2454: .  g - global vector
2455: -  ctx - optional user-defined function context

2457:    Level: advanced

2459: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2460: @*/
2461: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2462: {
2463:   PetscErrorCode          ierr;
2464:   DMLocalToGlobalHookLink link,*p;

2468:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2469:   PetscNew(&link);
2470:   link->beginhook = beginhook;
2471:   link->endhook   = endhook;
2472:   link->ctx       = ctx;
2473:   link->next      = NULL;
2474:   *p              = link;
2475:   return(0);
2476: }

2478: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2479: {
2480:   Mat cMat;
2481:   Vec cVec;
2482:   PetscSection section, cSec;
2483:   PetscInt pStart, pEnd, p, dof;

2488:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2489:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2490:     PetscInt nRows;

2492:     MatGetSize(cMat,&nRows,NULL);
2493:     if (nRows <= 0) return(0);
2494:     DMGetLocalSection(dm,&section);
2495:     MatCreateVecs(cMat,NULL,&cVec);
2496:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2497:     for (p = pStart; p < pEnd; p++) {
2498:       PetscSectionGetDof(cSec,p,&dof);
2499:       if (dof) {
2500:         PetscInt d;
2501:         PetscScalar *vals;
2502:         VecGetValuesSection(l,section,p,&vals);
2503:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2504:         /* for this to be the true transpose, we have to zero the values that
2505:          * we just extracted */
2506:         for (d = 0; d < dof; d++) {
2507:           vals[d] = 0.;
2508:         }
2509:       }
2510:     }
2511:     MatMultTransposeAdd(cMat,cVec,l,l);
2512:     VecDestroy(&cVec);
2513:   }
2514:   return(0);
2515: }
2516: /*@
2517:     DMLocalToGlobal - updates global vectors from local vectors

2519:     Neighbor-wise Collective on dm

2521:     Input Parameters:
2522: +   dm - the DM object
2523: .   l - the local vector
2524: .   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.
2525: -   g - the global vector

2527:     Notes:
2528:     The communication involved in this update can be overlapped with computation by using
2529:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2534:     Level: beginner

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

2538: @*/
2539: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2540: {

2544:   DMLocalToGlobalBegin(dm,l,mode,g);
2545:   DMLocalToGlobalEnd(dm,l,mode,g);
2546:   return(0);
2547: }

2549: /*@
2550:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2552:     Neighbor-wise Collective on dm

2554:     Input Parameters:
2555: +   dm - the DM object
2556: .   l - the local vector
2557: .   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.
2558: -   g - the global vector

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

2564:     Level: intermediate

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

2568: @*/
2569: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2570: {
2571:   PetscSF                 sf;
2572:   PetscSection            s, gs;
2573:   DMLocalToGlobalHookLink link;
2574:   Vec                     tmpl;
2575:   const PetscScalar      *lArray;
2576:   PetscScalar            *gArray;
2577:   PetscBool               isInsert, transform;
2578:   PetscErrorCode          ierr;

2582:   for (link=dm->ltoghook; link; link=link->next) {
2583:     if (link->beginhook) {
2584:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2585:     }
2586:   }
2587:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2588:   DMGetSectionSF(dm, &sf);
2589:   DMGetLocalSection(dm, &s);
2590:   switch (mode) {
2591:   case INSERT_VALUES:
2592:   case INSERT_ALL_VALUES:
2593:   case INSERT_BC_VALUES:
2594:     isInsert = PETSC_TRUE; break;
2595:   case ADD_VALUES:
2596:   case ADD_ALL_VALUES:
2597:   case ADD_BC_VALUES:
2598:     isInsert = PETSC_FALSE; break;
2599:   default:
2600:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2601:   }
2602:   if ((sf && !isInsert) || (s && isInsert)) {
2603:     DMHasBasisTransform(dm, &transform);
2604:     if (transform) {
2605:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2606:       VecCopy(l, tmpl);
2607:       DMPlexLocalToGlobalBasis(dm, tmpl);
2608:       VecGetArrayRead(tmpl, &lArray);
2609:     } else {
2610:       VecGetArrayRead(l, &lArray);
2611:     }
2612:     VecGetArray(g, &gArray);
2613:     if (sf && !isInsert) {
2614:       PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2615:     } else if (s && isInsert) {
2616:       PetscInt gStart, pStart, pEnd, p;

2618:       DMGetGlobalSection(dm, &gs);
2619:       PetscSectionGetChart(s, &pStart, &pEnd);
2620:       VecGetOwnershipRange(g, &gStart, NULL);
2621:       for (p = pStart; p < pEnd; ++p) {
2622:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2624:         PetscSectionGetDof(s, p, &dof);
2625:         PetscSectionGetDof(gs, p, &gdof);
2626:         PetscSectionGetConstraintDof(s, p, &cdof);
2627:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2628:         PetscSectionGetOffset(s, p, &off);
2629:         PetscSectionGetOffset(gs, p, &goff);
2630:         /* Ignore off-process data and points with no global data */
2631:         if (!gdof || goff < 0) continue;
2632:         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);
2633:         /* If no constraints are enforced in the global vector */
2634:         if (!gcdof) {
2635:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2636:           /* If constraints are enforced in the global vector */
2637:         } else if (cdof == gcdof) {
2638:           const PetscInt *cdofs;
2639:           PetscInt        cind = 0;

2641:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2642:           for (d = 0, e = 0; d < dof; ++d) {
2643:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2644:             gArray[goff-gStart+e++] = lArray[off+d];
2645:           }
2646:         } 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);
2647:       }
2648:     }
2649:     VecRestoreArray(g, &gArray);
2650:     if (transform) {
2651:       VecRestoreArrayRead(tmpl, &lArray);
2652:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2653:     } else {
2654:       VecRestoreArrayRead(l, &lArray);
2655:     }
2656:   } else {
2657:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
2658:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2659:   }
2660:   return(0);
2661: }

2663: /*@
2664:     DMLocalToGlobalEnd - 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 - INSERT_VALUES or ADD_VALUES
2672: -   g - the global vector

2674:     Level: intermediate

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

2678: @*/
2679: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2680: {
2681:   PetscSF                 sf;
2682:   PetscSection            s;
2683:   DMLocalToGlobalHookLink link;
2684:   PetscBool               isInsert, transform;
2685:   PetscErrorCode          ierr;

2689:   DMGetSectionSF(dm, &sf);
2690:   DMGetLocalSection(dm, &s);
2691:   switch (mode) {
2692:   case INSERT_VALUES:
2693:   case INSERT_ALL_VALUES:
2694:     isInsert = PETSC_TRUE; break;
2695:   case ADD_VALUES:
2696:   case ADD_ALL_VALUES:
2697:     isInsert = PETSC_FALSE; break;
2698:   default:
2699:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2700:   }
2701:   if (sf && !isInsert) {
2702:     const PetscScalar *lArray;
2703:     PetscScalar       *gArray;
2704:     Vec                tmpl;

2706:     DMHasBasisTransform(dm, &transform);
2707:     if (transform) {
2708:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2709:       VecGetArrayRead(tmpl, &lArray);
2710:     } else {
2711:       VecGetArrayRead(l, &lArray);
2712:     }
2713:     VecGetArray(g, &gArray);
2714:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2715:     if (transform) {
2716:       VecRestoreArrayRead(tmpl, &lArray);
2717:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2718:     } else {
2719:       VecRestoreArrayRead(l, &lArray);
2720:     }
2721:     VecRestoreArray(g, &gArray);
2722:   } else if (s && isInsert) {
2723:   } else {
2724:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
2725:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2726:   }
2727:   for (link=dm->ltoghook; link; link=link->next) {
2728:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2729:   }
2730:   return(0);
2731: }

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

2738:    Neighbor-wise Collective on dm

2740:    Input Parameters:
2741: +  dm - the DM object
2742: .  g - the original local vector
2743: -  mode - one of INSERT_VALUES or ADD_VALUES

2745:    Output Parameter:
2746: .  l  - the local vector with correct ghost values

2748:    Level: intermediate

2750:    Notes:
2751:    The local vectors used here need not be the same as those
2752:    obtained from DMCreateLocalVector(), BUT they
2753:    must have the same parallel data layout; they could, for example, be
2754:    obtained with VecDuplicate() from the DM originating vectors.

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

2758: @*/
2759: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2760: {
2761:   PetscErrorCode          ierr;

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

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

2775:    Neighbor-wise Collective on dm

2777:    Input Parameters:
2778: +  da - the DM object
2779: .  g - the original local vector
2780: -  mode - one of INSERT_VALUES or ADD_VALUES

2782:    Output Parameter:
2783: .  l  - the local vector with correct ghost values

2785:    Level: intermediate

2787:    Notes:
2788:    The local vectors used here need not be the same as those
2789:    obtained from DMCreateLocalVector(), BUT they
2790:    must have the same parallel data layout; they could, for example, be
2791:    obtained with VecDuplicate() from the DM originating vectors.

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

2795: @*/
2796: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2797: {
2798:   PetscErrorCode          ierr;

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


2808: /*@
2809:     DMCoarsen - Coarsens a DM object

2811:     Collective on dm

2813:     Input Parameter:
2814: +   dm - the DM object
2815: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2817:     Output Parameter:
2818: .   dmc - the coarsened DM

2820:     Level: developer

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

2824: @*/
2825: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2826: {
2827:   PetscErrorCode    ierr;
2828:   DMCoarsenHookLink link;

2832:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
2833:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2834:   (*dm->ops->coarsen)(dm, comm, dmc);
2835:   if (*dmc) {
2836:     DMSetCoarseDM(dm,*dmc);
2837:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2838:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2839:     (*dmc)->ctx               = dm->ctx;
2840:     (*dmc)->levelup           = dm->levelup;
2841:     (*dmc)->leveldown         = dm->leveldown + 1;
2842:     DMSetMatType(*dmc,dm->mattype);
2843:     for (link=dm->coarsenhook; link; link=link->next) {
2844:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2845:     }
2846:   }
2847:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
2848:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2849:   return(0);
2850: }

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

2855:    Logically Collective

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

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

2866: +  fine - fine level DM
2867: .  coarse - coarse level DM to restrict problem to
2868: -  ctx - optional user-defined function context

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

2873: +  fine - fine level DM
2874: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2875: .  rscale - scaling vector for restriction
2876: .  inject - matrix restricting by injection
2877: .  coarse - coarse level DM to update
2878: -  ctx - optional user-defined function context

2880:    Level: advanced

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

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

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

2890:    This function is currently not available from Fortran.

2892: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2893: @*/
2894: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2895: {
2896:   PetscErrorCode    ierr;
2897:   DMCoarsenHookLink link,*p;

2901:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2902:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2903:   }
2904:   PetscNew(&link);
2905:   link->coarsenhook  = coarsenhook;
2906:   link->restricthook = restricthook;
2907:   link->ctx          = ctx;
2908:   link->next         = NULL;
2909:   *p                 = link;
2910:   return(0);
2911: }

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

2916:    Logically Collective

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

2924:    Level: advanced

2926:    Notes:
2927:    This function does nothing if the hook is not in the list.

2929:    This function is currently not available from Fortran.

2931: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2932: @*/
2933: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2934: {
2935:   PetscErrorCode    ierr;
2936:   DMCoarsenHookLink link,*p;

2940:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2941:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2942:       link = *p;
2943:       *p = link->next;
2944:       PetscFree(link);
2945:       break;
2946:     }
2947:   }
2948:   return(0);
2949: }


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

2955:    Collective if any hooks are

2957:    Input Arguments:
2958: +  fine - finer DM to use as a base
2959: .  restrct - restriction matrix, apply using MatRestrict()
2960: .  rscale - scaling vector for restriction
2961: .  inject - injection matrix, also use MatRestrict()
2962: -  coarse - coarser DM to update

2964:    Level: developer

2966: .seealso: DMCoarsenHookAdd(), MatRestrict()
2967: @*/
2968: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2969: {
2970:   PetscErrorCode    ierr;
2971:   DMCoarsenHookLink link;

2974:   for (link=fine->coarsenhook; link; link=link->next) {
2975:     if (link->restricthook) {
2976:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
2977:     }
2978:   }
2979:   return(0);
2980: }

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

2985:    Logically Collective on global

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


2994:    Calling sequence for ddhook:
2995: $    ddhook(DM global,DM block,void *ctx)

2997: +  global - global DM
2998: .  block  - block DM
2999: -  ctx - optional user-defined function context

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

3004: +  global - global DM
3005: .  out    - scatter to the outer (with ghost and overlap points) block vector
3006: .  in     - scatter to block vector values only owned locally
3007: .  block  - block DM
3008: -  ctx - optional user-defined function context

3010:    Level: advanced

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

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

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

3020:    This function is currently not available from Fortran.

3022: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3023: @*/
3024: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3025: {
3026:   PetscErrorCode      ierr;
3027:   DMSubDomainHookLink link,*p;

3031:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3032:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
3033:   }
3034:   PetscNew(&link);
3035:   link->restricthook = restricthook;
3036:   link->ddhook       = ddhook;
3037:   link->ctx          = ctx;
3038:   link->next         = NULL;
3039:   *p                 = link;
3040:   return(0);
3041: }

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

3046:    Logically Collective

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

3054:    Level: advanced

3056:    Notes:

3058:    This function is currently not available from Fortran.

3060: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3061: @*/
3062: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3063: {
3064:   PetscErrorCode      ierr;
3065:   DMSubDomainHookLink link,*p;

3069:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3070:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3071:       link = *p;
3072:       *p = link->next;
3073:       PetscFree(link);
3074:       break;
3075:     }
3076:   }
3077:   return(0);
3078: }

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

3083:    Collective if any hooks are

3085:    Input Arguments:
3086: +  fine - finer DM to use as a base
3087: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3088: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3089: -  coarse - coarer DM to update

3091:    Level: developer

3093: .seealso: DMCoarsenHookAdd(), MatRestrict()
3094: @*/
3095: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3096: {
3097:   PetscErrorCode      ierr;
3098:   DMSubDomainHookLink link;

3101:   for (link=global->subdomainhook; link; link=link->next) {
3102:     if (link->restricthook) {
3103:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3104:     }
3105:   }
3106:   return(0);
3107: }

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

3112:     Not Collective

3114:     Input Parameter:
3115: .   dm - the DM object

3117:     Output Parameter:
3118: .   level - number of coarsenings

3120:     Level: developer

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

3124: @*/
3125: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3126: {
3130:   *level = dm->leveldown;
3131:   return(0);
3132: }

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

3137:     Not Collective

3139:     Input Parameters:
3140: +   dm - the DM object
3141: -   level - number of coarsenings

3143:     Level: developer

3145: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3146: @*/
3147: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3148: {
3151:   dm->leveldown = level;
3152:   return(0);
3153: }



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

3160:     Collective on dm

3162:     Input Parameter:
3163: +   dm - the DM object
3164: -   nlevels - the number of levels of refinement

3166:     Output Parameter:
3167: .   dmf - the refined DM hierarchy

3169:     Level: developer

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

3173: @*/
3174: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3175: {

3180:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3181:   if (nlevels == 0) return(0);
3183:   if (dm->ops->refinehierarchy) {
3184:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3185:   } else if (dm->ops->refine) {
3186:     PetscInt i;

3188:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3189:     for (i=1; i<nlevels; i++) {
3190:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3191:     }
3192:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3193:   return(0);
3194: }

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

3199:     Collective on dm

3201:     Input Parameter:
3202: +   dm - the DM object
3203: -   nlevels - the number of levels of coarsening

3205:     Output Parameter:
3206: .   dmc - the coarsened DM hierarchy

3208:     Level: developer

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

3212: @*/
3213: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3214: {

3219:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
3220:   if (nlevels == 0) return(0);
3222:   if (dm->ops->coarsenhierarchy) {
3223:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3224:   } else if (dm->ops->coarsen) {
3225:     PetscInt i;

3227:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3228:     for (i=1; i<nlevels; i++) {
3229:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3230:     }
3231:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3232:   return(0);
3233: }

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

3238:     Not Collective

3240:     Input Parameters:
3241: +   dm - the DM object
3242: -   destroy - the destroy function

3244:     Level: intermediate

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

3248: @*/
3249: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3250: {
3253:   dm->ctxdestroy = destroy;
3254:   return(0);
3255: }

3257: /*@
3258:     DMSetApplicationContext - Set a user context into a DM object

3260:     Not Collective

3262:     Input Parameters:
3263: +   dm - the DM object
3264: -   ctx - the user context

3266:     Level: intermediate

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

3270: @*/
3271: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3272: {
3275:   dm->ctx = ctx;
3276:   return(0);
3277: }

3279: /*@
3280:     DMGetApplicationContext - Gets a user context from a DM object

3282:     Not Collective

3284:     Input Parameter:
3285: .   dm - the DM object

3287:     Output Parameter:
3288: .   ctx - the user context

3290:     Level: intermediate

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

3294: @*/
3295: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3296: {
3299:   *(void**)ctx = dm->ctx;
3300:   return(0);
3301: }

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

3306:     Logically Collective on dm

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

3312:     Level: intermediate

3314: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3315:          DMSetJacobian()

3317: @*/
3318: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3319: {
3322:   dm->ops->computevariablebounds = f;
3323:   return(0);
3324: }

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

3329:     Not Collective

3331:     Input Parameter:
3332: .   dm - the DM object to destroy

3334:     Output Parameter:
3335: .   flg - PETSC_TRUE if the variable bounds function exists

3337:     Level: developer

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

3341: @*/
3342: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3343: {
3347:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3348:   return(0);
3349: }

3351: /*@C
3352:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3354:     Logically Collective on dm

3356:     Input Parameters:
3357: .   dm - the DM object

3359:     Output parameters:
3360: +   xl - lower bound
3361: -   xu - upper bound

3363:     Level: advanced

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

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

3370: @*/
3371: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3372: {

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

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

3387:     Not Collective

3389:     Input Parameter:
3390: .   dm - the DM object

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

3395:     Level: developer

3397: .seealso DMCreateColoring()

3399: @*/
3400: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3401: {
3405:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3406:   return(0);
3407: }

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

3412:     Not Collective

3414:     Input Parameter:
3415: .   dm - the DM object

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

3420:     Level: developer

3422: .seealso DMCreateRestriction()

3424: @*/
3425: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3426: {
3430:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3431:   return(0);
3432: }


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

3438:     Not Collective

3440:     Input Parameter:
3441: .   dm - the DM object

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

3446:     Level: developer

3448: .seealso DMCreateInjection()

3450: @*/
3451: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3452: {

3458:   if (dm->ops->hascreateinjection) {
3459:     (*dm->ops->hascreateinjection)(dm,flg);
3460:   } else {
3461:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3462:   }
3463:   return(0);
3464: }


3467: /*@C
3468:     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.

3470:     Collective on dm

3472:     Input Parameter:
3473: +   dm - the DM object
3474: -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.

3476:     Level: developer

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

3480: @*/
3481: PetscErrorCode  DMSetVec(DM dm,Vec x)
3482: {

3487:   if (x) {
3488:     if (!dm->x) {
3489:       DMCreateGlobalVector(dm,&dm->x);
3490:     }
3491:     VecCopy(x,dm->x);
3492:   } else if (dm->x) {
3493:     VecDestroy(&dm->x);
3494:   }
3495:   return(0);
3496: }

3498: PetscFunctionList DMList              = NULL;
3499: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3501: /*@C
3502:   DMSetType - Builds a DM, for a particular DM implementation.

3504:   Collective on dm

3506:   Input Parameters:
3507: + dm     - The DM object
3508: - method - The name of the DM type

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

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

3516:   Level: intermediate

3518: .seealso: DMGetType(), DMCreate()
3519: @*/
3520: PetscErrorCode  DMSetType(DM dm, DMType method)
3521: {
3522:   PetscErrorCode (*r)(DM);
3523:   PetscBool      match;

3528:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3529:   if (match) return(0);

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

3535:   if (dm->ops->destroy) {
3536:     (*dm->ops->destroy)(dm);
3537:   }
3538:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3539:   PetscObjectChangeTypeName((PetscObject)dm,method);
3540:   (*r)(dm);
3541:   return(0);
3542: }

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

3547:   Not Collective

3549:   Input Parameter:
3550: . dm  - The DM

3552:   Output Parameter:
3553: . type - The DM type name

3555:   Level: intermediate

3557: .seealso: DMSetType(), DMCreate()
3558: @*/
3559: PetscErrorCode  DMGetType(DM dm, DMType *type)
3560: {

3566:   DMRegisterAll();
3567:   *type = ((PetscObject)dm)->type_name;
3568:   return(0);
3569: }

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

3574:   Collective on dm

3576:   Input Parameters:
3577: + dm - the DM
3578: - newtype - new DM type (use "same" for the same type)

3580:   Output Parameter:
3581: . M - pointer to new DM

3583:   Notes:
3584:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3585:   the MPI communicator of the generated DM is always the same as the communicator
3586:   of the input DM.

3588:   Level: intermediate

3590: .seealso: DMCreate()
3591: @*/
3592: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3593: {
3594:   DM             B;
3595:   char           convname[256];
3596:   PetscBool      sametype/*, issame */;

3603:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3604:   /* PetscStrcmp(newtype, "same", &issame); */
3605:   if (sametype) {
3606:     *M   = dm;
3607:     PetscObjectReference((PetscObject) dm);
3608:     return(0);
3609:   } else {
3610:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3612:     /*
3613:        Order of precedence:
3614:        1) See if a specialized converter is known to the current DM.
3615:        2) See if a specialized converter is known to the desired DM class.
3616:        3) See if a good general converter is registered for the desired class
3617:        4) See if a good general converter is known for the current matrix.
3618:        5) Use a really basic converter.
3619:     */

3621:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3622:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3623:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3624:     PetscStrlcat(convname,"_",sizeof(convname));
3625:     PetscStrlcat(convname,newtype,sizeof(convname));
3626:     PetscStrlcat(convname,"_C",sizeof(convname));
3627:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3628:     if (conv) goto foundconv;

3630:     /* 2)  See if a specialized converter is known to the desired DM class. */
3631:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3632:     DMSetType(B, newtype);
3633:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3634:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3635:     PetscStrlcat(convname,"_",sizeof(convname));
3636:     PetscStrlcat(convname,newtype,sizeof(convname));
3637:     PetscStrlcat(convname,"_C",sizeof(convname));
3638:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3639:     if (conv) {
3640:       DMDestroy(&B);
3641:       goto foundconv;
3642:     }

3644: #if 0
3645:     /* 3) See if a good general converter is registered for the desired class */
3646:     conv = B->ops->convertfrom;
3647:     DMDestroy(&B);
3648:     if (conv) goto foundconv;

3650:     /* 4) See if a good general converter is known for the current matrix */
3651:     if (dm->ops->convert) {
3652:       conv = dm->ops->convert;
3653:     }
3654:     if (conv) goto foundconv;
3655: #endif

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

3660: foundconv:
3661:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3662:     (*conv)(dm,newtype,M);
3663:     /* Things that are independent of DM type: We should consult DMClone() here */
3664:     {
3665:       PetscBool             isper;
3666:       const PetscReal      *maxCell, *L;
3667:       const DMBoundaryType *bd;
3668:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3669:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3670:     }
3671:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3672:   }
3673:   PetscObjectStateIncrease((PetscObject) *M);
3674:   return(0);
3675: }

3677: /*--------------------------------------------------------------------------------------------------------------------*/

3679: /*@C
3680:   DMRegister -  Adds a new DM component implementation

3682:   Not Collective

3684:   Input Parameters:
3685: + name        - The name of a new user-defined creation routine
3686: - create_func - The creation routine itself

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


3692:   Sample usage:
3693: .vb
3694:     DMRegister("my_da", MyDMCreate);
3695: .ve

3697:   Then, your DM type can be chosen with the procedural interface via
3698: .vb
3699:     DMCreate(MPI_Comm, DM *);
3700:     DMSetType(DM,"my_da");
3701: .ve
3702:    or at runtime via the option
3703: .vb
3704:     -da_type my_da
3705: .ve

3707:   Level: advanced

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

3711: @*/
3712: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3713: {

3717:   DMInitializePackage();
3718:   PetscFunctionListAdd(&DMList,sname,function);
3719:   return(0);
3720: }

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

3725:   Collective on viewer

3727:   Input Parameters:
3728: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3729:            some related function before a call to DMLoad().
3730: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3731:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3733:    Level: intermediate

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

3738:   Notes for advanced users:
3739:   Most users should not need to know the details of the binary storage
3740:   format, since DMLoad() and DMView() completely hide these details.
3741:   But for anyone who's interested, the standard binary matrix storage
3742:   format is
3743: .vb
3744:      has not yet been determined
3745: .ve

3747: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3748: @*/
3749: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3750: {
3751:   PetscBool      isbinary, ishdf5;

3757:   PetscViewerCheckReadable(viewer);
3758:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3759:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3760:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3761:   if (isbinary) {
3762:     PetscInt classid;
3763:     char     type[256];

3765:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3766:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3767:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3768:     DMSetType(newdm, type);
3769:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3770:   } else if (ishdf5) {
3771:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3772:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3773:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3774:   return(0);
3775: }

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

3780:   Not collective

3782:   Input Parameter:
3783: . dm - the DM

3785:   Output Parameters:
3786: + lmin - local minimum coordinates (length coord dim, optional)
3787: - lmax - local maximim coordinates (length coord dim, optional)

3789:   Level: beginner

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


3794: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3795: @*/
3796: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3797: {
3798:   Vec                coords = NULL;
3799:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3800:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3801:   const PetscScalar *local_coords;
3802:   PetscInt           N, Ni;
3803:   PetscInt           cdim, i, j;
3804:   PetscErrorCode     ierr;

3808:   DMGetCoordinateDim(dm, &cdim);
3809:   DMGetCoordinates(dm, &coords);
3810:   if (coords) {
3811:     VecGetArrayRead(coords, &local_coords);
3812:     VecGetLocalSize(coords, &N);
3813:     Ni   = N/cdim;
3814:     for (i = 0; i < Ni; ++i) {
3815:       for (j = 0; j < 3; ++j) {
3816:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3817:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3818:       }
3819:     }
3820:     VecRestoreArrayRead(coords, &local_coords);
3821:   } else {
3822:     PetscBool isda;

3824:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3825:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3826:   }
3827:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
3828:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
3829:   return(0);
3830: }

3832: /*@
3833:   DMGetBoundingBox - Returns the global bounding box for the DM.

3835:   Collective

3837:   Input Parameter:
3838: . dm - the DM

3840:   Output Parameters:
3841: + gmin - global minimum coordinates (length coord dim, optional)
3842: - gmax - global maximim coordinates (length coord dim, optional)

3844:   Level: beginner

3846: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3847: @*/
3848: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3849: {
3850:   PetscReal      lmin[3], lmax[3];
3851:   PetscInt       cdim;
3852:   PetscMPIInt    count;

3857:   DMGetCoordinateDim(dm, &cdim);
3858:   PetscMPIIntCast(cdim, &count);
3859:   DMGetLocalBoundingBox(dm, lmin, lmax);
3860:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3861:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3862:   return(0);
3863: }

3865: /******************************** FEM Support **********************************/

3867: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3868: {
3869:   PetscInt       f;

3873:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3874:   for (f = 0; f < len; ++f) {
3875:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
3876:   }
3877:   return(0);
3878: }

3880: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3881: {
3882:   PetscInt       f, g;

3886:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3887:   for (f = 0; f < rows; ++f) {
3888:     PetscPrintf(PETSC_COMM_SELF, "  |");
3889:     for (g = 0; g < cols; ++g) {
3890:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
3891:     }
3892:     PetscPrintf(PETSC_COMM_SELF, " |\n");
3893:   }
3894:   return(0);
3895: }

3897: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3898: {
3899:   PetscInt          localSize, bs;
3900:   PetscMPIInt       size;
3901:   Vec               x, xglob;
3902:   const PetscScalar *xarray;
3903:   PetscErrorCode    ierr;

3906:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
3907:   VecDuplicate(X, &x);
3908:   VecCopy(X, x);
3909:   VecChop(x, tol);
3910:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
3911:   if (size > 1) {
3912:     VecGetLocalSize(x,&localSize);
3913:     VecGetArrayRead(x,&xarray);
3914:     VecGetBlockSize(x,&bs);
3915:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
3916:   } else {
3917:     xglob = x;
3918:   }
3919:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
3920:   if (size > 1) {
3921:     VecDestroy(&xglob);
3922:     VecRestoreArrayRead(x,&xarray);
3923:   }
3924:   VecDestroy(&x);
3925:   return(0);
3926: }

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

3931:   Input Parameter:
3932: . dm - The DM

3934:   Output Parameter:
3935: . section - The PetscSection

3937:   Options Database Keys:
3938: . -dm_petscsection_view - View the Section created by the DM

3940:   Level: advanced

3942:   Notes:
3943:   Use DMGetLocalSection() in new code.

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

3947: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
3948: @*/
3949: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3950: {

3954:   DMGetLocalSection(dm,section);
3955:   return(0);
3956: }

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

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

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

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

3970:   Level: intermediate

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

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

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

3986:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
3987:     (*dm->ops->createlocalsection)(dm);
3988:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
3989:   }
3990:   *section = dm->localSection;
3991:   return(0);
3992: }

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

3997:   Input Parameters:
3998: + dm - The DM
3999: - section - The PetscSection

4001:   Level: advanced

4003:   Notes:
4004:   Use DMSetLocalSection() in new code.

4006:   Any existing Section will be destroyed

4008: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4009: @*/
4010: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4011: {

4015:   DMSetLocalSection(dm,section);
4016:   return(0);
4017: }

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

4022:   Input Parameters:
4023: + dm - The DM
4024: - section - The PetscSection

4026:   Level: intermediate

4028:   Note: Any existing Section will be destroyed

4030: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4031: @*/
4032: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4033: {
4034:   PetscInt       numFields = 0;
4035:   PetscInt       f;

4041:   PetscObjectReference((PetscObject)section);
4042:   PetscSectionDestroy(&dm->localSection);
4043:   dm->localSection = section;
4044:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4045:   if (numFields) {
4046:     DMSetNumFields(dm, numFields);
4047:     for (f = 0; f < numFields; ++f) {
4048:       PetscObject disc;
4049:       const char *name;

4051:       PetscSectionGetFieldName(dm->localSection, f, &name);
4052:       DMGetField(dm, f, NULL, &disc);
4053:       PetscObjectSetName(disc, name);
4054:     }
4055:   }
4056:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4057:   PetscSectionDestroy(&dm->globalSection);
4058:   return(0);
4059: }

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

4064:   not collective

4066:   Input Parameter:
4067: . dm - The DM

4069:   Output Parameter:
4070: + 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.
4071: - 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.

4073:   Level: advanced

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

4077: .seealso: DMSetDefaultConstraints()
4078: @*/
4079: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4080: {

4085:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4086:   if (section) {*section = dm->defaultConstraintSection;}
4087:   if (mat) {*mat = dm->defaultConstraintMat;}
4088:   return(0);
4089: }

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

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

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

4098:   collective on dm

4100:   Input Parameters:
4101: + dm - The DM
4102: + 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).
4103: - 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).

4105:   Level: advanced

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

4109: .seealso: DMGetDefaultConstraints()
4110: @*/
4111: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4112: {
4113:   PetscMPIInt result;

4118:   if (section) {
4120:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4121:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
4122:   }
4123:   if (mat) {
4125:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4126:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
4127:   }
4128:   PetscObjectReference((PetscObject)section);
4129:   PetscSectionDestroy(&dm->defaultConstraintSection);
4130:   dm->defaultConstraintSection = section;
4131:   PetscObjectReference((PetscObject)mat);
4132:   MatDestroy(&dm->defaultConstraintMat);
4133:   dm->defaultConstraintMat = mat;
4134:   return(0);
4135: }

4137: #if defined(PETSC_USE_DEBUG)
4138: /*
4139:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4141:   Input Parameters:
4142: + dm - The DM
4143: . localSection - PetscSection describing the local data layout
4144: - globalSection - PetscSection describing the global data layout

4146:   Level: intermediate

4148: .seealso: DMGetSectionSF(), DMSetSectionSF()
4149: */
4150: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4151: {
4152:   MPI_Comm        comm;
4153:   PetscLayout     layout;
4154:   const PetscInt *ranges;
4155:   PetscInt        pStart, pEnd, p, nroots;
4156:   PetscMPIInt     size, rank;
4157:   PetscBool       valid = PETSC_TRUE, gvalid;
4158:   PetscErrorCode  ierr;

4161:   PetscObjectGetComm((PetscObject)dm,&comm);
4163:   MPI_Comm_size(comm, &size);
4164:   MPI_Comm_rank(comm, &rank);
4165:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4166:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4167:   PetscLayoutCreate(comm, &layout);
4168:   PetscLayoutSetBlockSize(layout, 1);
4169:   PetscLayoutSetLocalSize(layout, nroots);
4170:   PetscLayoutSetUp(layout);
4171:   PetscLayoutGetRanges(layout, &ranges);
4172:   for (p = pStart; p < pEnd; ++p) {
4173:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4175:     PetscSectionGetDof(localSection, p, &dof);
4176:     PetscSectionGetOffset(localSection, p, &off);
4177:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4178:     PetscSectionGetDof(globalSection, p, &gdof);
4179:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4180:     PetscSectionGetOffset(globalSection, p, &goff);
4181:     if (!gdof) continue; /* Censored point */
4182:     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;}
4183:     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;}
4184:     if (gdof < 0) {
4185:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4186:       for (d = 0; d < gsize; ++d) {
4187:         PetscInt offset = -(goff+1) + d, r;

4189:         PetscFindInt(offset,size+1,ranges,&r);
4190:         if (r < 0) r = -(r+2);
4191:         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;}
4192:       }
4193:     }
4194:   }
4195:   PetscLayoutDestroy(&layout);
4196:   PetscSynchronizedFlush(comm, NULL);
4197:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4198:   if (!gvalid) {
4199:     DMView(dm, NULL);
4200:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4201:   }
4202:   return(0);
4203: }
4204: #endif

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

4209:   Collective on dm

4211:   Input Parameter:
4212: . dm - The DM

4214:   Output Parameter:
4215: . section - The PetscSection

4217:   Level: intermediate

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

4221: .seealso: DMSetLocalSection(), DMGetLocalSection()
4222: @*/
4223: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4224: {

4230:   if (!dm->globalSection) {
4231:     PetscSection s;

4233:     DMGetLocalSection(dm, &s);
4234:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4235:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4236:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4237:     PetscLayoutDestroy(&dm->map);
4238:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4239:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4240:   }
4241:   *section = dm->globalSection;
4242:   return(0);
4243: }

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

4248:   Input Parameters:
4249: + dm - The DM
4250: - section - The PetscSection, or NULL

4252:   Level: intermediate

4254:   Note: Any existing Section will be destroyed

4256: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4257: @*/
4258: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4259: {

4265:   PetscObjectReference((PetscObject)section);
4266:   PetscSectionDestroy(&dm->globalSection);
4267:   dm->globalSection = section;
4268: #if defined(PETSC_USE_DEBUG)
4269:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4270: #endif
4271:   return(0);
4272: }

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

4278:   Input Parameter:
4279: . dm - The DM

4281:   Output Parameter:
4282: . sf - The PetscSF

4284:   Level: intermediate

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

4288: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4289: @*/
4290: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4291: {
4292:   PetscInt       nroots;

4298:   if (!dm->sectionSF) {
4299:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4300:   }
4301:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4302:   if (nroots < 0) {
4303:     PetscSection section, gSection;

4305:     DMGetLocalSection(dm, &section);
4306:     if (section) {
4307:       DMGetGlobalSection(dm, &gSection);
4308:       DMCreateSectionSF(dm, section, gSection);
4309:     } else {
4310:       *sf = NULL;
4311:       return(0);
4312:     }
4313:   }
4314:   *sf = dm->sectionSF;
4315:   return(0);
4316: }

4318: /*@
4319:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4321:   Input Parameters:
4322: + dm - The DM
4323: - sf - The PetscSF

4325:   Level: intermediate

4327:   Note: Any previous SF is destroyed

4329: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4330: @*/
4331: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4332: {

4338:   PetscObjectReference((PetscObject) sf);
4339:   PetscSFDestroy(&dm->sectionSF);
4340:   dm->sectionSF = sf;
4341:   return(0);
4342: }

4344: /*@C
4345:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4346:   describing the data layout.

4348:   Input Parameters:
4349: + dm - The DM
4350: . localSection - PetscSection describing the local data layout
4351: - globalSection - PetscSection describing the global data layout

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

4355:   Level: developer

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

4361: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4362: @*/
4363: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4364: {
4365:   MPI_Comm       comm;
4366:   PetscLayout    layout;
4367:   const PetscInt *ranges;
4368:   PetscInt       *local;
4369:   PetscSFNode    *remote;
4370:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4371:   PetscMPIInt    size, rank;

4376:   PetscObjectGetComm((PetscObject)dm,&comm);
4377:   MPI_Comm_size(comm, &size);
4378:   MPI_Comm_rank(comm, &rank);
4379:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4380:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4381:   PetscLayoutCreate(comm, &layout);
4382:   PetscLayoutSetBlockSize(layout, 1);
4383:   PetscLayoutSetLocalSize(layout, nroots);
4384:   PetscLayoutSetUp(layout);
4385:   PetscLayoutGetRanges(layout, &ranges);
4386:   for (p = pStart; p < pEnd; ++p) {
4387:     PetscInt gdof, gcdof;

4389:     PetscSectionGetDof(globalSection, p, &gdof);
4390:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4391:     if (gcdof > (gdof < 0 ? -(gdof+1) : gdof)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d has %d constraints > %d dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
4392:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4393:   }
4394:   PetscMalloc1(nleaves, &local);
4395:   PetscMalloc1(nleaves, &remote);
4396:   for (p = pStart, l = 0; p < pEnd; ++p) {
4397:     const PetscInt *cind;
4398:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4400:     PetscSectionGetDof(localSection, p, &dof);
4401:     PetscSectionGetOffset(localSection, p, &off);
4402:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4403:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4404:     PetscSectionGetDof(globalSection, p, &gdof);
4405:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4406:     PetscSectionGetOffset(globalSection, p, &goff);
4407:     if (!gdof) continue; /* Censored point */
4408:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4409:     if (gsize != dof-cdof) {
4410:       if (gsize != dof) SETERRQ4(comm, PETSC_ERR_ARG_WRONG, "Global dof %d for point %d is neither the constrained size %d, nor the unconstrained %d", gsize, p, dof-cdof, dof);
4411:       cdof = 0; /* Ignore constraints */
4412:     }
4413:     for (d = 0, c = 0; d < dof; ++d) {
4414:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4415:       local[l+d-c] = off+d;
4416:     }
4417:     if (gdof < 0) {
4418:       for (d = 0; d < gsize; ++d, ++l) {
4419:         PetscInt offset = -(goff+1) + d, r;

4421:         PetscFindInt(offset,size+1,ranges,&r);
4422:         if (r < 0) r = -(r+2);
4423:         if ((r < 0) || (r >= size)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d mapped to invalid process %d (%d, %d)", p, r, gdof, goff);
4424:         remote[l].rank  = r;
4425:         remote[l].index = offset - ranges[r];
4426:       }
4427:     } else {
4428:       for (d = 0; d < gsize; ++d, ++l) {
4429:         remote[l].rank  = rank;
4430:         remote[l].index = goff+d - ranges[rank];
4431:       }
4432:     }
4433:   }
4434:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4435:   PetscLayoutDestroy(&layout);
4436:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4437:   return(0);
4438: }

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

4443:   Input Parameter:
4444: . dm - The DM

4446:   Output Parameter:
4447: . sf - The PetscSF

4449:   Level: intermediate

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

4453: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4454: @*/
4455: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4456: {
4460:   *sf = dm->sf;
4461:   return(0);
4462: }

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

4467:   Input Parameters:
4468: + dm - The DM
4469: - sf - The PetscSF

4471:   Level: intermediate

4473: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4474: @*/
4475: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4476: {

4482:   PetscObjectReference((PetscObject) sf);
4483:   PetscSFDestroy(&dm->sf);
4484:   dm->sf = sf;
4485:   return(0);
4486: }

4488: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4489: {
4490:   PetscClassId   id;

4494:   PetscObjectGetClassId(disc, &id);
4495:   if (id == PETSCFE_CLASSID) {
4496:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4497:   } else if (id == PETSCFV_CLASSID) {
4498:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4499:   } else {
4500:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4501:   }
4502:   return(0);
4503: }

4505: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4506: {
4507:   RegionField   *tmpr;
4508:   PetscInt       Nf = dm->Nf, f;

4512:   if (Nf >= NfNew) return(0);
4513:   PetscMalloc1(NfNew, &tmpr);
4514:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4515:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4516:   PetscFree(dm->fields);
4517:   dm->Nf     = NfNew;
4518:   dm->fields = tmpr;
4519:   return(0);
4520: }

4522: /*@
4523:   DMClearFields - Remove all fields from the DM

4525:   Logically collective on dm

4527:   Input Parameter:
4528: . dm - The DM

4530:   Level: intermediate

4532: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4533: @*/
4534: PetscErrorCode DMClearFields(DM dm)
4535: {
4536:   PetscInt       f;

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

4551: /*@
4552:   DMGetNumFields - Get the number of fields in the DM

4554:   Not collective

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

4559:   Output Parameter:
4560: . Nf - The number of fields

4562:   Level: intermediate

4564: .seealso: DMSetNumFields(), DMSetField()
4565: @*/
4566: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4567: {
4571:   *numFields = dm->Nf;
4572:   return(0);
4573: }

4575: /*@
4576:   DMSetNumFields - Set the number of fields in the DM

4578:   Logically collective on dm

4580:   Input Parameters:
4581: + dm - The DM
4582: - Nf - The number of fields

4584:   Level: intermediate

4586: .seealso: DMGetNumFields(), DMSetField()
4587: @*/
4588: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4589: {
4590:   PetscInt       Nf, f;

4595:   DMGetNumFields(dm, &Nf);
4596:   for (f = Nf; f < numFields; ++f) {
4597:     PetscContainer obj;

4599:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4600:     DMAddField(dm, NULL, (PetscObject) obj);
4601:     PetscContainerDestroy(&obj);
4602:   }
4603:   return(0);
4604: }

4606: /*@
4607:   DMGetField - Return the discretization object for a given DM field

4609:   Not collective

4611:   Input Parameters:
4612: + dm - The DM
4613: - f  - The field number

4615:   Output Parameters:
4616: + label - The label indicating the support of the field, or NULL for the entire mesh
4617: - field - The discretization object

4619:   Level: intermediate

4621: .seealso: DMAddField(), DMSetField()
4622: @*/
4623: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4624: {
4628:   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);
4629:   if (label) *label = dm->fields[f].label;
4630:   if (field) *field = dm->fields[f].disc;
4631:   return(0);
4632: }

4634: /*@
4635:   DMSetField - Set the discretization object for a given DM field

4637:   Logically collective on dm

4639:   Input Parameters:
4640: + dm    - The DM
4641: . f     - The field number
4642: . label - The label indicating the support of the field, or NULL for the entire mesh
4643: - field - The discretization object

4645:   Level: intermediate

4647: .seealso: DMAddField(), DMGetField()
4648: @*/
4649: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4650: {

4657:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4658:   DMFieldEnlarge_Static(dm, f+1);
4659:   DMLabelDestroy(&dm->fields[f].label);
4660:   PetscObjectDestroy(&dm->fields[f].disc);
4661:   dm->fields[f].label = label;
4662:   dm->fields[f].disc  = field;
4663:   PetscObjectReference((PetscObject) label);
4664:   PetscObjectReference((PetscObject) field);
4665:   DMSetDefaultAdjacency_Private(dm, f, field);
4666:   DMClearDS(dm);
4667:   return(0);
4668: }

4670: /*@
4671:   DMAddField - Add the discretization object for the given DM field

4673:   Logically collective on dm

4675:   Input Parameters:
4676: + dm    - The DM
4677: . label - The label indicating the support of the field, or NULL for the entire mesh
4678: - field - The discretization object

4680:   Level: intermediate

4682: .seealso: DMSetField(), DMGetField()
4683: @*/
4684: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4685: {
4686:   PetscInt       Nf = dm->Nf;

4693:   DMFieldEnlarge_Static(dm, Nf+1);
4694:   dm->fields[Nf].label = label;
4695:   dm->fields[Nf].disc  = field;
4696:   PetscObjectReference((PetscObject) label);
4697:   PetscObjectReference((PetscObject) field);
4698:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4699:   DMClearDS(dm);
4700:   return(0);
4701: }

4703: /*@
4704:   DMCopyFields - Copy the discretizations for the DM into another DM

4706:   Collective on dm

4708:   Input Parameter:
4709: . dm - The DM

4711:   Output Parameter:
4712: . newdm - The DM

4714:   Level: advanced

4716: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4717: @*/
4718: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4719: {
4720:   PetscInt       Nf, f;

4724:   if (dm == newdm) return(0);
4725:   DMGetNumFields(dm, &Nf);
4726:   DMClearFields(newdm);
4727:   for (f = 0; f < Nf; ++f) {
4728:     DMLabel     label;
4729:     PetscObject field;
4730:     PetscBool   useCone, useClosure;

4732:     DMGetField(dm, f, &label, &field);
4733:     DMSetField(newdm, f, label, field);
4734:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4735:     DMSetAdjacency(newdm, f, useCone, useClosure);
4736:   }
4737:   return(0);
4738: }

4740: /*@
4741:   DMGetAdjacency - Returns the flags for determining variable influence

4743:   Not collective

4745:   Input Parameters:
4746: + dm - The DM object
4747: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4749:   Output Parameter:
4750: + useCone    - Flag for variable influence starting with the cone operation
4751: - useClosure - Flag for variable influence using transitive closure

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

4759:   Level: developer

4761: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4762: @*/
4763: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4764: {
4769:   if (f < 0) {
4770:     if (useCone)    *useCone    = dm->adjacency[0];
4771:     if (useClosure) *useClosure = dm->adjacency[1];
4772:   } else {
4773:     PetscInt       Nf;

4776:     DMGetNumFields(dm, &Nf);
4777:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4778:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4779:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4780:   }
4781:   return(0);
4782: }

4784: /*@
4785:   DMSetAdjacency - Set the flags for determining variable influence

4787:   Not collective

4789:   Input Parameters:
4790: + dm         - The DM object
4791: . f          - The field number
4792: . useCone    - Flag for variable influence starting with the cone operation
4793: - useClosure - Flag for variable influence using transitive closure

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

4801:   Level: developer

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

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

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

4827:   Not collective

4829:   Input Parameters:
4830: . dm - The DM object

4832:   Output Parameter:
4833: + useCone    - Flag for variable influence starting with the cone operation
4834: - useClosure - Flag for variable influence using transitive closure

4836:   Notes:
4837: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4838: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4839: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4841:   Level: developer

4843: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4844: @*/
4845: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4846: {
4847:   PetscInt       Nf;

4854:   DMGetNumFields(dm, &Nf);
4855:   if (!Nf) {
4856:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4857:   } else {
4858:     DMGetAdjacency(dm, 0, useCone, useClosure);
4859:   }
4860:   return(0);
4861: }

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

4866:   Not collective

4868:   Input Parameters:
4869: + dm         - The DM object
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

4878:   Level: developer

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

4889:   DMGetNumFields(dm, &Nf);
4890:   if (!Nf) {
4891:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4892:   } else {
4893:     DMSetAdjacency(dm, 0, useCone, useClosure);
4894:   }
4895:   return(0);
4896: }

4898: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
4899: {
4900:   DMSpace       *tmpd;
4901:   PetscInt       Nds = dm->Nds, s;

4905:   if (Nds >= NdsNew) return(0);
4906:   PetscMalloc1(NdsNew, &tmpd);
4907:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
4908:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
4909:   PetscFree(dm->probs);
4910:   dm->Nds   = NdsNew;
4911:   dm->probs = tmpd;
4912:   return(0);
4913: }

4915: /*@
4916:   DMGetNumDS - Get the number of discrete systems in the DM

4918:   Not collective

4920:   Input Parameter:
4921: . dm - The DM

4923:   Output Parameter:
4924: . Nds - The number of PetscDS objects

4926:   Level: intermediate

4928: .seealso: DMGetDS(), DMGetCellDS()
4929: @*/
4930: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4931: {
4935:   *Nds = dm->Nds;
4936:   return(0);
4937: }

4939: /*@
4940:   DMClearDS - Remove all discrete systems from the DM

4942:   Logically collective on dm

4944:   Input Parameter:
4945: . dm - The DM

4947:   Level: intermediate

4949: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
4950: @*/
4951: PetscErrorCode DMClearDS(DM dm)
4952: {
4953:   PetscInt       s;

4958:   for (s = 0; s < dm->Nds; ++s) {
4959:     PetscDSDestroy(&dm->probs[s].ds);
4960:     DMLabelDestroy(&dm->probs[s].label);
4961:     ISDestroy(&dm->probs[s].fields);
4962:   }
4963:   PetscFree(dm->probs);
4964:   dm->probs = NULL;
4965:   dm->Nds   = 0;
4966:   return(0);
4967: }

4969: /*@
4970:   DMGetDS - Get the default PetscDS

4972:   Not collective

4974:   Input Parameter:
4975: . dm    - The DM

4977:   Output Parameter:
4978: . prob - The default PetscDS

4980:   Level: intermediate

4982: .seealso: DMGetCellDS(), DMGetRegionDS()
4983: @*/
4984: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4985: {

4991:   if (dm->Nds <= 0) {
4992:     PetscDS ds;

4994:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
4995:     DMSetRegionDS(dm, NULL, NULL, ds);
4996:     PetscDSDestroy(&ds);
4997:   }
4998:   *prob = dm->probs[0].ds;
4999:   return(0);
5000: }

5002: /*@
5003:   DMGetCellDS - Get the PetscDS defined on a given cell

5005:   Not collective

5007:   Input Parameters:
5008: + dm    - The DM
5009: - point - Cell for the DS

5011:   Output Parameter:
5012: . prob - The PetscDS defined on the given cell

5014:   Level: developer

5016: .seealso: DMGetDS(), DMSetRegionDS()
5017: @*/
5018: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5019: {
5020:   PetscDS        probDef = NULL;
5021:   PetscInt       s;

5027:   *prob = NULL;
5028:   for (s = 0; s < dm->Nds; ++s) {
5029:     PetscInt val;

5031:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5032:     else {
5033:       DMLabelGetValue(dm->probs[s].label, point, &val);
5034:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5035:     }
5036:   }
5037:   if (!*prob) *prob = probDef;
5038:   return(0);
5039: }

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

5044:   Not collective

5046:   Input Parameters:
5047: + dm    - The DM
5048: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5056:   Level: advanced

5058: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5059: @*/
5060: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5061: {
5062:   PetscInt Nds = dm->Nds, s;

5069:   for (s = 0; s < Nds; ++s) {
5070:     if (dm->probs[s].label == label) {
5071:       if (fields) *fields = dm->probs[s].fields;
5072:       if (ds)     *ds     = dm->probs[s].ds;
5073:       return(0);
5074:     }
5075:   }
5076:   return(0);
5077: }

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

5082:   Not collective

5084:   Input Parameters:
5085: + dm  - The DM
5086: - num - The region number, in [0, Nds)

5088:   Output Parameters:
5089: + label  - The region label, or NULL
5090: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5091: - prob   - The PetscDS defined on the given region, or NULL

5093:   Level: advanced

5095: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5096: @*/
5097: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5098: {
5099:   PetscInt       Nds;

5104:   DMGetNumDS(dm, &Nds);
5105:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5106:   if (label) {
5108:     *label = dm->probs[num].label;
5109:   }
5110:   if (fields) {
5112:     *fields = dm->probs[num].fields;
5113:   }
5114:   if (ds) {
5116:     *ds = dm->probs[num].ds;
5117:   }
5118:   return(0);
5119: }

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

5124:   Collective on dm

5126:   Input Parameters:
5127: + dm     - The DM
5128: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5129: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5130: - prob   - The PetscDS defined on the given cell

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

5135:   Level: advanced

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

5148:   for (s = 0; s < Nds; ++s) {
5149:     if (dm->probs[s].label == label) {
5150:       PetscDSDestroy(&dm->probs[s].ds);
5151:       dm->probs[s].ds = ds;
5152:       return(0);
5153:     }
5154:   }
5155:   DMDSEnlarge_Static(dm, Nds+1);
5156:   PetscObjectReference((PetscObject) label);
5157:   PetscObjectReference((PetscObject) fields);
5158:   PetscObjectReference((PetscObject) ds);
5159:   if (!label) {
5160:     /* Put the NULL label at the front, so it is returned as the default */
5161:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5162:     Nds = 0;
5163:   }
5164:   dm->probs[Nds].label  = label;
5165:   dm->probs[Nds].fields = fields;
5166:   dm->probs[Nds].ds     = ds;
5167:   return(0);
5168: }

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

5173:   Collective on dm

5175:   Input Parameter:
5176: . dm - The DM

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

5180:   Level: intermediate

5182: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5183: @*/
5184: PetscErrorCode DMCreateDS(DM dm)
5185: {
5186:   MPI_Comm       comm;
5187:   PetscDS        prob, probh = NULL;
5188:   PetscInt       dimEmbed, Nf = dm->Nf, f, s, field = 0, fieldh = 0;
5189:   PetscBool      doSetup = PETSC_TRUE;

5194:   if (!dm->fields) return(0);
5195:   /* Can only handle two label cases right now:
5196:    1) NULL
5197:    2) Hybrid cells
5198:   */
5199:   PetscObjectGetComm((PetscObject) dm, &comm);
5200:   DMGetCoordinateDim(dm, &dimEmbed);
5201:   /* Create default DS */
5202:   DMGetRegionDS(dm, NULL, NULL, &prob);
5203:   if (!prob) {
5204:     IS        fields;
5205:     PetscInt *fld, nf;

5207:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5208:     PetscMalloc1(nf, &fld);
5209:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5210:     ISCreate(PETSC_COMM_SELF, &fields);
5211:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5212:     ISSetType(fields, ISGENERAL);
5213:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5215:     PetscDSCreate(comm, &prob);
5216:     DMSetRegionDS(dm, NULL, fields, prob);
5217:     PetscDSDestroy(&prob);
5218:     ISDestroy(&fields);
5219:     DMGetRegionDS(dm, NULL, NULL, &prob);
5220:   }
5221:   PetscDSSetCoordinateDimension(prob, dimEmbed);
5222:   /* Optionally create hybrid DS */
5223:   for (f = 0; f < Nf; ++f) {
5224:     DMLabel  label = dm->fields[f].label;
5225:     PetscInt lStart, lEnd;

5227:     if (label) {
5228:       DM        plex;
5229:       IS        fields;
5230:       PetscInt *fld;
5231:       PetscInt  depth, pMax[4];

5233:       DMConvert(dm, DMPLEX, &plex);
5234:       DMPlexGetDepth(plex, &depth);
5235:       DMPlexGetHybridBounds(plex, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);
5236:       DMDestroy(&plex);

5238:       DMLabelGetBounds(label, &lStart, &lEnd);
5239:       if (lStart < pMax[depth]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only support labels over hybrid cells right now");
5240:       PetscDSCreate(comm, &probh);
5241:       PetscMalloc1(1, &fld);
5242:       fld[0] = f;
5243:       ISCreate(PETSC_COMM_SELF, &fields);
5244:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5245:       ISSetType(fields, ISGENERAL);
5246:       ISGeneralSetIndices(fields, 1, fld, PETSC_OWN_POINTER);
5247:       DMSetRegionDS(dm, label, fields, probh);
5248:       ISDestroy(&fields);
5249:       PetscDSSetHybrid(probh, PETSC_TRUE);
5250:       PetscDSSetCoordinateDimension(probh, dimEmbed);
5251:       break;
5252:     }
5253:   }
5254:   /* Set fields in DSes */
5255:   for (f = 0; f < Nf; ++f) {
5256:     DMLabel     label = dm->fields[f].label;
5257:     PetscObject disc  = dm->fields[f].disc;

5259:     if (!label) {
5260:       PetscDSSetDiscretization(prob,  field++,  disc);
5261:       if (probh) {
5262:         PetscFE subfe;

5264:         PetscFEGetHeightSubspace((PetscFE) disc, 1, &subfe);
5265:         PetscDSSetDiscretization(probh, fieldh++, (PetscObject) subfe);
5266:       }
5267:     } else {
5268:       PetscDSSetDiscretization(probh, fieldh++, disc);
5269:     }
5270:     /* We allow people to have placeholder fields and construct the Section by hand */
5271:     {
5272:       PetscClassId id;

5274:       PetscObjectGetClassId(disc, &id);
5275:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5276:     }
5277:   }
5278:   PetscDSDestroy(&probh);
5279:   /* Setup DSes */
5280:   if (doSetup) {
5281:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5282:   }
5283:   return(0);
5284: }

5286: /*@
5287:   DMCopyDS - Copy the discrete systems for the DM into another DM

5289:   Collective on dm

5291:   Input Parameter:
5292: . dm - The DM

5294:   Output Parameter:
5295: . newdm - The DM

5297:   Level: advanced

5299: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5300: @*/
5301: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5302: {
5303:   PetscInt       Nds, s;

5307:   if (dm == newdm) return(0);
5308:   DMGetNumDS(dm, &Nds);
5309:   DMClearDS(newdm);
5310:   for (s = 0; s < Nds; ++s) {
5311:     DMLabel label;
5312:     IS      fields;
5313:     PetscDS ds;

5315:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5316:     DMSetRegionDS(newdm, label, fields, ds);
5317:   }
5318:   return(0);
5319: }

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

5324:   Collective on dm

5326:   Input Parameter:
5327: . dm - The DM

5329:   Output Parameter:
5330: . newdm - The DM

5332:   Level: advanced

5334: .seealso: DMCopyFields(), DMCopyDS()
5335: @*/
5336: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5337: {

5341:   if (dm == newdm) return(0);
5342:   DMCopyFields(dm, newdm);
5343:   DMCopyDS(dm, newdm);
5344:   return(0);
5345: }

5347: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5348: {
5349:   DM dm_coord,dmc_coord;
5351:   Vec coords,ccoords;
5352:   Mat inject;
5354:   DMGetCoordinateDM(dm,&dm_coord);
5355:   DMGetCoordinateDM(dmc,&dmc_coord);
5356:   DMGetCoordinates(dm,&coords);
5357:   DMGetCoordinates(dmc,&ccoords);
5358:   if (coords && !ccoords) {
5359:     DMCreateGlobalVector(dmc_coord,&ccoords);
5360:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5361:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5362:     MatRestrict(inject,coords,ccoords);
5363:     MatDestroy(&inject);
5364:     DMSetCoordinates(dmc,ccoords);
5365:     VecDestroy(&ccoords);
5366:   }
5367:   return(0);
5368: }

5370: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5371: {
5372:   DM dm_coord,subdm_coord;
5374:   Vec coords,ccoords,clcoords;
5375:   VecScatter *scat_i,*scat_g;
5377:   DMGetCoordinateDM(dm,&dm_coord);
5378:   DMGetCoordinateDM(subdm,&subdm_coord);
5379:   DMGetCoordinates(dm,&coords);
5380:   DMGetCoordinates(subdm,&ccoords);
5381:   if (coords && !ccoords) {
5382:     DMCreateGlobalVector(subdm_coord,&ccoords);
5383:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5384:     DMCreateLocalVector(subdm_coord,&clcoords);
5385:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5386:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5387:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5388:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5389:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5390:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5391:     DMSetCoordinates(subdm,ccoords);
5392:     DMSetCoordinatesLocal(subdm,clcoords);
5393:     VecScatterDestroy(&scat_i[0]);
5394:     VecScatterDestroy(&scat_g[0]);
5395:     VecDestroy(&ccoords);
5396:     VecDestroy(&clcoords);
5397:     PetscFree(scat_i);
5398:     PetscFree(scat_g);
5399:   }
5400:   return(0);
5401: }

5403: /*@
5404:   DMGetDimension - Return the topological dimension of the DM

5406:   Not collective

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

5411:   Output Parameter:
5412: . dim - The topological dimension

5414:   Level: beginner

5416: .seealso: DMSetDimension(), DMCreate()
5417: @*/
5418: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5419: {
5423:   *dim = dm->dim;
5424:   return(0);
5425: }

5427: /*@
5428:   DMSetDimension - Set the topological dimension of the DM

5430:   Collective on dm

5432:   Input Parameters:
5433: + dm - The DM
5434: - dim - The topological dimension

5436:   Level: beginner

5438: .seealso: DMGetDimension(), DMCreate()
5439: @*/
5440: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5441: {
5442:   PetscDS        ds;

5448:   dm->dim = dim;
5449:   DMGetDS(dm, &ds);
5450:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5451:   return(0);
5452: }

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

5457:   Collective on dm

5459:   Input Parameters:
5460: + dm - the DM
5461: - dim - the dimension

5463:   Output Parameters:
5464: + pStart - The first point of the given dimension
5465: - pEnd - The first point following points of the given dimension

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

5472:   Level: intermediate

5474: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5475: @*/
5476: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5477: {
5478:   PetscInt       d;

5483:   DMGetDimension(dm, &d);
5484:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5485:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5486:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5487:   return(0);
5488: }

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

5493:   Collective on dm

5495:   Input Parameters:
5496: + dm - the DM
5497: - c - coordinate vector

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

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

5504:   Level: intermediate

5506: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5507: @*/
5508: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5509: {

5515:   PetscObjectReference((PetscObject) c);
5516:   VecDestroy(&dm->coordinates);
5517:   dm->coordinates = c;
5518:   VecDestroy(&dm->coordinatesLocal);
5519:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5520:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5521:   return(0);
5522: }

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

5527:   Not collective

5529:    Input Parameters:
5530: +  dm - the DM
5531: -  c - coordinate vector

5533:   Notes:
5534:   The coordinates of ghost points can be set using DMSetCoordinates()
5535:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5536:   setting of ghost coordinates outside of the domain.

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

5540:   Level: intermediate

5542: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5543: @*/
5544: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5545: {

5551:   PetscObjectReference((PetscObject) c);
5552:   VecDestroy(&dm->coordinatesLocal);

5554:   dm->coordinatesLocal = c;

5556:   VecDestroy(&dm->coordinates);
5557:   return(0);
5558: }

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

5563:   Collective on dm

5565:   Input Parameter:
5566: . dm - the DM

5568:   Output Parameter:
5569: . c - global coordinate vector

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

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

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

5579:   Level: intermediate

5581: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5582: @*/
5583: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5584: {

5590:   if (!dm->coordinates && dm->coordinatesLocal) {
5591:     DM        cdm = NULL;
5592:     PetscBool localized;

5594:     DMGetCoordinateDM(dm, &cdm);
5595:     DMCreateGlobalVector(cdm, &dm->coordinates);
5596:     DMGetCoordinatesLocalized(dm, &localized);
5597:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5598:     if (localized) {
5599:       PetscInt cdim;

5601:       DMGetCoordinateDim(dm, &cdim);
5602:       VecSetBlockSize(dm->coordinates, cdim);
5603:     }
5604:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
5605:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5606:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5607:   }
5608:   *c = dm->coordinates;
5609:   return(0);
5610: }

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

5615:   Collective on dm

5617:   Input Parameter:
5618: . dm - the DM

5620:   Level: advanced

5622: .seealso: DMGetCoordinatesLocalNoncollective()
5623: @*/
5624: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5625: {

5630:   if (!dm->coordinatesLocal && dm->coordinates) {
5631:     DM        cdm = NULL;
5632:     PetscBool localized;

5634:     DMGetCoordinateDM(dm, &cdm);
5635:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
5636:     DMGetCoordinatesLocalized(dm, &localized);
5637:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5638:     if (localized) {
5639:       PetscInt cdim;

5641:       DMGetCoordinateDim(dm, &cdim);
5642:       VecSetBlockSize(dm->coordinates, cdim);
5643:     }
5644:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
5645:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5646:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5647:   }
5648:   return(0);
5649: }

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

5654:   Collective on dm

5656:   Input Parameter:
5657: . dm - the DM

5659:   Output Parameter:
5660: . c - coordinate vector

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

5665:   Each process has the local and ghost coordinates

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

5670:   Level: intermediate

5672: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5673: @*/
5674: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5675: {

5681:   DMGetCoordinatesLocalSetUp(dm);
5682:   *c = dm->coordinatesLocal;
5683:   return(0);
5684: }

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

5689:   Not collective

5691:   Input Parameter:
5692: . dm - the DM

5694:   Output Parameter:
5695: . c - coordinate vector

5697:   Level: advanced

5699: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5700: @*/
5701: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5702: {
5706:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5707:   *c = dm->coordinatesLocal;
5708:   return(0);
5709: }

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

5714:   Not collective

5716:   Input Parameter:
5717: + dm - the DM
5718: - p - the IS of points whose coordinates will be returned

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

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

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

5729:   Each process has the local and ghost coordinates

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

5734:   Level: advanced

5736: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5737: @*/
5738: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5739: {
5740:   PetscSection        cs, newcs;
5741:   Vec                 coords;
5742:   const PetscScalar   *arr;
5743:   PetscScalar         *newarr=NULL;
5744:   PetscInt            n;
5745:   PetscErrorCode      ierr;

5752:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5753:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5754:   cs = dm->coordinateDM->localSection;
5755:   coords = dm->coordinatesLocal;
5756:   VecGetArrayRead(coords, &arr);
5757:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
5758:   VecRestoreArrayRead(coords, &arr);
5759:   if (pCoord) {
5760:     PetscSectionGetStorageSize(newcs, &n);
5761:     /* set array in two steps to mimic PETSC_OWN_POINTER */
5762:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
5763:     VecReplaceArray(*pCoord, newarr);
5764:   } else {
5765:     PetscFree(newarr);
5766:   }
5767:   if (pCoordSection) {*pCoordSection = newcs;}
5768:   else               {PetscSectionDestroy(&newcs);}
5769:   return(0);
5770: }

5772: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5773: {

5779:   if (!dm->coordinateField) {
5780:     if (dm->ops->createcoordinatefield) {
5781:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
5782:     }
5783:   }
5784:   *field = dm->coordinateField;
5785:   return(0);
5786: }

5788: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5789: {

5795:   PetscObjectReference((PetscObject)field);
5796:   DMFieldDestroy(&dm->coordinateField);
5797:   dm->coordinateField = field;
5798:   return(0);
5799: }

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

5804:   Collective on dm

5806:   Input Parameter:
5807: . dm - the DM

5809:   Output Parameter:
5810: . cdm - coordinate DM

5812:   Level: intermediate

5814: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5815: @*/
5816: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5817: {

5823:   if (!dm->coordinateDM) {
5824:     DM cdm;

5826:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5827:     (*dm->ops->createcoordinatedm)(dm, &cdm);
5828:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5829:      * until the call to CreateCoordinateDM) */
5830:     DMDestroy(&dm->coordinateDM);
5831:     dm->coordinateDM = cdm;
5832:   }
5833:   *cdm = dm->coordinateDM;
5834:   return(0);
5835: }

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

5840:   Logically Collective on dm

5842:   Input Parameters:
5843: + dm - the DM
5844: - cdm - coordinate DM

5846:   Level: intermediate

5848: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5849: @*/
5850: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5851: {

5857:   PetscObjectReference((PetscObject)cdm);
5858:   DMDestroy(&dm->coordinateDM);
5859:   dm->coordinateDM = cdm;
5860:   return(0);
5861: }

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

5866:   Not Collective

5868:   Input Parameter:
5869: . dm - The DM object

5871:   Output Parameter:
5872: . dim - The embedding dimension

5874:   Level: intermediate

5876: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5877: @*/
5878: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5879: {
5883:   if (dm->dimEmbed == PETSC_DEFAULT) {
5884:     dm->dimEmbed = dm->dim;
5885:   }
5886:   *dim = dm->dimEmbed;
5887:   return(0);
5888: }

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

5893:   Not Collective

5895:   Input Parameters:
5896: + dm  - The DM object
5897: - dim - The embedding dimension

5899:   Level: intermediate

5901: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5902: @*/
5903: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5904: {
5905:   PetscDS        ds;

5910:   dm->dimEmbed = dim;
5911:   DMGetDS(dm, &ds);
5912:   PetscDSSetCoordinateDimension(ds, dim);
5913:   return(0);
5914: }

5916: /*@
5917:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

5919:   Collective on dm

5921:   Input Parameter:
5922: . dm - The DM object

5924:   Output Parameter:
5925: . section - The PetscSection object

5927:   Level: intermediate

5929: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5930: @*/
5931: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5932: {
5933:   DM             cdm;

5939:   DMGetCoordinateDM(dm, &cdm);
5940:   DMGetLocalSection(cdm, section);
5941:   return(0);
5942: }

5944: /*@
5945:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

5947:   Not Collective

5949:   Input Parameters:
5950: + dm      - The DM object
5951: . dim     - The embedding dimension, or PETSC_DETERMINE
5952: - section - The PetscSection object

5954:   Level: intermediate

5956: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5957: @*/
5958: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5959: {
5960:   DM             cdm;

5966:   DMGetCoordinateDM(dm, &cdm);
5967:   DMSetLocalSection(cdm, section);
5968:   if (dim == PETSC_DETERMINE) {
5969:     PetscInt d = PETSC_DEFAULT;
5970:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

5972:     PetscSectionGetChart(section, &pStart, &pEnd);
5973:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
5974:     pStart = PetscMax(vStart, pStart);
5975:     pEnd   = PetscMin(vEnd, pEnd);
5976:     for (v = pStart; v < pEnd; ++v) {
5977:       PetscSectionGetDof(section, v, &dd);
5978:       if (dd) {d = dd; break;}
5979:     }
5980:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
5981:   }
5982:   return(0);
5983: }

5985: /*@C
5986:   DMGetPeriodicity - Get the description of mesh periodicity

5988:   Input Parameters:
5989: . dm      - The DM object

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

5997:   Level: developer

5999: .seealso: DMGetPeriodicity()
6000: @*/
6001: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6002: {
6005:   if (per)     *per     = dm->periodic;
6006:   if (L)       *L       = dm->L;
6007:   if (maxCell) *maxCell = dm->maxCell;
6008:   if (bd)      *bd      = dm->bdtype;
6009:   return(0);
6010: }

6012: /*@C
6013:   DMSetPeriodicity - Set the description of mesh periodicity

6015:   Input Parameters:
6016: + dm      - The DM object
6017: . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6018: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6019: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6020: - bd      - This describes the type of periodicity in each topological dimension

6022:   Level: developer

6024: .seealso: DMGetPeriodicity()
6025: @*/
6026: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6027: {
6028:   PetscInt       dim, d;

6034:   if (maxCell) {
6038:   }
6039:   PetscFree3(dm->L,dm->maxCell,dm->bdtype);
6040:   DMGetDimension(dm, &dim);
6041:   if (maxCell) {
6042:     PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);
6043:     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
6044:   }
6045:   dm->periodic = per;
6046:   return(0);
6047: }

6049: /*@
6050:   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.

6052:   Input Parameters:
6053: + dm     - The DM
6054: . in     - The input coordinate point (dim numbers)
6055: - endpoint - Include the endpoint L_i

6057:   Output Parameter:
6058: . out - The localized coordinate point

6060:   Level: developer

6062: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6063: @*/
6064: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6065: {
6066:   PetscInt       dim, d;

6070:   DMGetCoordinateDim(dm, &dim);
6071:   if (!dm->maxCell) {
6072:     for (d = 0; d < dim; ++d) out[d] = in[d];
6073:   } else {
6074:     if (endpoint) {
6075:       for (d = 0; d < dim; ++d) {
6076:         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)) {
6077:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6078:         } else {
6079:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6080:         }
6081:       }
6082:     } else {
6083:       for (d = 0; d < dim; ++d) {
6084:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6085:       }
6086:     }
6087:   }
6088:   return(0);
6089: }

6091: /*
6092:   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.

6094:   Input Parameters:
6095: + dm     - The DM
6096: . dim    - The spatial dimension
6097: . anchor - The anchor point, the input point can be no more than maxCell away from it
6098: - in     - The input coordinate point (dim numbers)

6100:   Output Parameter:
6101: . out - The localized coordinate point

6103:   Level: developer

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

6107: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6108: */
6109: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6110: {
6111:   PetscInt d;

6114:   if (!dm->maxCell) {
6115:     for (d = 0; d < dim; ++d) out[d] = in[d];
6116:   } else {
6117:     for (d = 0; d < dim; ++d) {
6118:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6119:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6120:       } else {
6121:         out[d] = in[d];
6122:       }
6123:     }
6124:   }
6125:   return(0);
6126: }
6127: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6128: {
6129:   PetscInt d;

6132:   if (!dm->maxCell) {
6133:     for (d = 0; d < dim; ++d) out[d] = in[d];
6134:   } else {
6135:     for (d = 0; d < dim; ++d) {
6136:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6137:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6138:       } else {
6139:         out[d] = in[d];
6140:       }
6141:     }
6142:   }
6143:   return(0);
6144: }

6146: /*
6147:   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.

6149:   Input Parameters:
6150: + dm     - The DM
6151: . dim    - The spatial dimension
6152: . anchor - The anchor point, the input point can be no more than maxCell away from it
6153: . in     - The input coordinate delta (dim numbers)
6154: - out    - The input coordinate point (dim numbers)

6156:   Output Parameter:
6157: . out    - The localized coordinate in + out

6159:   Level: developer

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

6163: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6164: */
6165: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6166: {
6167:   PetscInt d;

6170:   if (!dm->maxCell) {
6171:     for (d = 0; d < dim; ++d) out[d] += in[d];
6172:   } else {
6173:     for (d = 0; d < dim; ++d) {
6174:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6175:         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6176:       } else {
6177:         out[d] += in[d];
6178:       }
6179:     }
6180:   }
6181:   return(0);
6182: }

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

6187:   Not collective

6189:   Input Parameter:
6190: . dm - The DM

6192:   Output Parameter:
6193:   areLocalized - True if localized

6195:   Level: developer

6197: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6198: @*/
6199: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6200: {
6201:   DM             cdm;
6202:   PetscSection   coordSection;
6203:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6204:   PetscBool      isPlex, alreadyLocalized;

6210:   *areLocalized = PETSC_FALSE;

6212:   /* We need some generic way of refering to cells/vertices */
6213:   DMGetCoordinateDM(dm, &cdm);
6214:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6215:   if (!isPlex) return(0);

6217:   DMGetCoordinateSection(dm, &coordSection);
6218:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6219:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6220:   alreadyLocalized = PETSC_FALSE;
6221:   for (c = cStart; c < cEnd; ++c) {
6222:     if (c < sStart || c >= sEnd) continue;
6223:     PetscSectionGetDof(coordSection, c, &dof);
6224:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6225:   }
6226:   *areLocalized = alreadyLocalized;
6227:   return(0);
6228: }

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

6233:   Collective on dm

6235:   Input Parameter:
6236: . dm - The DM

6238:   Output Parameter:
6239:   areLocalized - True if localized

6241:   Level: developer

6243: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6244: @*/
6245: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6246: {
6247:   PetscBool      localized;

6253:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6254:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6255:   return(0);
6256: }

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

6261:   Collective on dm

6263:   Input Parameter:
6264: . dm - The DM

6266:   Level: developer

6268: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6269: @*/
6270: PetscErrorCode DMLocalizeCoordinates(DM dm)
6271: {
6272:   DM             cdm;
6273:   PetscSection   coordSection, cSection;
6274:   Vec            coordinates,  cVec;
6275:   PetscScalar   *coords, *coords2, *anchor, *localized;
6276:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6277:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6278:   PetscInt       maxHeight = 0, h;
6279:   PetscInt       *pStart = NULL, *pEnd = NULL;

6284:   if (!dm->periodic) return(0);
6285:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6286:   if (alreadyLocalized) return(0);

6288:   /* We need some generic way of refering to cells/vertices */
6289:   DMGetCoordinateDM(dm, &cdm);
6290:   {
6291:     PetscBool isplex;

6293:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6294:     if (isplex) {
6295:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6296:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6297:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6298:       pEnd = &pStart[maxHeight + 1];
6299:       newStart = vStart;
6300:       newEnd   = vEnd;
6301:       for (h = 0; h <= maxHeight; h++) {
6302:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6303:         newStart = PetscMin(newStart,pStart[h]);
6304:         newEnd   = PetscMax(newEnd,pEnd[h]);
6305:       }
6306:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6307:   }
6308:   DMGetCoordinatesLocal(dm, &coordinates);
6309:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6310:   DMGetCoordinateSection(dm, &coordSection);
6311:   VecGetBlockSize(coordinates, &bs);
6312:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6314:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6315:   PetscSectionSetNumFields(cSection, 1);
6316:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6317:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6318:   PetscSectionSetChart(cSection, newStart, newEnd);

6320:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6321:   localized = &anchor[bs];
6322:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6323:   for (h = 0; h <= maxHeight; h++) {
6324:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6326:     for (c = cStart; c < cEnd; ++c) {
6327:       PetscScalar *cellCoords = NULL;
6328:       PetscInt     b;

6330:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6331:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6332:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6333:       for (d = 0; d < dof/bs; ++d) {
6334:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6335:         for (b = 0; b < bs; b++) {
6336:           if (cellCoords[d*bs + b] != localized[b]) break;
6337:         }
6338:         if (b < bs) break;
6339:       }
6340:       if (d < dof/bs) {
6341:         if (c >= sStart && c < sEnd) {
6342:           PetscInt cdof;

6344:           PetscSectionGetDof(coordSection, c, &cdof);
6345:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6346:         }
6347:         PetscSectionSetDof(cSection, c, dof);
6348:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6349:       }
6350:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6351:     }
6352:   }
6353:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6354:   if (alreadyLocalizedGlobal) {
6355:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6356:     PetscSectionDestroy(&cSection);
6357:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6358:     return(0);
6359:   }
6360:   for (v = vStart; v < vEnd; ++v) {
6361:     PetscSectionGetDof(coordSection, v, &dof);
6362:     PetscSectionSetDof(cSection, v, dof);
6363:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6364:   }
6365:   PetscSectionSetUp(cSection);
6366:   PetscSectionGetStorageSize(cSection, &coordSize);
6367:   VecCreate(PETSC_COMM_SELF, &cVec);
6368:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6369:   VecSetBlockSize(cVec, bs);
6370:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6371:   VecSetType(cVec, VECSTANDARD);
6372:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6373:   VecGetArray(cVec, &coords2);
6374:   for (v = vStart; v < vEnd; ++v) {
6375:     PetscSectionGetDof(coordSection, v, &dof);
6376:     PetscSectionGetOffset(coordSection, v, &off);
6377:     PetscSectionGetOffset(cSection,     v, &off2);
6378:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6379:   }
6380:   for (h = 0; h <= maxHeight; h++) {
6381:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6383:     for (c = cStart; c < cEnd; ++c) {
6384:       PetscScalar *cellCoords = NULL;
6385:       PetscInt     b, cdof;

6387:       PetscSectionGetDof(cSection,c,&cdof);
6388:       if (!cdof) continue;
6389:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6390:       PetscSectionGetOffset(cSection, c, &off2);
6391:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6392:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6393:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6394:     }
6395:   }
6396:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6397:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6398:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6399:   VecRestoreArray(cVec, &coords2);
6400:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6401:   DMSetCoordinatesLocal(dm, cVec);
6402:   VecDestroy(&cVec);
6403:   PetscSectionDestroy(&cSection);
6404:   return(0);
6405: }

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

6410:   Collective on v (see explanation below)

6412:   Input Parameters:
6413: + dm - The DM
6414: . v - The Vec of points
6415: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6416: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6418:   Output Parameter:
6419: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6420: - cells - The PetscSF containing the ranks and local indices of the containing points.


6423:   Level: developer

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

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

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

6434: $    const PetscSFNode *cells;
6435: $    PetscInt           nFound;
6436: $    const PetscInt    *found;
6437: $
6438: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

6443: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6444: @*/
6445: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6446: {

6453:   if (*cellSF) {
6454:     PetscMPIInt result;

6457:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6458:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6459:   } else {
6460:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6461:   }
6462:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6463:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6464:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6465:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6466:   return(0);
6467: }

6469: /*@
6470:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6472:   Collective on dm

6474:   Input Parameter:
6475: . dm - The original DM

6477:   Output Parameter:
6478: . odm - The DM which provides the layout for output

6480:   Level: intermediate

6482: .seealso: VecView(), DMGetGlobalSection()
6483: @*/
6484: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6485: {
6486:   PetscSection   section;
6487:   PetscBool      hasConstraints, ghasConstraints;

6493:   DMGetLocalSection(dm, &section);
6494:   PetscSectionHasConstraints(section, &hasConstraints);
6495:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6496:   if (!ghasConstraints) {
6497:     *odm = dm;
6498:     return(0);
6499:   }
6500:   if (!dm->dmBC) {
6501:     PetscSection newSection, gsection;
6502:     PetscSF      sf;

6504:     DMClone(dm, &dm->dmBC);
6505:     DMCopyDisc(dm, dm->dmBC);
6506:     PetscSectionClone(section, &newSection);
6507:     DMSetLocalSection(dm->dmBC, newSection);
6508:     PetscSectionDestroy(&newSection);
6509:     DMGetPointSF(dm->dmBC, &sf);
6510:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6511:     DMSetGlobalSection(dm->dmBC, gsection);
6512:     PetscSectionDestroy(&gsection);
6513:   }
6514:   *odm = dm->dmBC;
6515:   return(0);
6516: }

6518: /*@
6519:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6521:   Input Parameter:
6522: . dm - The original DM

6524:   Output Parameters:
6525: + num - The output sequence number
6526: - val - The output sequence value

6528:   Level: intermediate

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

6533: .seealso: VecView()
6534: @*/
6535: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6536: {
6541:   return(0);
6542: }

6544: /*@
6545:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6547:   Input Parameters:
6548: + dm - The original DM
6549: . num - The output sequence number
6550: - val - The output sequence value

6552:   Level: intermediate

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

6557: .seealso: VecView()
6558: @*/
6559: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6560: {
6563:   dm->outputSequenceNum = num;
6564:   dm->outputSequenceVal = val;
6565:   return(0);
6566: }

6568: /*@C
6569:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

6571:   Input Parameters:
6572: + dm   - The original DM
6573: . name - The sequence name
6574: - num  - The output sequence number

6576:   Output Parameter:
6577: . val  - The output sequence value

6579:   Level: intermediate

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

6584: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6585: @*/
6586: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6587: {
6588:   PetscBool      ishdf5;

6595:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
6596:   if (ishdf5) {
6597: #if defined(PETSC_HAVE_HDF5)
6598:     PetscScalar value;

6600:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6601:     *val = PetscRealPart(value);
6602: #endif
6603:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6604:   return(0);
6605: }

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

6610:   Not collective

6612:   Input Parameter:
6613: . dm - The DM

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

6618:   Level: beginner

6620: .seealso: DMSetUseNatural(), DMCreate()
6621: @*/
6622: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6623: {
6627:   *useNatural = dm->useNatural;
6628:   return(0);
6629: }

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

6634:   Collective on dm

6636:   Input Parameters:
6637: + dm - The DM
6638: - useNatural - The flag to build the mapping to a natural order during distribution

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

6642:   Level: beginner

6644: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6645: @*/
6646: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6647: {
6651:   dm->useNatural = useNatural;
6652:   return(0);
6653: }


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

6659:   Not Collective

6661:   Input Parameters:
6662: + dm   - The DM object
6663: - name - The label name

6665:   Level: intermediate

6667: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6668: @*/
6669: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6670: {
6671:   PetscBool      flg;
6672:   DMLabel        label;

6678:   DMHasLabel(dm, name, &flg);
6679:   if (!flg) {
6680:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6681:     DMAddLabel(dm, label);
6682:     DMLabelDestroy(&label);
6683:   }
6684:   return(0);
6685: }

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

6690:   Not Collective

6692:   Input Parameters:
6693: + dm   - The DM object
6694: . name - The label name
6695: - point - The mesh point

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

6700:   Level: beginner

6702: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6703: @*/
6704: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6705: {
6706:   DMLabel        label;

6712:   DMGetLabel(dm, name, &label);
6713:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6714:   DMLabelGetValue(label, point, value);
6715:   return(0);
6716: }

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

6721:   Not Collective

6723:   Input Parameters:
6724: + dm   - The DM object
6725: . name - The label name
6726: . point - The mesh point
6727: - value - The label value for this point

6729:   Output Parameter:

6731:   Level: beginner

6733: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6734: @*/
6735: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6736: {
6737:   DMLabel        label;

6743:   DMGetLabel(dm, name, &label);
6744:   if (!label) {
6745:     DMCreateLabel(dm, name);
6746:     DMGetLabel(dm, name, &label);
6747:   }
6748:   DMLabelSetValue(label, point, value);
6749:   return(0);
6750: }

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

6755:   Not Collective

6757:   Input Parameters:
6758: + dm   - The DM object
6759: . name - The label name
6760: . point - The mesh point
6761: - value - The label value for this point

6763:   Output Parameter:

6765:   Level: beginner

6767: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6768: @*/
6769: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6770: {
6771:   DMLabel        label;

6777:   DMGetLabel(dm, name, &label);
6778:   if (!label) return(0);
6779:   DMLabelClearValue(label, point, value);
6780:   return(0);
6781: }

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

6786:   Not Collective

6788:   Input Parameters:
6789: + dm   - The DM object
6790: - name - The label name

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

6795:   Level: beginner

6797: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6798: @*/
6799: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6800: {
6801:   DMLabel        label;

6808:   DMGetLabel(dm, name, &label);
6809:   *size = 0;
6810:   if (!label) return(0);
6811:   DMLabelGetNumValues(label, size);
6812:   return(0);
6813: }

6815: /*@C
6816:   DMGetLabelIdIS - Get the integer ids in a label

6818:   Not Collective

6820:   Input Parameters:
6821: + mesh - The DM object
6822: - name - The label name

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

6827:   Level: beginner

6829: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6830: @*/
6831: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6832: {
6833:   DMLabel        label;

6840:   DMGetLabel(dm, name, &label);
6841:   *ids = NULL;
6842:  if (label) {
6843:     DMLabelGetValueIS(label, ids);
6844:   } else {
6845:     /* returning an empty IS */
6846:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
6847:   }
6848:   return(0);
6849: }

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

6854:   Not Collective

6856:   Input Parameters:
6857: + dm - The DM object
6858: . name - The label name
6859: - value - The stratum value

6861:   Output Parameter:
6862: . size - The stratum size

6864:   Level: beginner

6866: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6867: @*/
6868: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6869: {
6870:   DMLabel        label;

6877:   DMGetLabel(dm, name, &label);
6878:   *size = 0;
6879:   if (!label) return(0);
6880:   DMLabelGetStratumSize(label, value, size);
6881:   return(0);
6882: }

6884: /*@C
6885:   DMGetStratumIS - Get the points in a label stratum

6887:   Not Collective

6889:   Input Parameters:
6890: + dm - The DM object
6891: . name - The label name
6892: - value - The stratum value

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

6897:   Level: beginner

6899: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6900: @*/
6901: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6902: {
6903:   DMLabel        label;

6910:   DMGetLabel(dm, name, &label);
6911:   *points = NULL;
6912:   if (!label) return(0);
6913:   DMLabelGetStratumIS(label, value, points);
6914:   return(0);
6915: }

6917: /*@C
6918:   DMSetStratumIS - Set the points in a label stratum

6920:   Not Collective

6922:   Input Parameters:
6923: + dm - The DM object
6924: . name - The label name
6925: . value - The stratum value
6926: - points - The stratum points

6928:   Level: beginner

6930: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6931: @*/
6932: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6933: {
6934:   DMLabel        label;

6941:   DMGetLabel(dm, name, &label);
6942:   if (!label) return(0);
6943:   DMLabelSetStratumIS(label, value, points);
6944:   return(0);
6945: }

6947: /*@C
6948:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

6950:   Not Collective

6952:   Input Parameters:
6953: + dm   - The DM object
6954: . name - The label name
6955: - value - The label value for this point

6957:   Output Parameter:

6959:   Level: beginner

6961: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6962: @*/
6963: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6964: {
6965:   DMLabel        label;

6971:   DMGetLabel(dm, name, &label);
6972:   if (!label) return(0);
6973:   DMLabelClearStratum(label, value);
6974:   return(0);
6975: }

6977: /*@
6978:   DMGetNumLabels - Return the number of labels defined by the mesh

6980:   Not Collective

6982:   Input Parameter:
6983: . dm   - The DM object

6985:   Output Parameter:
6986: . numLabels - the number of Labels

6988:   Level: intermediate

6990: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6991: @*/
6992: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6993: {
6994:   DMLabelLink next = dm->labels;
6995:   PetscInt  n    = 0;

7000:   while (next) {++n; next = next->next;}
7001:   *numLabels = n;
7002:   return(0);
7003: }

7005: /*@C
7006:   DMGetLabelName - Return the name of nth label

7008:   Not Collective

7010:   Input Parameters:
7011: + dm - The DM object
7012: - n  - the label number

7014:   Output Parameter:
7015: . name - the label name

7017:   Level: intermediate

7019: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7020: @*/
7021: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7022: {
7023:   DMLabelLink    next = dm->labels;
7024:   PetscInt       l    = 0;

7030:   while (next) {
7031:     if (l == n) {
7032:       PetscObjectGetName((PetscObject) next->label, name);
7033:       return(0);
7034:     }
7035:     ++l;
7036:     next = next->next;
7037:   }
7038:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7039: }

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

7044:   Not Collective

7046:   Input Parameters:
7047: + dm   - The DM object
7048: - name - The label name

7050:   Output Parameter:
7051: . hasLabel - PETSC_TRUE if the label is present

7053:   Level: intermediate

7055: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7056: @*/
7057: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7058: {
7059:   DMLabelLink    next = dm->labels;
7060:   const char    *lname;

7067:   *hasLabel = PETSC_FALSE;
7068:   while (next) {
7069:     PetscObjectGetName((PetscObject) next->label, &lname);
7070:     PetscStrcmp(name, lname, hasLabel);
7071:     if (*hasLabel) break;
7072:     next = next->next;
7073:   }
7074:   return(0);
7075: }

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

7080:   Not Collective

7082:   Input Parameters:
7083: + dm   - The DM object
7084: - name - The label name

7086:   Output Parameter:
7087: . label - The DMLabel, or NULL if the label is absent

7089:   Level: intermediate

7091: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7092: @*/
7093: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7094: {
7095:   DMLabelLink    next = dm->labels;
7096:   PetscBool      hasLabel;
7097:   const char    *lname;

7104:   *label = NULL;
7105:   while (next) {
7106:     PetscObjectGetName((PetscObject) next->label, &lname);
7107:     PetscStrcmp(name, lname, &hasLabel);
7108:     if (hasLabel) {
7109:       *label = next->label;
7110:       break;
7111:     }
7112:     next = next->next;
7113:   }
7114:   return(0);
7115: }

7117: /*@C
7118:   DMGetLabelByNum - Return the nth label

7120:   Not Collective

7122:   Input Parameters:
7123: + dm - The DM object
7124: - n  - the label number

7126:   Output Parameter:
7127: . label - the label

7129:   Level: intermediate

7131: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7132: @*/
7133: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7134: {
7135:   DMLabelLink next = dm->labels;
7136:   PetscInt    l    = 0;

7141:   while (next) {
7142:     if (l == n) {
7143:       *label = next->label;
7144:       return(0);
7145:     }
7146:     ++l;
7147:     next = next->next;
7148:   }
7149:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7150: }

7152: /*@C
7153:   DMAddLabel - Add the label to this mesh

7155:   Not Collective

7157:   Input Parameters:
7158: + dm   - The DM object
7159: - label - The DMLabel

7161:   Level: developer

7163: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7164: @*/
7165: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7166: {
7167:   DMLabelLink    l, *p, tmpLabel;
7168:   PetscBool      hasLabel;
7169:   const char    *lname;
7170:   PetscBool      flg;

7175:   PetscObjectGetName((PetscObject) label, &lname);
7176:   DMHasLabel(dm, lname, &hasLabel);
7177:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7178:   PetscCalloc1(1, &tmpLabel);
7179:   tmpLabel->label  = label;
7180:   tmpLabel->output = PETSC_TRUE;
7181:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7182:   *p = tmpLabel;
7183:   PetscObjectReference((PetscObject)label);
7184:   PetscStrcmp(lname, "depth", &flg);
7185:   if (flg) dm->depthLabel = label;
7186:   PetscStrcmp(lname, "celltype", &flg);
7187:   if (flg) dm->celltypeLabel = label;
7188:   return(0);
7189: }

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

7194:   Not Collective

7196:   Input Parameters:
7197: + dm   - The DM object
7198: - name - The label name

7200:   Output Parameter:
7201: . label - The DMLabel, or NULL if the label is absent

7203:   Level: developer

7205:   Notes:
7206:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7207:   DMLabelDestroy() on the label.

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

7213: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7214: @*/
7215: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7216: {
7217:   DMLabelLink    link, *pnext;
7218:   PetscBool      hasLabel;
7219:   const char    *lname;

7225:   if (label) {
7227:     *label = NULL;
7228:   }
7229:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7230:     PetscObjectGetName((PetscObject) link->label, &lname);
7231:     PetscStrcmp(name, lname, &hasLabel);
7232:     if (hasLabel) {
7233:       *pnext = link->next; /* Remove from list */
7234:       PetscStrcmp(name, "depth", &hasLabel);
7235:       if (hasLabel) dm->depthLabel = NULL;
7236:       PetscStrcmp(name, "celltype", &hasLabel);
7237:       if (hasLabel) dm->celltypeLabel = NULL;
7238:       if (label) *label = link->label;
7239:       else       {DMLabelDestroy(&link->label);}
7240:       PetscFree(link);
7241:       break;
7242:     }
7243:   }
7244:   return(0);
7245: }

7247: /*@
7248:   DMRemoveLabelBySelf - Remove the label from this mesh

7250:   Not Collective

7252:   Input Parameters:
7253: + dm   - The DM object
7254: . label - (Optional) The DMLabel to be removed from the DM
7255: - failNotFound - Should it fail if the label is not found in the DM?

7257:   Level: developer

7259:   Notes:
7260:   Only exactly the same instance is removed if found, name match is ignored.
7261:   If the DM has an exclusive reference to the label, it gets destroyed and
7262:   *label nullified.

7264: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7265: @*/
7266: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7267: {
7268:   DMLabelLink    link, *pnext;
7269:   PetscBool      hasLabel = PETSC_FALSE;

7275:   if (!*label && !failNotFound) return(0);
7278:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7279:     if (*label == link->label) {
7280:       hasLabel = PETSC_TRUE;
7281:       *pnext = link->next; /* Remove from list */
7282:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7283:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7284:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7285:       DMLabelDestroy(&link->label);
7286:       PetscFree(link);
7287:       break;
7288:     }
7289:   }
7290:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7291:   return(0);
7292: }

7294: /*@C
7295:   DMGetLabelOutput - Get the output flag for a given label

7297:   Not Collective

7299:   Input Parameters:
7300: + dm   - The DM object
7301: - name - The label name

7303:   Output Parameter:
7304: . output - The flag for output

7306:   Level: developer

7308: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7309: @*/
7310: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7311: {
7312:   DMLabelLink    next = dm->labels;
7313:   const char    *lname;

7320:   while (next) {
7321:     PetscBool flg;

7323:     PetscObjectGetName((PetscObject) next->label, &lname);
7324:     PetscStrcmp(name, lname, &flg);
7325:     if (flg) {*output = next->output; return(0);}
7326:     next = next->next;
7327:   }
7328:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7329: }

7331: /*@C
7332:   DMSetLabelOutput - Set the output flag for a given label

7334:   Not Collective

7336:   Input Parameters:
7337: + dm     - The DM object
7338: . name   - The label name
7339: - output - The flag for output

7341:   Level: developer

7343: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7344: @*/
7345: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7346: {
7347:   DMLabelLink    next = dm->labels;
7348:   const char    *lname;

7354:   while (next) {
7355:     PetscBool flg;

7357:     PetscObjectGetName((PetscObject) next->label, &lname);
7358:     PetscStrcmp(name, lname, &flg);
7359:     if (flg) {next->output = output; return(0);}
7360:     next = next->next;
7361:   }
7362:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7363: }

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

7368:   Collective on dmA

7370:   Input Parameter:
7371: + dmA - The DM object with initial labels
7372: . dmB - The DM object with copied labels
7373: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7374: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7376:   Level: intermediate

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

7380: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7381: @*/
7382: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7383: {
7384:   DMLabel        label, labelNew;
7385:   const char    *name;
7386:   PetscBool      flg;
7387:   DMLabelLink    link;

7395:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7396:   if (dmA == dmB) return(0);
7397:   for (link=dmA->labels; link; link=link->next) {
7398:     label=link->label;
7399:     PetscObjectGetName((PetscObject)label, &name);
7400:     if (!all) {
7401:       PetscStrcmp(name, "depth", &flg);
7402:       if (flg) continue;
7403:       PetscStrcmp(name, "dim", &flg);
7404:       if (flg) continue;
7405:       PetscStrcmp(name, "celltype", &flg);
7406:       if (flg) continue;
7407:     } else {
7408:       dmB->depthLabel    = dmA->depthLabel;
7409:       dmB->celltypeLabel = dmA->celltypeLabel;
7410:     }
7411:     if (mode==PETSC_COPY_VALUES) {
7412:       DMLabelDuplicate(label, &labelNew);
7413:     } else {
7414:       labelNew = label;
7415:     }
7416:     DMAddLabel(dmB, labelNew);
7417:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7418:   }
7419:   return(0);
7420: }

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

7425:   Input Parameter:
7426: . dm - The DM object

7428:   Output Parameter:
7429: . cdm - The coarse DM

7431:   Level: intermediate

7433: .seealso: DMSetCoarseDM()
7434: @*/
7435: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7436: {
7440:   *cdm = dm->coarseMesh;
7441:   return(0);
7442: }

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

7447:   Input Parameters:
7448: + dm - The DM object
7449: - cdm - The coarse DM

7451:   Level: intermediate

7453: .seealso: DMGetCoarseDM()
7454: @*/
7455: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7456: {

7462:   PetscObjectReference((PetscObject)cdm);
7463:   DMDestroy(&dm->coarseMesh);
7464:   dm->coarseMesh = cdm;
7465:   return(0);
7466: }

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

7471:   Input Parameter:
7472: . dm - The DM object

7474:   Output Parameter:
7475: . fdm - The fine DM

7477:   Level: intermediate

7479: .seealso: DMSetFineDM()
7480: @*/
7481: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7482: {
7486:   *fdm = dm->fineMesh;
7487:   return(0);
7488: }

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

7493:   Input Parameters:
7494: + dm - The DM object
7495: - fdm - The fine DM

7497:   Level: intermediate

7499: .seealso: DMGetFineDM()
7500: @*/
7501: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7502: {

7508:   PetscObjectReference((PetscObject)fdm);
7509:   DMDestroy(&dm->fineMesh);
7510:   dm->fineMesh = fdm;
7511:   return(0);
7512: }

7514: /*=== DMBoundary code ===*/

7516: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7517: {
7518:   PetscInt       d;

7522:   for (d = 0; d < dm->Nds; ++d) {
7523:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7524:   }
7525:   return(0);
7526: }

7528: /*@C
7529:   DMAddBoundary - Add a boundary condition to the model

7531:   Input Parameters:
7532: + dm          - The DM, with a PetscDS that matches the problem being constrained
7533: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7534: . name        - The BC name
7535: . labelname   - The label defining constrained points
7536: . field       - The field to constrain
7537: . numcomps    - The number of constrained field components (0 will constrain all fields)
7538: . comps       - An array of constrained component numbers
7539: . bcFunc      - A pointwise function giving boundary values
7540: . numids      - The number of DMLabel ids for constrained points
7541: . ids         - An array of ids for constrained points
7542: - ctx         - An optional user context for bcFunc

7544:   Options Database Keys:
7545: + -bc_<boundary name> <num> - Overrides the boundary ids
7546: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7548:   Level: developer

7550: .seealso: DMGetBoundary()
7551: @*/
7552: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
7553: {
7554:   PetscDS        ds;

7559:   DMGetDS(dm, &ds);
7560:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);
7561:   return(0);
7562: }

7564: /*@
7565:   DMGetNumBoundary - Get the number of registered BC

7567:   Input Parameters:
7568: . dm - The mesh object

7570:   Output Parameters:
7571: . numBd - The number of BC

7573:   Level: intermediate

7575: .seealso: DMAddBoundary(), DMGetBoundary()
7576: @*/
7577: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7578: {
7579:   PetscDS        ds;

7584:   DMGetDS(dm, &ds);
7585:   PetscDSGetNumBoundary(ds, numBd);
7586:   return(0);
7587: }

7589: /*@C
7590:   DMGetBoundary - Get a model boundary condition

7592:   Input Parameters:
7593: + dm          - The mesh object
7594: - bd          - The BC number

7596:   Output Parameters:
7597: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7598: . name        - The BC name
7599: . labelname   - The label defining constrained points
7600: . field       - The field to constrain
7601: . numcomps    - The number of constrained field components
7602: . comps       - An array of constrained component numbers
7603: . bcFunc      - A pointwise function giving boundary values
7604: . numids      - The number of DMLabel ids for constrained points
7605: . ids         - An array of ids for constrained points
7606: - ctx         - An optional user context for bcFunc

7608:   Options Database Keys:
7609: + -bc_<boundary name> <num> - Overrides the boundary ids
7610: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7612:   Level: developer

7614: .seealso: DMAddBoundary()
7615: @*/
7616: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
7617: {
7618:   PetscDS        ds;

7623:   DMGetDS(dm, &ds);
7624:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);
7625:   return(0);
7626: }

7628: static PetscErrorCode DMPopulateBoundary(DM dm)
7629: {
7630:   PetscDS        ds;
7631:   DMBoundary    *lastnext;
7632:   DSBoundary     dsbound;

7636:   DMGetDS(dm, &ds);
7637:   dsbound = ds->boundary;
7638:   if (dm->boundary) {
7639:     DMBoundary next = dm->boundary;

7641:     /* quick check to see if the PetscDS has changed */
7642:     if (next->dsboundary == dsbound) return(0);
7643:     /* the PetscDS has changed: tear down and rebuild */
7644:     while (next) {
7645:       DMBoundary b = next;

7647:       next = b->next;
7648:       PetscFree(b);
7649:     }
7650:     dm->boundary = NULL;
7651:   }

7653:   lastnext = &(dm->boundary);
7654:   while (dsbound) {
7655:     DMBoundary dmbound;

7657:     PetscNew(&dmbound);
7658:     dmbound->dsboundary = dsbound;
7659:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
7660:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
7661:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7662:     *lastnext = dmbound;
7663:     lastnext = &(dmbound->next);
7664:     dsbound = dsbound->next;
7665:   }
7666:   return(0);
7667: }

7669: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7670: {
7671:   DMBoundary     b;

7677:   *isBd = PETSC_FALSE;
7678:   DMPopulateBoundary(dm);
7679:   b = dm->boundary;
7680:   while (b && !(*isBd)) {
7681:     DMLabel    label = b->label;
7682:     DSBoundary dsb = b->dsboundary;

7684:     if (label) {
7685:       PetscInt i;

7687:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7688:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
7689:       }
7690:     }
7691:     b = b->next;
7692:   }
7693:   return(0);
7694: }

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

7699:   Collective on DM

7701:   Input Parameters:
7702: + dm      - The DM
7703: . time    - The time
7704: . funcs   - The coordinate functions to evaluate, one per field
7705: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7706: - mode    - The insertion mode for values

7708:   Output Parameter:
7709: . X - vector

7711:    Calling sequence of func:
7712: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7714: +  dim - The spatial dimension
7715: .  x   - The coordinates
7716: .  Nf  - The number of fields
7717: .  u   - The output field values
7718: -  ctx - optional user-defined function context

7720:   Level: developer

7722: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7723: @*/
7724: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7725: {
7726:   Vec            localX;

7731:   DMGetLocalVector(dm, &localX);
7732:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7733:   DMLocalToGlobalBegin(dm, localX, mode, X);
7734:   DMLocalToGlobalEnd(dm, localX, mode, X);
7735:   DMRestoreLocalVector(dm, &localX);
7736:   return(0);
7737: }

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

7742:   Not collective

7744:   Input Parameters:
7745: + dm      - The DM
7746: . time    - The time
7747: . funcs   - The coordinate functions to evaluate, one per field
7748: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7749: - mode    - The insertion mode for values

7751:   Output Parameter:
7752: . localX - vector

7754:    Calling sequence of func:
7755: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7757: +  dim - The spatial dimension
7758: .  x   - The coordinates
7759: .  Nf  - The number of fields
7760: .  u   - The output field values
7761: -  ctx - optional user-defined function context

7763:   Level: developer

7765: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7766: @*/
7767: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7768: {

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

7779: /*@C
7780:   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.

7782:   Collective on DM

7784:   Input Parameters:
7785: + dm      - The DM
7786: . time    - The time
7787: . label   - The DMLabel selecting the portion of the mesh for projection
7788: . funcs   - The coordinate functions to evaluate, one per field
7789: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7790: - mode    - The insertion mode for values

7792:   Output Parameter:
7793: . X - vector

7795:    Calling sequence of func:
7796: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7798: +  dim - The spatial dimension
7799: .  x   - The coordinates
7800: .  Nf  - The number of fields
7801: .  u   - The output field values
7802: -  ctx - optional user-defined function context

7804:   Level: developer

7806: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
7807: @*/
7808: 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)
7809: {
7810:   Vec            localX;

7815:   DMGetLocalVector(dm, &localX);
7816:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7817:   DMLocalToGlobalBegin(dm, localX, mode, X);
7818:   DMLocalToGlobalEnd(dm, localX, mode, X);
7819:   DMRestoreLocalVector(dm, &localX);
7820:   return(0);
7821: }

7823: /*@C
7824:   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.

7826:   Not collective

7828:   Input Parameters:
7829: + dm      - The DM
7830: . time    - The time
7831: . label   - The DMLabel selecting the portion of the mesh for projection
7832: . funcs   - The coordinate functions to evaluate, one per field
7833: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7834: - mode    - The insertion mode for values

7836:   Output Parameter:
7837: . localX - vector

7839:    Calling sequence of func:
7840: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7842: +  dim - The spatial dimension
7843: .  x   - The coordinates
7844: .  Nf  - The number of fields
7845: .  u   - The output field values
7846: -  ctx - optional user-defined function context

7848:   Level: developer

7850: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7851: @*/
7852: 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)
7853: {

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

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

7867:   Not collective

7869:   Input Parameters:
7870: + dm      - The DM
7871: . time    - The time
7872: . localU  - The input field vector
7873: . funcs   - The functions to evaluate, one per field
7874: - mode    - The insertion mode for values

7876:   Output Parameter:
7877: . localX  - The output vector

7879:    Calling sequence of func:
7880: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7881: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7882: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7883: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7885: +  dim          - The spatial dimension
7886: .  Nf           - The number of input fields
7887: .  NfAux        - The number of input auxiliary fields
7888: .  uOff         - The offset of each field in u[]
7889: .  uOff_x       - The offset of each field in u_x[]
7890: .  u            - The field values at this point in space
7891: .  u_t          - The field time derivative at this point in space (or NULL)
7892: .  u_x          - The field derivatives at this point in space
7893: .  aOff         - The offset of each auxiliary field in u[]
7894: .  aOff_x       - The offset of each auxiliary field in u_x[]
7895: .  a            - The auxiliary field values at this point in space
7896: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7897: .  a_x          - The auxiliary field derivatives at this point in space
7898: .  t            - The current time
7899: .  x            - The coordinates of this point
7900: .  numConstants - The number of constants
7901: .  constants    - The value of each constant
7902: -  f            - The value of the function at this point in space

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

7909:   Level: intermediate

7911: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7912: @*/
7913: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7914:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7915:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7916:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7917:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7918:                                    InsertMode mode, Vec localX)
7919: {

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

7931: /*@C
7932:   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.

7934:   Not collective

7936:   Input Parameters:
7937: + dm      - The DM
7938: . time    - The time
7939: . label   - The DMLabel marking the portion of the domain to output
7940: . numIds  - The number of label ids to use
7941: . ids     - The label ids to use for marking
7942: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
7943: . comps   - The components to set in the output, or NULL for all components
7944: . localU  - The input field vector
7945: . funcs   - The functions to evaluate, one per field
7946: - mode    - The insertion mode for values

7948:   Output Parameter:
7949: . localX  - The output vector

7951:    Calling sequence of func:
7952: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7953: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7954: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7955: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7957: +  dim          - The spatial dimension
7958: .  Nf           - The number of input fields
7959: .  NfAux        - The number of input auxiliary fields
7960: .  uOff         - The offset of each field in u[]
7961: .  uOff_x       - The offset of each field in u_x[]
7962: .  u            - The field values at this point in space
7963: .  u_t          - The field time derivative at this point in space (or NULL)
7964: .  u_x          - The field derivatives at this point in space
7965: .  aOff         - The offset of each auxiliary field in u[]
7966: .  aOff_x       - The offset of each auxiliary field in u_x[]
7967: .  a            - The auxiliary field values at this point in space
7968: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7969: .  a_x          - The auxiliary field derivatives at this point in space
7970: .  t            - The current time
7971: .  x            - The coordinates of this point
7972: .  numConstants - The number of constants
7973: .  constants    - The value of each constant
7974: -  f            - The value of the function at this point in space

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

7981:   Level: intermediate

7983: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7984: @*/
7985: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7986:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7987:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7988:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7989:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7990:                                         InsertMode mode, Vec localX)
7991: {

7998:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7999:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8000:   return(0);
8001: }

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

8006:   Input Parameters:
8007: + dm    - The DM
8008: . time  - The time
8009: . funcs - The functions to evaluate for each field component
8010: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8011: - X     - The coefficient vector u_h, a global vector

8013:   Output Parameter:
8014: . diff - The diff ||u - u_h||_2

8016:   Level: developer

8018: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8019: @*/
8020: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8021: {

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

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

8035:   Collective on dm

8037:   Input Parameters:
8038: + dm    - The DM
8039: , time  - The time
8040: . funcs - The gradient functions to evaluate for each field component
8041: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8042: . X     - The coefficient vector u_h, a global vector
8043: - n     - The vector to project along

8045:   Output Parameter:
8046: . diff - The diff ||(grad u - grad u_h) . n||_2

8048:   Level: developer

8050: .seealso: DMProjectFunction(), DMComputeL2Diff()
8051: @*/
8052: 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)
8053: {

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

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

8067:   Collective on dm

8069:   Input Parameters:
8070: + dm    - The DM
8071: . time  - The time
8072: . funcs - The functions to evaluate for each field component
8073: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8074: - X     - The coefficient vector u_h, a global vector

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

8079:   Level: developer

8081: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8082: @*/
8083: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8084: {

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

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

8099:   Collective on dm

8101:   Input parameters:
8102: + dm - the pre-adaptation DM object
8103: - label - label with the flags

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

8108:   Level: intermediate

8110: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8111: @*/
8112: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8113: {

8120:   *dmAdapt = NULL;
8121:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8122:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8123:   return(0);
8124: }

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

8129:   Input Parameters:
8130: + dm - The DM object
8131: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8132: - 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_".

8134:   Output Parameter:
8135: . dmAdapt  - Pointer to the DM object containing the adapted mesh

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

8139:   Level: advanced

8141: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8142: @*/
8143: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8144: {

8152:   *dmAdapt = NULL;
8153:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8154:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8155:   return(0);
8156: }

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

8161:  Not Collective

8163:  Input Parameter:
8164:  . dm    - The DM

8166:  Output Parameter:
8167:  . nranks - the number of neighbours
8168:  . ranks - the neighbors ranks

8170:  Notes:
8171:  Do not free the array, it is freed when the DM is destroyed.

8173:  Level: beginner

8175:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8176: @*/
8177: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8178: {

8183:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8184:   (dm->ops->getneighbors)(dm,nranks,ranks);
8185:   return(0);
8186: }

8188: #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */

8190: /*
8191:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8192:     This has be a different function because it requires DM which is not defined in the Mat library
8193: */
8194: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8195: {

8199:   if (coloring->ctype == IS_COLORING_LOCAL) {
8200:     Vec x1local;
8201:     DM  dm;
8202:     MatGetDM(J,&dm);
8203:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8204:     DMGetLocalVector(dm,&x1local);
8205:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8206:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8207:     x1   = x1local;
8208:   }
8209:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8210:   if (coloring->ctype == IS_COLORING_LOCAL) {
8211:     DM  dm;
8212:     MatGetDM(J,&dm);
8213:     DMRestoreLocalVector(dm,&x1);
8214:   }
8215:   return(0);
8216: }

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

8221:     Input Parameter:
8222: .    coloring - the MatFDColoring object

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

8227:     Level: advanced

8229: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8230: @*/
8231: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8232: {
8234:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8235:   return(0);
8236: }

8238: /*@
8239:     DMGetCompatibility - determine if two DMs are compatible

8241:     Collective

8243:     Input Parameters:
8244: +    dm - the first DM
8245: -    dm2 - the second DM

8247:     Output Parameters:
8248: +    compatible - whether or not the two DMs are compatible
8249: -    set - whether or not the compatible value was set

8251:     Notes:
8252:     Two DMs are deemed compatible if they represent the same parallel decomposition
8253:     of the same topology. This implies that the section (field data) on one
8254:     "makes sense" with respect to the topology and parallel decomposition of the other.
8255:     Loosely speaking, compatible DMs represent the same domain and parallel
8256:     decomposition, but hold different data.

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

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

8266:     Consider the operation of summing data living on a 2-dof DMDA to data living
8267:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8268: .vb
8269:   ...
8270:   DMGetCompatibility(da1,da2,&compatible,&set);
8271:   if (set && compatible)  {
8272:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8273:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8274:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8275:     for (j=y; j<y+n; ++j) {
8276:       for (i=x; i<x+m, ++i) {
8277:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8278:       }
8279:     }
8280:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8281:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8282:   } else {
8283:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8284:   }
8285:   ...
8286: .ve

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

8293:     A DM is always compatible with itself.

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

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

8303:     Developer Notes:
8304:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8305:     iff B is compatible with A. Thus, this function checks the implementations
8306:     of both dm and dm2 (if they are of different types), attempting to determine
8307:     compatibility. It is left to DM implementers to ensure that symmetry is
8308:     preserved. The simplest way to do this is, when implementing type-specific
8309:     logic for this function, is to check for existing logic in the implementation
8310:     of other DM types and let *set = PETSC_FALSE if found.

8312:     Level: advanced

8314: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8315: @*/

8317: PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
8318: {
8320:   PetscMPIInt    compareResult;
8321:   DMType         type,type2;
8322:   PetscBool      sameType;


8328:   /* Declare a DM compatible with itself */
8329:   if (dm == dm2) {
8330:     *set = PETSC_TRUE;
8331:     *compatible = PETSC_TRUE;
8332:     return(0);
8333:   }

8335:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8336:      communicator. Note that this does not preclude compatibility with
8337:      DMs living on "congruent" or "similar" communicators, but this must be
8338:      determined by the implementation-specific logic */
8339:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);
8340:   if (compareResult == MPI_UNEQUAL) {
8341:     *set = PETSC_TRUE;
8342:     *compatible = PETSC_FALSE;
8343:     return(0);
8344:   }

8346:   /* Pass to the implementation-specific routine, if one exists. */
8347:   if (dm->ops->getcompatibility) {
8348:     (*dm->ops->getcompatibility)(dm,dm2,compatible,set);
8349:     if (*set) return(0);
8350:   }

8352:   /* If dm and dm2 are of different types, then attempt to check compatibility
8353:      with an implementation of this function from dm2 */
8354:   DMGetType(dm,&type);
8355:   DMGetType(dm2,&type2);
8356:   PetscStrcmp(type,type2,&sameType);
8357:   if (!sameType && dm2->ops->getcompatibility) {
8358:     (*dm2->ops->getcompatibility)(dm2,dm,compatible,set); /* Note argument order */
8359:   } else {
8360:     *set = PETSC_FALSE;
8361:   }
8362:   return(0);
8363: }

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

8368:   Logically Collective on DM

8370:   Input Parameters:
8371: + DM - the DM
8372: . f - the monitor function
8373: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8374: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

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

8380:   Notes:
8381:   Several different monitoring routines may be set by calling
8382:   DMMonitorSet() multiple times; all will be called in the
8383:   order in which they were set.

8385:   Fortran Notes:
8386:   Only a single monitor function can be set for each DM object

8388:   Level: intermediate

8390: .seealso: DMMonitorCancel()
8391: @*/
8392: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8393: {
8394:   PetscInt       m;

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

8402:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8403:     if (identical) return(0);
8404:   }
8405:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8406:   dm->monitor[dm->numbermonitors]          = f;
8407:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8408:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8409:   return(0);
8410: }

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

8415:   Logically Collective on DM

8417:   Input Parameter:
8418: . dm - the DM

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

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

8428:   Level: intermediate

8430: .seealso: DMMonitorSet()
8431: @*/
8432: PetscErrorCode DMMonitorCancel(DM dm)
8433: {
8435:   PetscInt       m;

8439:   for (m = 0; m < dm->numbermonitors; ++m) {
8440:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
8441:   }
8442:   dm->numbermonitors = 0;
8443:   return(0);
8444: }

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

8449:   Collective on DM

8451:   Input Parameters:
8452: + dm   - DM object you wish to monitor
8453: . name - the monitor type one is seeking
8454: . help - message indicating what monitoring is done
8455: . manual - manual page for the monitor
8456: . monitor - the monitor function
8457: - 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

8459:   Output Parameter:
8460: . flg - Flag set if the monitor was created

8462:   Level: developer

8464: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8465:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8466:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8467:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8468:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8469:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8470:           PetscOptionsFList(), PetscOptionsEList()
8471: @*/
8472: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8473: {
8474:   PetscViewer       viewer;
8475:   PetscViewerFormat format;
8476:   PetscErrorCode    ierr;

8480:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
8481:   if (*flg) {
8482:     PetscViewerAndFormat *vf;

8484:     PetscViewerAndFormatCreate(viewer, format, &vf);
8485:     PetscObjectDereference((PetscObject) viewer);
8486:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
8487:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
8488:   }
8489:   return(0);
8490: }

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

8495:    Collective on DM

8497:    Input Parameters:
8498: .  dm - The DM

8500:    Level: developer

8502: .seealso: DMMonitorSet()
8503: @*/
8504: PetscErrorCode DMMonitor(DM dm)
8505: {
8506:   PetscInt       m;

8510:   if (!dm) return(0);
8512:   for (m = 0; m < dm->numbermonitors; ++m) {
8513:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8514:   }
8515:   return(0);
8516: }