Actual source code: dm.c

petsc-master 2020-01-17
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};

 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->localSection             = NULL;
 59:   v->globalSection            = NULL;
 60:   v->defaultConstraintSection = NULL;
 61:   v->defaultConstraintMat     = NULL;
 62:   v->L                        = NULL;
 63:   v->maxCell                  = NULL;
 64:   v->bdtype                   = NULL;
 65:   v->dimEmbed                 = PETSC_DEFAULT;
 66:   v->dim                      = PETSC_DETERMINE;
 67:   {
 68:     PetscInt i;
 69:     for (i = 0; i < 10; ++i) {
 70:       v->nullspaceConstructors[i] = NULL;
 71:       v->nearnullspaceConstructors[i] = NULL;
 72:     }
 73:   }
 74:   PetscDSCreate(PetscObjectComm((PetscObject) v), &ds);
 75:   DMSetRegionDS(v, NULL, NULL, ds);
 76:   PetscDSDestroy(&ds);
 77:   v->dmBC = NULL;
 78:   v->coarseMesh = NULL;
 79:   v->outputSequenceNum = -1;
 80:   v->outputSequenceVal = 0.0;
 81:   DMSetVecType(v,VECSTANDARD);
 82:   DMSetMatType(v,MATAIJ);

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

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

 91:   Collective

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

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

 99:   Level: beginner

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

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

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

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

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

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

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

177:    Logically Collective on da

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

183:    Options Database:
184: .   -dm_vec_type ctype

186:    Level: intermediate

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

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

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

204:    Logically Collective on da

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

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

212:    Level: intermediate

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

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

227:   Not collective

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

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

235:   Level: intermediate

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

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

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

253:   Not collective

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

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

261:   Level: intermediate

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

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

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

279:    Logically Collective on dm

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

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

288:    Level: intermediate

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

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

304:    Logically Collective on dm

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

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

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

315:    Level: intermediate

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

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

331:    Logically Collective on dm

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

337:    Options Database:
338: .   -dm_mat_type ctype

340:    Level: intermediate

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

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

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

358:    Logically Collective on dm

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

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

366:    Options Database:
367: .   -dm_mat_type ctype

369:    Level: intermediate

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

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

384:   Not collective

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

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

392:   Level: intermediate

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

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

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

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

413:   Not collective

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

419:   Level: intermediate

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


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

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

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

442:    Logically Collective on dm

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

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

452:    Level: advanced

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

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

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

476:    Logically Collective on dm

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

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

486:    Level: advanced

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

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

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

504:    Not Collective

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

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

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

516:    Level: advanced

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

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

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

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

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

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

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

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

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

591: /*@
592:     DMDestroy - Destroys a vector packer or DM.

594:     Collective on dm

596:     Input Parameter:
597: .   dm - the DM object to destroy

599:     Level: developer

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

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

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

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

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

710:       next = b->next;
711:       PetscFree(b);
712:     }
713:   }

715:   PetscObjectDestroy(&(*dm)->dmksp);
716:   PetscObjectDestroy(&(*dm)->dmsnes);
717:   PetscObjectDestroy(&(*dm)->dmts);

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

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

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

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

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

776:     Collective on dm

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

781:     Level: developer

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

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

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

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

803:     Collective on dm

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

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

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

823:     Level: intermediate

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

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

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

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

863:    Collective on DM

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

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

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

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

886:     Collective on dm

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

892:     Level: beginner

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

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

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

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

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

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

942:     Collective on dm

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

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

950:     Level: beginner

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

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

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

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

970:     Not Collective

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

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

978:     Level: beginner

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

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

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

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

998:    Collective on dm

1000:    Input Parameter:
1001: .  dm - the DM that provides the mapping

1003:    Output Parameter:
1004: .  ltog - the mapping

1006:    Level: intermediate

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

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

1022:   if (!dm->ltogmap) {
1023:     PetscSection section, sectionGlobal;

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

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

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

1076: /*@
1077:    DMGetBlockSize - Gets the inherent block size associated with a DM

1079:    Not Collective

1081:    Input Parameter:
1082: .  dm - the DM with block structure

1084:    Output Parameter:
1085: .  bs - the block size, 1 implies no exploitable block structure

1087:    Level: intermediate

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

1101: /*@
1102:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1104:     Collective on dm1

1106:     Input Parameter:
1107: +   dm1 - the DM object
1108: -   dm2 - the second, finer DM object

1110:     Output Parameter:
1111: +  mat - the interpolation
1112: -  vec - the scaling (optional)

1114:     Level: developer

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

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


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

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

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

1142: /*@
1143:     DMCreateRestriction - Gets restriction matrix between two DM objects

1145:     Collective on dm1

1147:     Input Parameter:
1148: +   dm1 - the DM object
1149: -   dm2 - the second, finer DM object

1151:     Output Parameter:
1152: .  mat - the restriction


1155:     Level: developer

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


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

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

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

1180: /*@
1181:     DMCreateInjection - Gets injection matrix between two DM objects

1183:     Collective on dm1

1185:     Input Parameter:
1186: +   dm1 - the DM object
1187: -   dm2 - the second, finer DM object

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

1192:     Level: developer

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

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

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

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

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

1219:   Collective on dm1

1221:   Input Parameter:
1222: + dm1 - the DM object
1223: - dm2 - the second, finer DM object

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

1228:   Level: developer

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

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

1245: /*@
1246:     DMCreateColoring - Gets coloring for a DM

1248:     Collective on dm

1250:     Input Parameter:
1251: +   dm - the DM object
1252: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1254:     Output Parameter:
1255: .   coloring - the coloring

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

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

1263:     Level: developer

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

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

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

1280: /*@
1281:     DMCreateMatrix - Gets empty Jacobian for a DM

1283:     Collective on dm

1285:     Input Parameter:
1286: .   dm - the DM object

1288:     Output Parameter:
1289: .   mat - the empty Jacobian

1291:     Level: beginner

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

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

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

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

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

1308: @*/
1309: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1310: {

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

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

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

1347:   Logically Collective on dm

1349:   Input Parameter:
1350: + dm - the DM
1351: - only - PETSC_TRUE if only want preallocation

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

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

1368:   Logically Collective on dm

1370:   Input Parameter:
1371: + dm - the DM
1372: - only - PETSC_TRUE if only want matrix stucture

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

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

1388:   Not Collective

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

1395:   Output Parameter:
1396: . array - the work array

1398:   Level: developer

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

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

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

1432:   Not Collective

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

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

1442:   Level: developer

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

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

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

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

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

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

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

1508:   Not collective

1510:   Input Parameter:
1511: . dm - the DM object

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

1518:   Level: intermediate

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

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

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

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

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

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

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

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

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

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


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

1636:   Not collective

1638:   Input Parameter:
1639: . dm - the DM object

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

1647:   Level: intermediate

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

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

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

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

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

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

1719:   Not collective

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

1726:   Output Parameters:
1727: + is - The global indices for the subproblem
1728: - subdm - The DM for the subproblem

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

1732:   Level: intermediate

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

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

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

1753:   Not collective

1755:   Input Parameter:
1756: + dms - The DM objects
1757: - len - The number of DMs

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

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

1765:   Level: intermediate

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

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


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

1796:   Not collective

1798:   Input Parameter:
1799: . dm - the DM object

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

1808:   Level: intermediate

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

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

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


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

1856:   Not collective

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

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

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

1875:   Level: developer

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

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

1891: /*@
1892:   DMRefine - Refines a DM object

1894:   Collective on dm

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

1900:   Output Parameter:
1901: . dmf - the refined DM, or NULL

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

1905:   Level: developer

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

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

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

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

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

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

1942:    Logically Collective

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

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

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

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

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

1965:    Level: advanced

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

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

1972:    This function is currently not available from Fortran.

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

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

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

1998:    Logically Collective

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

2006:    Level: advanced

2008:    Notes:
2009:    This function does nothing if the hook is not in the list.

2011:    This function is currently not available from Fortran.

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

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

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

2036:    Collective if any hooks are

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

2043:    Level: developer

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

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

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

2064:     Not Collective

2066:     Input Parameter:
2067: .   dm - the DM object

2069:     Output Parameter:
2070: .   level - number of refinements

2072:     Level: developer

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

2076: @*/
2077: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2078: {
2081:   *level = dm->levelup;
2082:   return(0);
2083: }

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

2088:     Not Collective

2090:     Input Parameter:
2091: +   dm - the DM object
2092: -   level - number of refinements

2094:     Level: advanced

2096:     Notes:
2097:     This value is used by PCMG to determine how many multigrid levels to use

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

2101: @*/
2102: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2103: {
2106:   dm->levelup = level;
2107:   return(0);
2108: }

2110: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2111: {
2115:   *tdm = dm->transformDM;
2116:   return(0);
2117: }

2119: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2120: {
2124:   *tv = dm->transform;
2125:   return(0);
2126: }

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

2131:   Input Parameter:
2132: . dm - The DM

2134:   Output Parameter:
2135: . flg - PETSC_TRUE if a basis transformation should be done

2137:   Level: developer

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

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

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

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

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

2203: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2204: {

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

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

2221:    Logically Collective

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

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

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


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

2242: +  global - global DM
2243: -  ctx - optional user-defined function context

2245:    Level: advanced

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

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

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

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

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

2299: /*@
2300:     DMGlobalToLocal - update local vectors from global vector

2302:     Neighbor-wise Collective on dm

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

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

2314:     Level: beginner

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

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

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

2329: /*@
2330:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2332:     Neighbor-wise Collective on dm

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

2340:     Level: intermediate

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

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

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

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

2376: /*@
2377:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2379:     Neighbor-wise Collective on dm

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

2387:     Level: intermediate

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

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

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

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

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

2428:    Logically Collective

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

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

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


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

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

2455:    Level: advanced

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

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

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

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

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

2517:     Neighbor-wise Collective on dm

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

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

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

2532:     Level: beginner

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

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

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

2547: /*@
2548:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2550:     Neighbor-wise Collective on dm

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

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

2562:     Level: intermediate

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

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

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

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

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

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

2661: /*@
2662:     DMLocalToGlobalEnd - updates global vectors from local vectors

2664:     Neighbor-wise Collective on dm

2666:     Input Parameters:
2667: +   dm - the DM object
2668: .   l - the local vector
2669: .   mode - INSERT_VALUES or ADD_VALUES
2670: -   g - the global vector

2672:     Level: intermediate

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

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

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

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

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

2736:    Neighbor-wise Collective on dm

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

2743:    Output Parameter:
2744: .  l  - the local vector with correct ghost values

2746:    Level: intermediate

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

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

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

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

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

2773:    Neighbor-wise Collective on dm

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

2780:    Output Parameter:
2781: .  l  - the local vector with correct ghost values

2783:    Level: intermediate

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

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

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

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


2806: /*@
2807:     DMCoarsen - Coarsens a DM object

2809:     Collective on dm

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

2815:     Output Parameter:
2816: .   dmc - the coarsened DM

2818:     Level: developer

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

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

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

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

2853:    Logically Collective

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

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

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

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

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

2878:    Level: advanced

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

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

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

2888:    This function is currently not available from Fortran.

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

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

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

2914:    Logically Collective

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

2922:    Level: advanced

2924:    Notes:
2925:    This function does nothing if the hook is not in the list.

2927:    This function is currently not available from Fortran.

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

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


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

2953:    Collective if any hooks are

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

2962:    Level: developer

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

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

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

2983:    Logically Collective on global

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


2992:    Calling sequence for ddhook:
2993: $    ddhook(DM global,DM block,void *ctx)

2995: +  global - global DM
2996: .  block  - block DM
2997: -  ctx - optional user-defined function context

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

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

3008:    Level: advanced

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

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

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

3018:    This function is currently not available from Fortran.

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

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

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

3044:    Logically Collective

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

3052:    Level: advanced

3054:    Notes:

3056:    This function is currently not available from Fortran.

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

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

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

3081:    Collective if any hooks are

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

3089:    Level: developer

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

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

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

3110:     Not Collective

3112:     Input Parameter:
3113: .   dm - the DM object

3115:     Output Parameter:
3116: .   level - number of coarsenings

3118:     Level: developer

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

3122: @*/
3123: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3124: {
3128:   *level = dm->leveldown;
3129:   return(0);
3130: }

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

3135:     Not Collective

3137:     Input Parameters:
3138: +   dm - the DM object
3139: -   level - number of coarsenings

3141:     Level: developer

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



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

3158:     Collective on dm

3160:     Input Parameter:
3161: +   dm - the DM object
3162: -   nlevels - the number of levels of refinement

3164:     Output Parameter:
3165: .   dmf - the refined DM hierarchy

3167:     Level: developer

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

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

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

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

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

3197:     Collective on dm

3199:     Input Parameter:
3200: +   dm - the DM object
3201: -   nlevels - the number of levels of coarsening

3203:     Output Parameter:
3204: .   dmc - the coarsened DM hierarchy

3206:     Level: developer

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

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

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

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

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

3236:     Not Collective

3238:     Input Parameters:
3239: +   dm - the DM object
3240: -   destroy - the destroy function

3242:     Level: intermediate

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

3246: @*/
3247: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3248: {
3251:   dm->ctxdestroy = destroy;
3252:   return(0);
3253: }

3255: /*@
3256:     DMSetApplicationContext - Set a user context into a DM object

3258:     Not Collective

3260:     Input Parameters:
3261: +   dm - the DM object
3262: -   ctx - the user context

3264:     Level: intermediate

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

3268: @*/
3269: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3270: {
3273:   dm->ctx = ctx;
3274:   return(0);
3275: }

3277: /*@
3278:     DMGetApplicationContext - Gets a user context from a DM object

3280:     Not Collective

3282:     Input Parameter:
3283: .   dm - the DM object

3285:     Output Parameter:
3286: .   ctx - the user context

3288:     Level: intermediate

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

3292: @*/
3293: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3294: {
3297:   *(void**)ctx = dm->ctx;
3298:   return(0);
3299: }

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

3304:     Logically Collective on dm

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

3310:     Level: intermediate

3312: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3313:          DMSetJacobian()

3315: @*/
3316: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3317: {
3320:   dm->ops->computevariablebounds = f;
3321:   return(0);
3322: }

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

3327:     Not Collective

3329:     Input Parameter:
3330: .   dm - the DM object to destroy

3332:     Output Parameter:
3333: .   flg - PETSC_TRUE if the variable bounds function exists

3335:     Level: developer

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

3339: @*/
3340: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3341: {
3345:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3346:   return(0);
3347: }

3349: /*@C
3350:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3352:     Logically Collective on dm

3354:     Input Parameters:
3355: .   dm - the DM object

3357:     Output parameters:
3358: +   xl - lower bound
3359: -   xu - upper bound

3361:     Level: advanced

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

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

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

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

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

3385:     Not Collective

3387:     Input Parameter:
3388: .   dm - the DM object

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

3393:     Level: developer

3395: .seealso DMCreateColoring()

3397: @*/
3398: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3399: {
3403:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3404:   return(0);
3405: }

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

3410:     Not Collective

3412:     Input Parameter:
3413: .   dm - the DM object

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

3418:     Level: developer

3420: .seealso DMCreateRestriction()

3422: @*/
3423: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3424: {
3428:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3429:   return(0);
3430: }


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

3436:     Not Collective

3438:     Input Parameter:
3439: .   dm - the DM object

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

3444:     Level: developer

3446: .seealso DMCreateInjection()

3448: @*/
3449: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3450: {

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


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

3468:     Collective on dm

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

3474:     Level: developer

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

3478: @*/
3479: PetscErrorCode  DMSetVec(DM dm,Vec x)
3480: {

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

3496: PetscFunctionList DMList              = NULL;
3497: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3499: /*@C
3500:   DMSetType - Builds a DM, for a particular DM implementation.

3502:   Collective on dm

3504:   Input Parameters:
3505: + dm     - The DM object
3506: - method - The name of the DM type

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

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

3514:   Level: intermediate

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

3526:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3527:   if (match) return(0);

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

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

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

3545:   Not Collective

3547:   Input Parameter:
3548: . dm  - The DM

3550:   Output Parameter:
3551: . type - The DM type name

3553:   Level: intermediate

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

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

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

3572:   Collective on dm

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

3578:   Output Parameter:
3579: . M - pointer to new DM

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

3586:   Level: intermediate

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

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

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

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

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

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

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

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

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

3675: /*--------------------------------------------------------------------------------------------------------------------*/

3677: /*@C
3678:   DMRegister -  Adds a new DM component implementation

3680:   Not Collective

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

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


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

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

3705:   Level: advanced

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

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

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

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

3723:   Collective on viewer

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

3731:    Level: intermediate

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

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

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

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

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

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

3778:   Not collective

3780:   Input Parameter:
3781: . dm - the DM

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

3787:   Level: beginner

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


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

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

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

3830: /*@
3831:   DMGetBoundingBox - Returns the global bounding box for the DM.

3833:   Collective

3835:   Input Parameter:
3836: . dm - the DM

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

3842:   Level: beginner

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

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

3863: /******************************** FEM Support **********************************/

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

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

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

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

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

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

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

3929:   Input Parameter:
3930: . dm - The DM

3932:   Output Parameter:
3933: . section - The PetscSection

3935:   Options Database Keys:
3936: . -dm_petscsection_view - View the Section created by the DM

3938:   Level: advanced

3940:   Notes:
3941:   Use DMGetLocalSection() in new code.

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

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

3952:   DMGetLocalSection(dm,section);
3953:   return(0);
3954: }

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

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

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

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

3968:   Level: intermediate

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

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

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

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

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

3995:   Input Parameters:
3996: + dm - The DM
3997: - section - The PetscSection

3999:   Level: advanced

4001:   Notes:
4002:   Use DMSetLocalSection() in new code.

4004:   Any existing Section will be destroyed

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

4013:   DMSetLocalSection(dm,section);
4014:   return(0);
4015: }

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

4020:   Input Parameters:
4021: + dm - The DM
4022: - section - The PetscSection

4024:   Level: intermediate

4026:   Note: Any existing Section will be destroyed

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

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

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

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

4062:   not collective

4064:   Input Parameter:
4065: . dm - The DM

4067:   Output Parameter:
4068: + 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.
4069: - 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.

4071:   Level: advanced

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

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

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

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

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

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

4096:   collective on dm

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

4103:   Level: advanced

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

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

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

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

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

4144:   Level: intermediate

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

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

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

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

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

4207:   Collective on dm

4209:   Input Parameter:
4210: . dm - The DM

4212:   Output Parameter:
4213: . section - The PetscSection

4215:   Level: intermediate

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

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

4228:   if (!dm->globalSection) {
4229:     PetscSection s;

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

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

4246:   Input Parameters:
4247: + dm - The DM
4248: - section - The PetscSection, or NULL

4250:   Level: intermediate

4252:   Note: Any existing Section will be destroyed

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

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

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

4276:   Input Parameter:
4277: . dm - The DM

4279:   Output Parameter:
4280: . sf - The PetscSF

4282:   Level: intermediate

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

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

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

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

4316: /*@
4317:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4319:   Input Parameters:
4320: + dm - The DM
4321: - sf - The PetscSF

4323:   Level: intermediate

4325:   Note: Any previous SF is destroyed

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

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

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

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

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

4353:   Level: developer

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

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

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

4387:     PetscSectionGetDof(globalSection, p, &gdof);
4388:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4389:     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));
4390:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4391:   }
4392:   PetscMalloc1(nleaves, &local);
4393:   PetscMalloc1(nleaves, &remote);
4394:   for (p = pStart, l = 0; p < pEnd; ++p) {
4395:     const PetscInt *cind;
4396:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4398:     PetscSectionGetDof(localSection, p, &dof);
4399:     PetscSectionGetOffset(localSection, p, &off);
4400:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4401:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4402:     PetscSectionGetDof(globalSection, p, &gdof);
4403:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4404:     PetscSectionGetOffset(globalSection, p, &goff);
4405:     if (!gdof) continue; /* Censored point */
4406:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4407:     if (gsize != dof-cdof) {
4408:       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);
4409:       cdof = 0; /* Ignore constraints */
4410:     }
4411:     for (d = 0, c = 0; d < dof; ++d) {
4412:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4413:       local[l+d-c] = off+d;
4414:     }
4415:     if (gdof < 0) {
4416:       for (d = 0; d < gsize; ++d, ++l) {
4417:         PetscInt offset = -(goff+1) + d, r;

4419:         PetscFindInt(offset,size+1,ranges,&r);
4420:         if (r < 0) r = -(r+2);
4421:         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);
4422:         remote[l].rank  = r;
4423:         remote[l].index = offset - ranges[r];
4424:       }
4425:     } else {
4426:       for (d = 0; d < gsize; ++d, ++l) {
4427:         remote[l].rank  = rank;
4428:         remote[l].index = goff+d - ranges[rank];
4429:       }
4430:     }
4431:   }
4432:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4433:   PetscLayoutDestroy(&layout);
4434:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4435:   return(0);
4436: }

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

4441:   Input Parameter:
4442: . dm - The DM

4444:   Output Parameter:
4445: . sf - The PetscSF

4447:   Level: intermediate

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

4451: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4452: @*/
4453: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4454: {
4458:   *sf = dm->sf;
4459:   return(0);
4460: }

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

4465:   Input Parameters:
4466: + dm - The DM
4467: - sf - The PetscSF

4469:   Level: intermediate

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

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

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

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

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

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

4520: /*@
4521:   DMClearFields - Remove all fields from the DM

4523:   Logically collective on dm

4525:   Input Parameter:
4526: . dm - The DM

4528:   Level: intermediate

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

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

4549: /*@
4550:   DMGetNumFields - Get the number of fields in the DM

4552:   Not collective

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

4557:   Output Parameter:
4558: . Nf - The number of fields

4560:   Level: intermediate

4562: .seealso: DMSetNumFields(), DMSetField()
4563: @*/
4564: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4565: {
4569:   *numFields = dm->Nf;
4570:   return(0);
4571: }

4573: /*@
4574:   DMSetNumFields - Set the number of fields in the DM

4576:   Logically collective on dm

4578:   Input Parameters:
4579: + dm - The DM
4580: - Nf - The number of fields

4582:   Level: intermediate

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

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

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

4604: /*@
4605:   DMGetField - Return the discretization object for a given DM field

4607:   Not collective

4609:   Input Parameters:
4610: + dm - The DM
4611: - f  - The field number

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

4617:   Level: intermediate

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

4632: /*@
4633:   DMSetField - Set the discretization object for a given DM field

4635:   Logically collective on dm

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

4643:   Level: intermediate

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

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

4668: /*@
4669:   DMAddField - Add the discretization object for the given DM field

4671:   Logically collective on dm

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

4678:   Level: intermediate

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

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

4701: /*@
4702:   DMCopyFields - Copy the discretizations for the DM into another DM

4704:   Collective on dm

4706:   Input Parameter:
4707: . dm - The DM

4709:   Output Parameter:
4710: . newdm - The DM

4712:   Level: advanced

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

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

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

4738: /*@
4739:   DMGetAdjacency - Returns the flags for determining variable influence

4741:   Not collective

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

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

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

4757:   Level: developer

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

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

4782: /*@
4783:   DMSetAdjacency - Set the flags for determining variable influence

4785:   Not collective

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

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

4799:   Level: developer

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

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

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

4825:   Not collective

4827:   Input Parameters:
4828: . dm - The DM object

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

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

4839:   Level: developer

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

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

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

4864:   Not collective

4866:   Input Parameters:
4867: + dm         - The DM object
4868: . useCone    - Flag for variable influence starting with the cone operation
4869: - useClosure - Flag for variable influence using transitive closure

4871:   Notes:
4872: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4873: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4874: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4876:   Level: developer

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

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

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

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

4913: /*@
4914:   DMGetNumDS - Get the number of discrete systems in the DM

4916:   Not collective

4918:   Input Parameter:
4919: . dm - The DM

4921:   Output Parameter:
4922: . Nds - The number of PetscDS objects

4924:   Level: intermediate

4926: .seealso: DMGetDS(), DMGetCellDS()
4927: @*/
4928: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
4929: {
4933:   *Nds = dm->Nds;
4934:   return(0);
4935: }

4937: /*@
4938:   DMClearDS - Remove all discrete systems from the DM

4940:   Logically collective on dm

4942:   Input Parameter:
4943: . dm - The DM

4945:   Level: intermediate

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

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

4967: /*@
4968:   DMGetDS - Get the default PetscDS

4970:   Not collective

4972:   Input Parameter:
4973: . dm    - The DM

4975:   Output Parameter:
4976: . prob - The default PetscDS

4978:   Level: intermediate

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

4989:   if (dm->Nds <= 0) {
4990:     PetscDS ds;

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

5000: /*@
5001:   DMGetCellDS - Get the PetscDS defined on a given cell

5003:   Not collective

5005:   Input Parameters:
5006: + dm    - The DM
5007: - point - Cell for the DS

5009:   Output Parameter:
5010: . prob - The PetscDS defined on the given cell

5012:   Level: developer

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

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

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

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

5042:   Not collective

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

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

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

5054:   Level: advanced

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

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

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

5080:   Not collective

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

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

5091:   Level: advanced

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

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

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

5122:   Collective on dm

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

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

5133:   Level: advanced

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

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

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

5171:   Collective on dm

5173:   Input Parameter:
5174: . dm - The DM

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

5178:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

5284: /*@
5285:   DMCopyDS - Copy the discrete systems for the DM into another DM

5287:   Collective on dm

5289:   Input Parameter:
5290: . dm - The DM

5292:   Output Parameter:
5293: . newdm - The DM

5295:   Level: advanced

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

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

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

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

5322:   Collective on dm

5324:   Input Parameter:
5325: . dm - The DM

5327:   Output Parameter:
5328: . newdm - The DM

5330:   Level: advanced

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

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

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

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

5401: /*@
5402:   DMGetDimension - Return the topological dimension of the DM

5404:   Not collective

5406:   Input Parameter:
5407: . dm - The DM

5409:   Output Parameter:
5410: . dim - The topological dimension

5412:   Level: beginner

5414: .seealso: DMSetDimension(), DMCreate()
5415: @*/
5416: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5417: {
5421:   *dim = dm->dim;
5422:   return(0);
5423: }

5425: /*@
5426:   DMSetDimension - Set the topological dimension of the DM

5428:   Collective on dm

5430:   Input Parameters:
5431: + dm - The DM
5432: - dim - The topological dimension

5434:   Level: beginner

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

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

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

5455:   Collective on dm

5457:   Input Parameters:
5458: + dm - the DM
5459: - dim - the dimension

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

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

5470:   Level: intermediate

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

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

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

5491:   Collective on dm

5493:   Input Parameters:
5494: + dm - the DM
5495: - c - coordinate vector

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

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

5502:   Level: intermediate

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

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

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

5525:   Not collective

5527:    Input Parameters:
5528: +  dm - the DM
5529: -  c - coordinate vector

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

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

5538:   Level: intermediate

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

5549:   PetscObjectReference((PetscObject) c);
5550:   VecDestroy(&dm->coordinatesLocal);

5552:   dm->coordinatesLocal = c;

5554:   VecDestroy(&dm->coordinates);
5555:   return(0);
5556: }

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

5561:   Collective on dm

5563:   Input Parameter:
5564: . dm - the DM

5566:   Output Parameter:
5567: . c - global coordinate vector

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

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

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

5577:   Level: intermediate

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

5588:   if (!dm->coordinates && dm->coordinatesLocal) {
5589:     DM        cdm = NULL;
5590:     PetscBool localized;

5592:     DMGetCoordinateDM(dm, &cdm);
5593:     DMCreateGlobalVector(cdm, &dm->coordinates);
5594:     DMGetCoordinatesLocalized(dm, &localized);
5595:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5596:     if (localized) {
5597:       PetscInt cdim;

5599:       DMGetCoordinateDim(dm, &cdim);
5600:       VecSetBlockSize(dm->coordinates, cdim);
5601:     }
5602:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
5603:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5604:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
5605:   }
5606:   *c = dm->coordinates;
5607:   return(0);
5608: }

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

5613:   Collective on dm

5615:   Input Parameter:
5616: . dm - the DM

5618:   Level: advanced

5620: .seealso: DMGetCoordinatesLocalNoncollective()
5621: @*/
5622: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
5623: {

5628:   if (!dm->coordinatesLocal && dm->coordinates) {
5629:     DM        cdm = NULL;
5630:     PetscBool localized;

5632:     DMGetCoordinateDM(dm, &cdm);
5633:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
5634:     DMGetCoordinatesLocalized(dm, &localized);
5635:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
5636:     if (localized) {
5637:       PetscInt cdim;

5639:       DMGetCoordinateDim(dm, &cdim);
5640:       VecSetBlockSize(dm->coordinates, cdim);
5641:     }
5642:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
5643:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5644:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
5645:   }
5646:   return(0);
5647: }

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

5652:   Collective on dm

5654:   Input Parameter:
5655: . dm - the DM

5657:   Output Parameter:
5658: . c - coordinate vector

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

5663:   Each process has the local and ghost coordinates

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

5668:   Level: intermediate

5670: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
5671: @*/
5672: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
5673: {

5679:   DMGetCoordinatesLocalSetUp(dm);
5680:   *c = dm->coordinatesLocal;
5681:   return(0);
5682: }

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

5687:   Not collective

5689:   Input Parameter:
5690: . dm - the DM

5692:   Output Parameter:
5693: . c - coordinate vector

5695:   Level: advanced

5697: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5698: @*/
5699: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
5700: {
5704:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
5705:   *c = dm->coordinatesLocal;
5706:   return(0);
5707: }

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

5712:   Not collective

5714:   Input Parameter:
5715: + dm - the DM
5716: - p - the IS of points whose coordinates will be returned

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

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

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

5727:   Each process has the local and ghost coordinates

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

5732:   Level: advanced

5734: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
5735: @*/
5736: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
5737: {
5738:   PetscSection        cs, newcs;
5739:   Vec                 coords;
5740:   const PetscScalar   *arr;
5741:   PetscScalar         *newarr=NULL;
5742:   PetscInt            n;
5743:   PetscErrorCode      ierr;

5750:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
5751:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
5752:   cs = dm->coordinateDM->localSection;
5753:   coords = dm->coordinatesLocal;
5754:   VecGetArrayRead(coords, &arr);
5755:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
5756:   VecRestoreArrayRead(coords, &arr);
5757:   if (pCoord) {
5758:     PetscSectionGetStorageSize(newcs, &n);
5759:     /* set array in two steps to mimic PETSC_OWN_POINTER */
5760:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
5761:     VecReplaceArray(*pCoord, newarr);
5762:   } else {
5763:     PetscFree(newarr);
5764:   }
5765:   if (pCoordSection) {*pCoordSection = newcs;}
5766:   else               {PetscSectionDestroy(&newcs);}
5767:   return(0);
5768: }

5770: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
5771: {

5777:   if (!dm->coordinateField) {
5778:     if (dm->ops->createcoordinatefield) {
5779:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
5780:     }
5781:   }
5782:   *field = dm->coordinateField;
5783:   return(0);
5784: }

5786: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
5787: {

5793:   PetscObjectReference((PetscObject)field);
5794:   DMFieldDestroy(&dm->coordinateField);
5795:   dm->coordinateField = field;
5796:   return(0);
5797: }

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

5802:   Collective on dm

5804:   Input Parameter:
5805: . dm - the DM

5807:   Output Parameter:
5808: . cdm - coordinate DM

5810:   Level: intermediate

5812: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5813: @*/
5814: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
5815: {

5821:   if (!dm->coordinateDM) {
5822:     DM cdm;

5824:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
5825:     (*dm->ops->createcoordinatedm)(dm, &cdm);
5826:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
5827:      * until the call to CreateCoordinateDM) */
5828:     DMDestroy(&dm->coordinateDM);
5829:     dm->coordinateDM = cdm;
5830:   }
5831:   *cdm = dm->coordinateDM;
5832:   return(0);
5833: }

5835: /*@
5836:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

5838:   Logically Collective on dm

5840:   Input Parameters:
5841: + dm - the DM
5842: - cdm - coordinate DM

5844:   Level: intermediate

5846: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
5847: @*/
5848: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
5849: {

5855:   PetscObjectReference((PetscObject)cdm);
5856:   DMDestroy(&dm->coordinateDM);
5857:   dm->coordinateDM = cdm;
5858:   return(0);
5859: }

5861: /*@
5862:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

5864:   Not Collective

5866:   Input Parameter:
5867: . dm - The DM object

5869:   Output Parameter:
5870: . dim - The embedding dimension

5872:   Level: intermediate

5874: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5875: @*/
5876: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
5877: {
5881:   if (dm->dimEmbed == PETSC_DEFAULT) {
5882:     dm->dimEmbed = dm->dim;
5883:   }
5884:   *dim = dm->dimEmbed;
5885:   return(0);
5886: }

5888: /*@
5889:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

5891:   Not Collective

5893:   Input Parameters:
5894: + dm  - The DM object
5895: - dim - The embedding dimension

5897:   Level: intermediate

5899: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5900: @*/
5901: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
5902: {
5903:   PetscDS        ds;

5908:   dm->dimEmbed = dim;
5909:   DMGetDS(dm, &ds);
5910:   PetscDSSetCoordinateDimension(ds, dim);
5911:   return(0);
5912: }

5914: /*@
5915:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

5917:   Collective on dm

5919:   Input Parameter:
5920: . dm - The DM object

5922:   Output Parameter:
5923: . section - The PetscSection object

5925:   Level: intermediate

5927: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
5928: @*/
5929: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
5930: {
5931:   DM             cdm;

5937:   DMGetCoordinateDM(dm, &cdm);
5938:   DMGetLocalSection(cdm, section);
5939:   return(0);
5940: }

5942: /*@
5943:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

5945:   Not Collective

5947:   Input Parameters:
5948: + dm      - The DM object
5949: . dim     - The embedding dimension, or PETSC_DETERMINE
5950: - section - The PetscSection object

5952:   Level: intermediate

5954: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
5955: @*/
5956: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
5957: {
5958:   DM             cdm;

5964:   DMGetCoordinateDM(dm, &cdm);
5965:   DMSetLocalSection(cdm, section);
5966:   if (dim == PETSC_DETERMINE) {
5967:     PetscInt d = PETSC_DEFAULT;
5968:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

5970:     PetscSectionGetChart(section, &pStart, &pEnd);
5971:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
5972:     pStart = PetscMax(vStart, pStart);
5973:     pEnd   = PetscMin(vEnd, pEnd);
5974:     for (v = pStart; v < pEnd; ++v) {
5975:       PetscSectionGetDof(section, v, &dd);
5976:       if (dd) {d = dd; break;}
5977:     }
5978:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
5979:   }
5980:   return(0);
5981: }

5983: /*@C
5984:   DMGetPeriodicity - Get the description of mesh periodicity

5986:   Input Parameters:
5987: . dm      - The DM object

5989:   Output Parameters:
5990: + per     - Whether the DM is periodic or not
5991: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
5992: . L       - If we assume the mesh is a torus, this is the length of each coordinate
5993: - bd      - This describes the type of periodicity in each topological dimension

5995:   Level: developer

5997: .seealso: DMGetPeriodicity()
5998: @*/
5999: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6000: {
6003:   if (per)     *per     = dm->periodic;
6004:   if (L)       *L       = dm->L;
6005:   if (maxCell) *maxCell = dm->maxCell;
6006:   if (bd)      *bd      = dm->bdtype;
6007:   return(0);
6008: }

6010: /*@C
6011:   DMSetPeriodicity - Set the description of mesh periodicity

6013:   Input Parameters:
6014: + dm      - The DM object
6015: . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
6016: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6017: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6018: - bd      - This describes the type of periodicity in each topological dimension

6020:   Level: developer

6022: .seealso: DMGetPeriodicity()
6023: @*/
6024: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6025: {
6026:   PetscInt       dim, d;

6032:   if (maxCell) {
6036:   }
6037:   PetscFree3(dm->L,dm->maxCell,dm->bdtype);
6038:   DMGetDimension(dm, &dim);
6039:   if (maxCell) {
6040:     PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);
6041:     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
6042:   }
6043:   dm->periodic = per;
6044:   return(0);
6045: }

6047: /*@
6048:   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.

6050:   Input Parameters:
6051: + dm     - The DM
6052: . in     - The input coordinate point (dim numbers)
6053: - endpoint - Include the endpoint L_i

6055:   Output Parameter:
6056: . out - The localized coordinate point

6058:   Level: developer

6060: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6061: @*/
6062: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6063: {
6064:   PetscInt       dim, d;

6068:   DMGetCoordinateDim(dm, &dim);
6069:   if (!dm->maxCell) {
6070:     for (d = 0; d < dim; ++d) out[d] = in[d];
6071:   } else {
6072:     if (endpoint) {
6073:       for (d = 0; d < dim; ++d) {
6074:         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)) {
6075:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6076:         } else {
6077:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6078:         }
6079:       }
6080:     } else {
6081:       for (d = 0; d < dim; ++d) {
6082:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6083:       }
6084:     }
6085:   }
6086:   return(0);
6087: }

6089: /*
6090:   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.

6092:   Input Parameters:
6093: + dm     - The DM
6094: . dim    - The spatial dimension
6095: . anchor - The anchor point, the input point can be no more than maxCell away from it
6096: - in     - The input coordinate point (dim numbers)

6098:   Output Parameter:
6099: . out - The localized coordinate point

6101:   Level: developer

6103:   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

6105: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6106: */
6107: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6108: {
6109:   PetscInt d;

6112:   if (!dm->maxCell) {
6113:     for (d = 0; d < dim; ++d) out[d] = in[d];
6114:   } else {
6115:     for (d = 0; d < dim; ++d) {
6116:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6117:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6118:       } else {
6119:         out[d] = in[d];
6120:       }
6121:     }
6122:   }
6123:   return(0);
6124: }
6125: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6126: {
6127:   PetscInt d;

6130:   if (!dm->maxCell) {
6131:     for (d = 0; d < dim; ++d) out[d] = in[d];
6132:   } else {
6133:     for (d = 0; d < dim; ++d) {
6134:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6135:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6136:       } else {
6137:         out[d] = in[d];
6138:       }
6139:     }
6140:   }
6141:   return(0);
6142: }

6144: /*
6145:   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.

6147:   Input Parameters:
6148: + dm     - The DM
6149: . dim    - The spatial dimension
6150: . anchor - The anchor point, the input point can be no more than maxCell away from it
6151: . in     - The input coordinate delta (dim numbers)
6152: - out    - The input coordinate point (dim numbers)

6154:   Output Parameter:
6155: . out    - The localized coordinate in + out

6157:   Level: developer

6159:   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

6161: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6162: */
6163: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6164: {
6165:   PetscInt d;

6168:   if (!dm->maxCell) {
6169:     for (d = 0; d < dim; ++d) out[d] += in[d];
6170:   } else {
6171:     for (d = 0; d < dim; ++d) {
6172:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6173:         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6174:       } else {
6175:         out[d] += in[d];
6176:       }
6177:     }
6178:   }
6179:   return(0);
6180: }

6182: /*@
6183:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6185:   Not collective

6187:   Input Parameter:
6188: . dm - The DM

6190:   Output Parameter:
6191:   areLocalized - True if localized

6193:   Level: developer

6195: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6196: @*/
6197: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6198: {
6199:   DM             cdm;
6200:   PetscSection   coordSection;
6201:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6202:   PetscBool      isPlex, alreadyLocalized;

6208:   *areLocalized = PETSC_FALSE;

6210:   /* We need some generic way of refering to cells/vertices */
6211:   DMGetCoordinateDM(dm, &cdm);
6212:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6213:   if (!isPlex) return(0);

6215:   DMGetCoordinateSection(dm, &coordSection);
6216:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6217:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6218:   alreadyLocalized = PETSC_FALSE;
6219:   for (c = cStart; c < cEnd; ++c) {
6220:     if (c < sStart || c >= sEnd) continue;
6221:     PetscSectionGetDof(coordSection, c, &dof);
6222:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6223:   }
6224:   *areLocalized = alreadyLocalized;
6225:   return(0);
6226: }

6228: /*@
6229:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

6231:   Collective on dm

6233:   Input Parameter:
6234: . dm - The DM

6236:   Output Parameter:
6237:   areLocalized - True if localized

6239:   Level: developer

6241: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6242: @*/
6243: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6244: {
6245:   PetscBool      localized;

6251:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6252:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6253:   return(0);
6254: }

6256: /*@
6257:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

6259:   Collective on dm

6261:   Input Parameter:
6262: . dm - The DM

6264:   Level: developer

6266: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6267: @*/
6268: PetscErrorCode DMLocalizeCoordinates(DM dm)
6269: {
6270:   DM             cdm;
6271:   PetscSection   coordSection, cSection;
6272:   Vec            coordinates,  cVec;
6273:   PetscScalar   *coords, *coords2, *anchor, *localized;
6274:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6275:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6276:   PetscInt       maxHeight = 0, h;
6277:   PetscInt       *pStart = NULL, *pEnd = NULL;

6282:   if (!dm->periodic) return(0);
6283:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6284:   if (alreadyLocalized) return(0);

6286:   /* We need some generic way of refering to cells/vertices */
6287:   DMGetCoordinateDM(dm, &cdm);
6288:   {
6289:     PetscBool isplex;

6291:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6292:     if (isplex) {
6293:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6294:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6295:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6296:       pEnd = &pStart[maxHeight + 1];
6297:       newStart = vStart;
6298:       newEnd   = vEnd;
6299:       for (h = 0; h <= maxHeight; h++) {
6300:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6301:         newStart = PetscMin(newStart,pStart[h]);
6302:         newEnd   = PetscMax(newEnd,pEnd[h]);
6303:       }
6304:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6305:   }
6306:   DMGetCoordinatesLocal(dm, &coordinates);
6307:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6308:   DMGetCoordinateSection(dm, &coordSection);
6309:   VecGetBlockSize(coordinates, &bs);
6310:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6312:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6313:   PetscSectionSetNumFields(cSection, 1);
6314:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6315:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6316:   PetscSectionSetChart(cSection, newStart, newEnd);

6318:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6319:   localized = &anchor[bs];
6320:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6321:   for (h = 0; h <= maxHeight; h++) {
6322:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6324:     for (c = cStart; c < cEnd; ++c) {
6325:       PetscScalar *cellCoords = NULL;
6326:       PetscInt     b;

6328:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6329:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6330:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6331:       for (d = 0; d < dof/bs; ++d) {
6332:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6333:         for (b = 0; b < bs; b++) {
6334:           if (cellCoords[d*bs + b] != localized[b]) break;
6335:         }
6336:         if (b < bs) break;
6337:       }
6338:       if (d < dof/bs) {
6339:         if (c >= sStart && c < sEnd) {
6340:           PetscInt cdof;

6342:           PetscSectionGetDof(coordSection, c, &cdof);
6343:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6344:         }
6345:         PetscSectionSetDof(cSection, c, dof);
6346:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6347:       }
6348:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6349:     }
6350:   }
6351:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6352:   if (alreadyLocalizedGlobal) {
6353:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6354:     PetscSectionDestroy(&cSection);
6355:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6356:     return(0);
6357:   }
6358:   for (v = vStart; v < vEnd; ++v) {
6359:     PetscSectionGetDof(coordSection, v, &dof);
6360:     PetscSectionSetDof(cSection, v, dof);
6361:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6362:   }
6363:   PetscSectionSetUp(cSection);
6364:   PetscSectionGetStorageSize(cSection, &coordSize);
6365:   VecCreate(PETSC_COMM_SELF, &cVec);
6366:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6367:   VecSetBlockSize(cVec, bs);
6368:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6369:   VecSetType(cVec, VECSTANDARD);
6370:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6371:   VecGetArray(cVec, &coords2);
6372:   for (v = vStart; v < vEnd; ++v) {
6373:     PetscSectionGetDof(coordSection, v, &dof);
6374:     PetscSectionGetOffset(coordSection, v, &off);
6375:     PetscSectionGetOffset(cSection,     v, &off2);
6376:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6377:   }
6378:   for (h = 0; h <= maxHeight; h++) {
6379:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6381:     for (c = cStart; c < cEnd; ++c) {
6382:       PetscScalar *cellCoords = NULL;
6383:       PetscInt     b, cdof;

6385:       PetscSectionGetDof(cSection,c,&cdof);
6386:       if (!cdof) continue;
6387:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6388:       PetscSectionGetOffset(cSection, c, &off2);
6389:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6390:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6391:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6392:     }
6393:   }
6394:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6395:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6396:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6397:   VecRestoreArray(cVec, &coords2);
6398:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6399:   DMSetCoordinatesLocal(dm, cVec);
6400:   VecDestroy(&cVec);
6401:   PetscSectionDestroy(&cSection);
6402:   return(0);
6403: }

6405: /*@
6406:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

6408:   Collective on v (see explanation below)

6410:   Input Parameters:
6411: + dm - The DM
6412: . v - The Vec of points
6413: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6414: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

6416:   Output Parameter:
6417: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6418: - cells - The PetscSF containing the ranks and local indices of the containing points.


6421:   Level: developer

6423:   Notes:
6424:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6425:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

6427:   If *cellSF is NULL on input, a PetscSF will be created.
6428:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

6430:   An array that maps each point to its containing cell can be obtained with

6432: $    const PetscSFNode *cells;
6433: $    PetscInt           nFound;
6434: $    const PetscInt    *found;
6435: $
6436: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

6438:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6439:   the index of the cell in its rank's local numbering.

6441: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6442: @*/
6443: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6444: {

6451:   if (*cellSF) {
6452:     PetscMPIInt result;

6455:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6456:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6457:   } else {
6458:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6459:   }
6460:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6461:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6462:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6463:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6464:   return(0);
6465: }

6467: /*@
6468:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6470:   Collective on dm

6472:   Input Parameter:
6473: . dm - The original DM

6475:   Output Parameter:
6476: . odm - The DM which provides the layout for output

6478:   Level: intermediate

6480: .seealso: VecView(), DMGetGlobalSection()
6481: @*/
6482: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6483: {
6484:   PetscSection   section;
6485:   PetscBool      hasConstraints, ghasConstraints;

6491:   DMGetLocalSection(dm, &section);
6492:   PetscSectionHasConstraints(section, &hasConstraints);
6493:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6494:   if (!ghasConstraints) {
6495:     *odm = dm;
6496:     return(0);
6497:   }
6498:   if (!dm->dmBC) {
6499:     PetscSection newSection, gsection;
6500:     PetscSF      sf;

6502:     DMClone(dm, &dm->dmBC);
6503:     DMCopyDisc(dm, dm->dmBC);
6504:     PetscSectionClone(section, &newSection);
6505:     DMSetLocalSection(dm->dmBC, newSection);
6506:     PetscSectionDestroy(&newSection);
6507:     DMGetPointSF(dm->dmBC, &sf);
6508:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6509:     DMSetGlobalSection(dm->dmBC, gsection);
6510:     PetscSectionDestroy(&gsection);
6511:   }
6512:   *odm = dm->dmBC;
6513:   return(0);
6514: }

6516: /*@
6517:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6519:   Input Parameter:
6520: . dm - The original DM

6522:   Output Parameters:
6523: + num - The output sequence number
6524: - val - The output sequence value

6526:   Level: intermediate

6528:   Note: This is intended for output that should appear in sequence, for instance
6529:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

6531: .seealso: VecView()
6532: @*/
6533: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6534: {
6539:   return(0);
6540: }

6542: /*@
6543:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6545:   Input Parameters:
6546: + dm - The original DM
6547: . num - The output sequence number
6548: - val - The output sequence value

6550:   Level: intermediate

6552:   Note: This is intended for output that should appear in sequence, for instance
6553:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

6555: .seealso: VecView()
6556: @*/
6557: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6558: {
6561:   dm->outputSequenceNum = num;
6562:   dm->outputSequenceVal = val;
6563:   return(0);
6564: }

6566: /*@C
6567:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

6569:   Input Parameters:
6570: + dm   - The original DM
6571: . name - The sequence name
6572: - num  - The output sequence number

6574:   Output Parameter:
6575: . val  - The output sequence value

6577:   Level: intermediate

6579:   Note: This is intended for output that should appear in sequence, for instance
6580:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

6582: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
6583: @*/
6584: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6585: {
6586:   PetscBool      ishdf5;

6593:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
6594:   if (ishdf5) {
6595: #if defined(PETSC_HAVE_HDF5)
6596:     PetscScalar value;

6598:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6599:     *val = PetscRealPart(value);
6600: #endif
6601:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6602:   return(0);
6603: }

6605: /*@
6606:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

6608:   Not collective

6610:   Input Parameter:
6611: . dm - The DM

6613:   Output Parameter:
6614: . useNatural - The flag to build the mapping to a natural order during distribution

6616:   Level: beginner

6618: .seealso: DMSetUseNatural(), DMCreate()
6619: @*/
6620: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6621: {
6625:   *useNatural = dm->useNatural;
6626:   return(0);
6627: }

6629: /*@
6630:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

6632:   Collective on dm

6634:   Input Parameters:
6635: + dm - The DM
6636: - useNatural - The flag to build the mapping to a natural order during distribution

6638:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

6640:   Level: beginner

6642: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
6643: @*/
6644: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6645: {
6649:   dm->useNatural = useNatural;
6650:   return(0);
6651: }


6654: /*@C
6655:   DMCreateLabel - Create a label of the given name if it does not already exist

6657:   Not Collective

6659:   Input Parameters:
6660: + dm   - The DM object
6661: - name - The label name

6663:   Level: intermediate

6665: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6666: @*/
6667: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6668: {
6669:   PetscBool      flg;
6670:   DMLabel        label;

6676:   DMHasLabel(dm, name, &flg);
6677:   if (!flg) {
6678:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6679:     DMAddLabel(dm, label);
6680:     DMLabelDestroy(&label);
6681:   }
6682:   return(0);
6683: }

6685: /*@C
6686:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

6688:   Not Collective

6690:   Input Parameters:
6691: + dm   - The DM object
6692: . name - The label name
6693: - point - The mesh point

6695:   Output Parameter:
6696: . value - The label value for this point, or -1 if the point is not in the label

6698:   Level: beginner

6700: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
6701: @*/
6702: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6703: {
6704:   DMLabel        label;

6710:   DMGetLabel(dm, name, &label);
6711:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6712:   DMLabelGetValue(label, point, value);
6713:   return(0);
6714: }

6716: /*@C
6717:   DMSetLabelValue - Add a point to a Sieve Label with given value

6719:   Not Collective

6721:   Input Parameters:
6722: + dm   - The DM object
6723: . name - The label name
6724: . point - The mesh point
6725: - value - The label value for this point

6727:   Output Parameter:

6729:   Level: beginner

6731: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
6732: @*/
6733: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6734: {
6735:   DMLabel        label;

6741:   DMGetLabel(dm, name, &label);
6742:   if (!label) {
6743:     DMCreateLabel(dm, name);
6744:     DMGetLabel(dm, name, &label);
6745:   }
6746:   DMLabelSetValue(label, point, value);
6747:   return(0);
6748: }

6750: /*@C
6751:   DMClearLabelValue - Remove a point from a Sieve Label with given value

6753:   Not Collective

6755:   Input Parameters:
6756: + dm   - The DM object
6757: . name - The label name
6758: . point - The mesh point
6759: - value - The label value for this point

6761:   Output Parameter:

6763:   Level: beginner

6765: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
6766: @*/
6767: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6768: {
6769:   DMLabel        label;

6775:   DMGetLabel(dm, name, &label);
6776:   if (!label) return(0);
6777:   DMLabelClearValue(label, point, value);
6778:   return(0);
6779: }

6781: /*@C
6782:   DMGetLabelSize - Get the number of different integer ids in a Label

6784:   Not Collective

6786:   Input Parameters:
6787: + dm   - The DM object
6788: - name - The label name

6790:   Output Parameter:
6791: . size - The number of different integer ids, or 0 if the label does not exist

6793:   Level: beginner

6795: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
6796: @*/
6797: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6798: {
6799:   DMLabel        label;

6806:   DMGetLabel(dm, name, &label);
6807:   *size = 0;
6808:   if (!label) return(0);
6809:   DMLabelGetNumValues(label, size);
6810:   return(0);
6811: }

6813: /*@C
6814:   DMGetLabelIdIS - Get the integer ids in a label

6816:   Not Collective

6818:   Input Parameters:
6819: + mesh - The DM object
6820: - name - The label name

6822:   Output Parameter:
6823: . ids - The integer ids, or NULL if the label does not exist

6825:   Level: beginner

6827: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
6828: @*/
6829: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6830: {
6831:   DMLabel        label;

6838:   DMGetLabel(dm, name, &label);
6839:   *ids = NULL;
6840:  if (label) {
6841:     DMLabelGetValueIS(label, ids);
6842:   } else {
6843:     /* returning an empty IS */
6844:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
6845:   }
6846:   return(0);
6847: }

6849: /*@C
6850:   DMGetStratumSize - Get the number of points in a label stratum

6852:   Not Collective

6854:   Input Parameters:
6855: + dm - The DM object
6856: . name - The label name
6857: - value - The stratum value

6859:   Output Parameter:
6860: . size - The stratum size

6862:   Level: beginner

6864: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
6865: @*/
6866: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6867: {
6868:   DMLabel        label;

6875:   DMGetLabel(dm, name, &label);
6876:   *size = 0;
6877:   if (!label) return(0);
6878:   DMLabelGetStratumSize(label, value, size);
6879:   return(0);
6880: }

6882: /*@C
6883:   DMGetStratumIS - Get the points in a label stratum

6885:   Not Collective

6887:   Input Parameters:
6888: + dm - The DM object
6889: . name - The label name
6890: - value - The stratum value

6892:   Output Parameter:
6893: . points - The stratum points, or NULL if the label does not exist or does not have that value

6895:   Level: beginner

6897: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
6898: @*/
6899: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6900: {
6901:   DMLabel        label;

6908:   DMGetLabel(dm, name, &label);
6909:   *points = NULL;
6910:   if (!label) return(0);
6911:   DMLabelGetStratumIS(label, value, points);
6912:   return(0);
6913: }

6915: /*@C
6916:   DMSetStratumIS - Set the points in a label stratum

6918:   Not Collective

6920:   Input Parameters:
6921: + dm - The DM object
6922: . name - The label name
6923: . value - The stratum value
6924: - points - The stratum points

6926:   Level: beginner

6928: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
6929: @*/
6930: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6931: {
6932:   DMLabel        label;

6939:   DMGetLabel(dm, name, &label);
6940:   if (!label) return(0);
6941:   DMLabelSetStratumIS(label, value, points);
6942:   return(0);
6943: }

6945: /*@C
6946:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

6948:   Not Collective

6950:   Input Parameters:
6951: + dm   - The DM object
6952: . name - The label name
6953: - value - The label value for this point

6955:   Output Parameter:

6957:   Level: beginner

6959: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
6960: @*/
6961: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6962: {
6963:   DMLabel        label;

6969:   DMGetLabel(dm, name, &label);
6970:   if (!label) return(0);
6971:   DMLabelClearStratum(label, value);
6972:   return(0);
6973: }

6975: /*@
6976:   DMGetNumLabels - Return the number of labels defined by the mesh

6978:   Not Collective

6980:   Input Parameter:
6981: . dm   - The DM object

6983:   Output Parameter:
6984: . numLabels - the number of Labels

6986:   Level: intermediate

6988: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
6989: @*/
6990: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6991: {
6992:   DMLabelLink next = dm->labels;
6993:   PetscInt  n    = 0;

6998:   while (next) {++n; next = next->next;}
6999:   *numLabels = n;
7000:   return(0);
7001: }

7003: /*@C
7004:   DMGetLabelName - Return the name of nth label

7006:   Not Collective

7008:   Input Parameters:
7009: + dm - The DM object
7010: - n  - the label number

7012:   Output Parameter:
7013: . name - the label name

7015:   Level: intermediate

7017: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7018: @*/
7019: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7020: {
7021:   DMLabelLink    next = dm->labels;
7022:   PetscInt       l    = 0;

7028:   while (next) {
7029:     if (l == n) {
7030:       PetscObjectGetName((PetscObject) next->label, name);
7031:       return(0);
7032:     }
7033:     ++l;
7034:     next = next->next;
7035:   }
7036:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7037: }

7039: /*@C
7040:   DMHasLabel - Determine whether the mesh has a label of a given name

7042:   Not Collective

7044:   Input Parameters:
7045: + dm   - The DM object
7046: - name - The label name

7048:   Output Parameter:
7049: . hasLabel - PETSC_TRUE if the label is present

7051:   Level: intermediate

7053: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7054: @*/
7055: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7056: {
7057:   DMLabelLink    next = dm->labels;
7058:   const char    *lname;

7065:   *hasLabel = PETSC_FALSE;
7066:   while (next) {
7067:     PetscObjectGetName((PetscObject) next->label, &lname);
7068:     PetscStrcmp(name, lname, hasLabel);
7069:     if (*hasLabel) break;
7070:     next = next->next;
7071:   }
7072:   return(0);
7073: }

7075: /*@C
7076:   DMGetLabel - Return the label of a given name, or NULL

7078:   Not Collective

7080:   Input Parameters:
7081: + dm   - The DM object
7082: - name - The label name

7084:   Output Parameter:
7085: . label - The DMLabel, or NULL if the label is absent

7087:   Level: intermediate

7089: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7090: @*/
7091: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7092: {
7093:   DMLabelLink    next = dm->labels;
7094:   PetscBool      hasLabel;
7095:   const char    *lname;

7102:   *label = NULL;
7103:   while (next) {
7104:     PetscObjectGetName((PetscObject) next->label, &lname);
7105:     PetscStrcmp(name, lname, &hasLabel);
7106:     if (hasLabel) {
7107:       *label = next->label;
7108:       break;
7109:     }
7110:     next = next->next;
7111:   }
7112:   return(0);
7113: }

7115: /*@C
7116:   DMGetLabelByNum - Return the nth label

7118:   Not Collective

7120:   Input Parameters:
7121: + dm - The DM object
7122: - n  - the label number

7124:   Output Parameter:
7125: . label - the label

7127:   Level: intermediate

7129: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7130: @*/
7131: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7132: {
7133:   DMLabelLink next = dm->labels;
7134:   PetscInt    l    = 0;

7139:   while (next) {
7140:     if (l == n) {
7141:       *label = next->label;
7142:       return(0);
7143:     }
7144:     ++l;
7145:     next = next->next;
7146:   }
7147:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7148: }

7150: /*@C
7151:   DMAddLabel - Add the label to this mesh

7153:   Not Collective

7155:   Input Parameters:
7156: + dm   - The DM object
7157: - label - The DMLabel

7159:   Level: developer

7161: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7162: @*/
7163: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7164: {
7165:   DMLabelLink    l, *p, tmpLabel;
7166:   PetscBool      hasLabel;
7167:   const char    *lname;
7168:   PetscBool      flg;

7173:   PetscObjectGetName((PetscObject) label, &lname);
7174:   DMHasLabel(dm, lname, &hasLabel);
7175:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7176:   PetscCalloc1(1, &tmpLabel);
7177:   tmpLabel->label  = label;
7178:   tmpLabel->output = PETSC_TRUE;
7179:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7180:   *p = tmpLabel;
7181:   PetscObjectReference((PetscObject)label);
7182:   PetscStrcmp(lname, "depth", &flg);
7183:   if (flg) dm->depthLabel = label;
7184:   return(0);
7185: }

7187: /*@C
7188:   DMRemoveLabel - Remove the label given by name from this mesh

7190:   Not Collective

7192:   Input Parameters:
7193: + dm   - The DM object
7194: - name - The label name

7196:   Output Parameter:
7197: . label - The DMLabel, or NULL if the label is absent

7199:   Level: developer

7201:   Notes:
7202:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7203:   DMLabelDestroy() on the label.

7205:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7206:   call DMLabelDestroy(). Instead, the label is returned and the user is
7207:   responsible of calling DMLabelDestroy() at some point.

7209: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7210: @*/
7211: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7212: {
7213:   DMLabelLink    link, *pnext;
7214:   PetscBool      hasLabel;
7215:   const char    *lname;

7221:   if (label) {
7223:     *label = NULL;
7224:   }
7225:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7226:     PetscObjectGetName((PetscObject) link->label, &lname);
7227:     PetscStrcmp(name, lname, &hasLabel);
7228:     if (hasLabel) {
7229:       *pnext = link->next; /* Remove from list */
7230:       PetscStrcmp(name, "depth", &hasLabel);
7231:       if (hasLabel) dm->depthLabel = NULL;
7232:       if (label) *label = link->label;
7233:       else       {DMLabelDestroy(&link->label);}
7234:       PetscFree(link);
7235:       break;
7236:     }
7237:   }
7238:   return(0);
7239: }

7241: /*@
7242:   DMRemoveLabelBySelf - Remove the label from this mesh

7244:   Not Collective

7246:   Input Parameters:
7247: + dm   - The DM object
7248: . label - (Optional) The DMLabel to be removed from the DM
7249: - failNotFound - Should it fail if the label is not found in the DM?

7251:   Level: developer

7253:   Notes:
7254:   Only exactly the same instance is removed if found, name match is ignored.
7255:   If the DM has an exclusive reference to the label, it gets destroyed and
7256:   *label nullified.

7258: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7259: @*/
7260: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7261: {
7262:   DMLabelLink    link, *pnext;
7263:   PetscBool      hasLabel = PETSC_FALSE;

7269:   if (!*label && !failNotFound) return(0);
7272:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7273:     if (*label == link->label) {
7274:       hasLabel = PETSC_TRUE;
7275:       *pnext = link->next; /* Remove from list */
7276:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7277:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7278:       DMLabelDestroy(&link->label);
7279:       PetscFree(link);
7280:       break;
7281:     }
7282:   }
7283:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7284:   return(0);
7285: }

7287: /*@C
7288:   DMGetLabelOutput - Get the output flag for a given label

7290:   Not Collective

7292:   Input Parameters:
7293: + dm   - The DM object
7294: - name - The label name

7296:   Output Parameter:
7297: . output - The flag for output

7299:   Level: developer

7301: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7302: @*/
7303: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7304: {
7305:   DMLabelLink    next = dm->labels;
7306:   const char    *lname;

7313:   while (next) {
7314:     PetscBool flg;

7316:     PetscObjectGetName((PetscObject) next->label, &lname);
7317:     PetscStrcmp(name, lname, &flg);
7318:     if (flg) {*output = next->output; return(0);}
7319:     next = next->next;
7320:   }
7321:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7322: }

7324: /*@C
7325:   DMSetLabelOutput - Set the output flag for a given label

7327:   Not Collective

7329:   Input Parameters:
7330: + dm     - The DM object
7331: . name   - The label name
7332: - output - The flag for output

7334:   Level: developer

7336: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7337: @*/
7338: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7339: {
7340:   DMLabelLink    next = dm->labels;
7341:   const char    *lname;

7347:   while (next) {
7348:     PetscBool flg;

7350:     PetscObjectGetName((PetscObject) next->label, &lname);
7351:     PetscStrcmp(name, lname, &flg);
7352:     if (flg) {next->output = output; return(0);}
7353:     next = next->next;
7354:   }
7355:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7356: }

7358: /*@
7359:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

7361:   Collective on dmA

7363:   Input Parameter:
7364: + dmA - The DM object with initial labels
7365: . dmB - The DM object with copied labels
7366: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7367: - all  - Copy all labels including "depth" and "dim" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7369:   Level: intermediate

7371:   Note: This is typically used when interpolating or otherwise adding to a mesh

7373: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7374: @*/
7375: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7376: {
7377:   DMLabel        label, labelNew;
7378:   const char    *name;
7379:   PetscBool      flg;
7380:   DMLabelLink    link;

7388:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7389:   if (dmA == dmB) return(0);
7390:   for (link=dmA->labels; link; link=link->next) {
7391:     label=link->label;
7392:     PetscObjectGetName((PetscObject)label, &name);
7393:     if (!all) {
7394:       PetscStrcmp(name, "depth", &flg);
7395:       if (flg) continue;
7396:       PetscStrcmp(name, "dim", &flg);
7397:       if (flg) continue;
7398:     } else {
7399:       dmB->depthLabel = dmA->depthLabel;
7400:     }
7401:     if (mode==PETSC_COPY_VALUES) {
7402:       DMLabelDuplicate(label, &labelNew);
7403:     } else {
7404:       labelNew = label;
7405:     }
7406:     DMAddLabel(dmB, labelNew);
7407:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7408:   }
7409:   return(0);
7410: }

7412: /*@
7413:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

7415:   Input Parameter:
7416: . dm - The DM object

7418:   Output Parameter:
7419: . cdm - The coarse DM

7421:   Level: intermediate

7423: .seealso: DMSetCoarseDM()
7424: @*/
7425: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7426: {
7430:   *cdm = dm->coarseMesh;
7431:   return(0);
7432: }

7434: /*@
7435:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

7437:   Input Parameters:
7438: + dm - The DM object
7439: - cdm - The coarse DM

7441:   Level: intermediate

7443: .seealso: DMGetCoarseDM()
7444: @*/
7445: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7446: {

7452:   PetscObjectReference((PetscObject)cdm);
7453:   DMDestroy(&dm->coarseMesh);
7454:   dm->coarseMesh = cdm;
7455:   return(0);
7456: }

7458: /*@
7459:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

7461:   Input Parameter:
7462: . dm - The DM object

7464:   Output Parameter:
7465: . fdm - The fine DM

7467:   Level: intermediate

7469: .seealso: DMSetFineDM()
7470: @*/
7471: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7472: {
7476:   *fdm = dm->fineMesh;
7477:   return(0);
7478: }

7480: /*@
7481:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

7483:   Input Parameters:
7484: + dm - The DM object
7485: - fdm - The fine DM

7487:   Level: intermediate

7489: .seealso: DMGetFineDM()
7490: @*/
7491: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7492: {

7498:   PetscObjectReference((PetscObject)fdm);
7499:   DMDestroy(&dm->fineMesh);
7500:   dm->fineMesh = fdm;
7501:   return(0);
7502: }

7504: /*=== DMBoundary code ===*/

7506: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7507: {
7508:   PetscInt       d;

7512:   for (d = 0; d < dm->Nds; ++d) {
7513:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7514:   }
7515:   return(0);
7516: }

7518: /*@C
7519:   DMAddBoundary - Add a boundary condition to the model

7521:   Input Parameters:
7522: + dm          - The DM, with a PetscDS that matches the problem being constrained
7523: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7524: . name        - The BC name
7525: . labelname   - The label defining constrained points
7526: . field       - The field to constrain
7527: . numcomps    - The number of constrained field components (0 will constrain all fields)
7528: . comps       - An array of constrained component numbers
7529: . bcFunc      - A pointwise function giving boundary values
7530: . numids      - The number of DMLabel ids for constrained points
7531: . ids         - An array of ids for constrained points
7532: - ctx         - An optional user context for bcFunc

7534:   Options Database Keys:
7535: + -bc_<boundary name> <num> - Overrides the boundary ids
7536: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7538:   Level: developer

7540: .seealso: DMGetBoundary()
7541: @*/
7542: 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)
7543: {
7544:   PetscDS        ds;

7549:   DMGetDS(dm, &ds);
7550:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, numids, ids, ctx);
7551:   return(0);
7552: }

7554: /*@
7555:   DMGetNumBoundary - Get the number of registered BC

7557:   Input Parameters:
7558: . dm - The mesh object

7560:   Output Parameters:
7561: . numBd - The number of BC

7563:   Level: intermediate

7565: .seealso: DMAddBoundary(), DMGetBoundary()
7566: @*/
7567: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
7568: {
7569:   PetscDS        ds;

7574:   DMGetDS(dm, &ds);
7575:   PetscDSGetNumBoundary(ds, numBd);
7576:   return(0);
7577: }

7579: /*@C
7580:   DMGetBoundary - Get a model boundary condition

7582:   Input Parameters:
7583: + dm          - The mesh object
7584: - bd          - The BC number

7586:   Output Parameters:
7587: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
7588: . name        - The BC name
7589: . labelname   - The label defining constrained points
7590: . field       - The field to constrain
7591: . numcomps    - The number of constrained field components
7592: . comps       - An array of constrained component numbers
7593: . bcFunc      - A pointwise function giving boundary values
7594: . numids      - The number of DMLabel ids for constrained points
7595: . ids         - An array of ids for constrained points
7596: - ctx         - An optional user context for bcFunc

7598:   Options Database Keys:
7599: + -bc_<boundary name> <num> - Overrides the boundary ids
7600: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7602:   Level: developer

7604: .seealso: DMAddBoundary()
7605: @*/
7606: 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)
7607: {
7608:   PetscDS        ds;

7613:   DMGetDS(dm, &ds);
7614:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, numids, ids, ctx);
7615:   return(0);
7616: }

7618: static PetscErrorCode DMPopulateBoundary(DM dm)
7619: {
7620:   PetscDS        ds;
7621:   DMBoundary    *lastnext;
7622:   DSBoundary     dsbound;

7626:   DMGetDS(dm, &ds);
7627:   dsbound = ds->boundary;
7628:   if (dm->boundary) {
7629:     DMBoundary next = dm->boundary;

7631:     /* quick check to see if the PetscDS has changed */
7632:     if (next->dsboundary == dsbound) return(0);
7633:     /* the PetscDS has changed: tear down and rebuild */
7634:     while (next) {
7635:       DMBoundary b = next;

7637:       next = b->next;
7638:       PetscFree(b);
7639:     }
7640:     dm->boundary = NULL;
7641:   }

7643:   lastnext = &(dm->boundary);
7644:   while (dsbound) {
7645:     DMBoundary dmbound;

7647:     PetscNew(&dmbound);
7648:     dmbound->dsboundary = dsbound;
7649:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
7650:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
7651:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7652:     *lastnext = dmbound;
7653:     lastnext = &(dmbound->next);
7654:     dsbound = dsbound->next;
7655:   }
7656:   return(0);
7657: }

7659: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7660: {
7661:   DMBoundary     b;

7667:   *isBd = PETSC_FALSE;
7668:   DMPopulateBoundary(dm);
7669:   b = dm->boundary;
7670:   while (b && !(*isBd)) {
7671:     DMLabel    label = b->label;
7672:     DSBoundary dsb = b->dsboundary;

7674:     if (label) {
7675:       PetscInt i;

7677:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
7678:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
7679:       }
7680:     }
7681:     b = b->next;
7682:   }
7683:   return(0);
7684: }

7686: /*@C
7687:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

7689:   Collective on DM

7691:   Input Parameters:
7692: + dm      - The DM
7693: . time    - The time
7694: . funcs   - The coordinate functions to evaluate, one per field
7695: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7696: - mode    - The insertion mode for values

7698:   Output Parameter:
7699: . X - vector

7701:    Calling sequence of func:
7702: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7704: +  dim - The spatial dimension
7705: .  x   - The coordinates
7706: .  Nf  - The number of fields
7707: .  u   - The output field values
7708: -  ctx - optional user-defined function context

7710:   Level: developer

7712: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7713: @*/
7714: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7715: {
7716:   Vec            localX;

7721:   DMGetLocalVector(dm, &localX);
7722:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7723:   DMLocalToGlobalBegin(dm, localX, mode, X);
7724:   DMLocalToGlobalEnd(dm, localX, mode, X);
7725:   DMRestoreLocalVector(dm, &localX);
7726:   return(0);
7727: }

7729: /*@C
7730:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

7732:   Not collective

7734:   Input Parameters:
7735: + dm      - The DM
7736: . time    - The time
7737: . funcs   - The coordinate functions to evaluate, one per field
7738: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7739: - mode    - The insertion mode for values

7741:   Output Parameter:
7742: . localX - vector

7744:    Calling sequence of func:
7745: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7747: +  dim - The spatial dimension
7748: .  x   - The coordinates
7749: .  Nf  - The number of fields
7750: .  u   - The output field values
7751: -  ctx - optional user-defined function context

7753:   Level: developer

7755: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
7756: @*/
7757: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7758: {

7764:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
7765:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
7766:   return(0);
7767: }

7769: /*@C
7770:   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.

7772:   Collective on DM

7774:   Input Parameters:
7775: + dm      - The DM
7776: . time    - The time
7777: . label   - The DMLabel selecting the portion of the mesh for projection
7778: . funcs   - The coordinate functions to evaluate, one per field
7779: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7780: - mode    - The insertion mode for values

7782:   Output Parameter:
7783: . X - vector

7785:    Calling sequence of func:
7786: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7788: +  dim - The spatial dimension
7789: .  x   - The coordinates
7790: .  Nf  - The number of fields
7791: .  u   - The output field values
7792: -  ctx - optional user-defined function context

7794:   Level: developer

7796: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
7797: @*/
7798: 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)
7799: {
7800:   Vec            localX;

7805:   DMGetLocalVector(dm, &localX);
7806:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7807:   DMLocalToGlobalBegin(dm, localX, mode, X);
7808:   DMLocalToGlobalEnd(dm, localX, mode, X);
7809:   DMRestoreLocalVector(dm, &localX);
7810:   return(0);
7811: }

7813: /*@C
7814:   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.

7816:   Not collective

7818:   Input Parameters:
7819: + dm      - The DM
7820: . time    - The time
7821: . label   - The DMLabel selecting the portion of the mesh for projection
7822: . funcs   - The coordinate functions to evaluate, one per field
7823: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7824: - mode    - The insertion mode for values

7826:   Output Parameter:
7827: . localX - vector

7829:    Calling sequence of func:
7830: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

7832: +  dim - The spatial dimension
7833: .  x   - The coordinates
7834: .  Nf  - The number of fields
7835: .  u   - The output field values
7836: -  ctx - optional user-defined function context

7838:   Level: developer

7840: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
7841: @*/
7842: 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)
7843: {

7849:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
7850:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7851:   return(0);
7852: }

7854: /*@C
7855:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

7857:   Not collective

7859:   Input Parameters:
7860: + dm      - The DM
7861: . time    - The time
7862: . localU  - The input field vector
7863: . funcs   - The functions to evaluate, one per field
7864: - mode    - The insertion mode for values

7866:   Output Parameter:
7867: . localX  - The output vector

7869:    Calling sequence of func:
7870: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7871: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7872: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7873: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7875: +  dim          - The spatial dimension
7876: .  Nf           - The number of input fields
7877: .  NfAux        - The number of input auxiliary fields
7878: .  uOff         - The offset of each field in u[]
7879: .  uOff_x       - The offset of each field in u_x[]
7880: .  u            - The field values at this point in space
7881: .  u_t          - The field time derivative at this point in space (or NULL)
7882: .  u_x          - The field derivatives at this point in space
7883: .  aOff         - The offset of each auxiliary field in u[]
7884: .  aOff_x       - The offset of each auxiliary field in u_x[]
7885: .  a            - The auxiliary field values at this point in space
7886: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7887: .  a_x          - The auxiliary field derivatives at this point in space
7888: .  t            - The current time
7889: .  x            - The coordinates of this point
7890: .  numConstants - The number of constants
7891: .  constants    - The value of each constant
7892: -  f            - The value of the function at this point in space

7894:   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.
7895:   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
7896:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
7897:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7899:   Level: intermediate

7901: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7902: @*/
7903: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
7904:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
7905:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7906:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7907:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7908:                                    InsertMode mode, Vec localX)
7909: {

7916:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7917:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
7918:   return(0);
7919: }

7921: /*@C
7922:   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.

7924:   Not collective

7926:   Input Parameters:
7927: + dm      - The DM
7928: . time    - The time
7929: . label   - The DMLabel marking the portion of the domain to output
7930: . numIds  - The number of label ids to use
7931: . ids     - The label ids to use for marking
7932: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
7933: . comps   - The components to set in the output, or NULL for all components
7934: . localU  - The input field vector
7935: . funcs   - The functions to evaluate, one per field
7936: - mode    - The insertion mode for values

7938:   Output Parameter:
7939: . localX  - The output vector

7941:    Calling sequence of func:
7942: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7943: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7944: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7945: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7947: +  dim          - The spatial dimension
7948: .  Nf           - The number of input fields
7949: .  NfAux        - The number of input auxiliary fields
7950: .  uOff         - The offset of each field in u[]
7951: .  uOff_x       - The offset of each field in u_x[]
7952: .  u            - The field values at this point in space
7953: .  u_t          - The field time derivative at this point in space (or NULL)
7954: .  u_x          - The field derivatives at this point in space
7955: .  aOff         - The offset of each auxiliary field in u[]
7956: .  aOff_x       - The offset of each auxiliary field in u_x[]
7957: .  a            - The auxiliary field values at this point in space
7958: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7959: .  a_x          - The auxiliary field derivatives at this point in space
7960: .  t            - The current time
7961: .  x            - The coordinates of this point
7962: .  numConstants - The number of constants
7963: .  constants    - The value of each constant
7964: -  f            - The value of the function at this point in space

7966:   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.
7967:   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
7968:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
7969:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7971:   Level: intermediate

7973: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
7974: @*/
7975: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
7976:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
7977:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7978:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
7979:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
7980:                                         InsertMode mode, Vec localX)
7981: {

7988:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
7989:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
7990:   return(0);
7991: }

7993: /*@C
7994:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

7996:   Input Parameters:
7997: + dm    - The DM
7998: . time  - The time
7999: . funcs - The functions to evaluate for each field component
8000: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8001: - X     - The coefficient vector u_h, a global vector

8003:   Output Parameter:
8004: . diff - The diff ||u - u_h||_2

8006:   Level: developer

8008: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8009: @*/
8010: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8011: {

8017:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8018:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8019:   return(0);
8020: }

8022: /*@C
8023:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8025:   Collective on dm

8027:   Input Parameters:
8028: + dm    - The DM
8029: , time  - The time
8030: . funcs - The gradient functions to evaluate for each field component
8031: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8032: . X     - The coefficient vector u_h, a global vector
8033: - n     - The vector to project along

8035:   Output Parameter:
8036: . diff - The diff ||(grad u - grad u_h) . n||_2

8038:   Level: developer

8040: .seealso: DMProjectFunction(), DMComputeL2Diff()
8041: @*/
8042: 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)
8043: {

8049:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8050:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8051:   return(0);
8052: }

8054: /*@C
8055:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8057:   Collective on dm

8059:   Input Parameters:
8060: + dm    - The DM
8061: . time  - The time
8062: . funcs - The functions to evaluate for each field component
8063: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8064: - X     - The coefficient vector u_h, a global vector

8066:   Output Parameter:
8067: . diff - The array of differences, ||u^f - u^f_h||_2

8069:   Level: developer

8071: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8072: @*/
8073: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8074: {

8080:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8081:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8082:   return(0);
8083: }

8085: /*@C
8086:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8087:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

8089:   Collective on dm

8091:   Input parameters:
8092: + dm - the pre-adaptation DM object
8093: - label - label with the flags

8095:   Output parameters:
8096: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

8098:   Level: intermediate

8100: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8101: @*/
8102: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8103: {

8110:   *dmAdapt = NULL;
8111:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8112:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8113:   return(0);
8114: }

8116: /*@C
8117:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

8119:   Input Parameters:
8120: + dm - The DM object
8121: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8122: - 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_".

8124:   Output Parameter:
8125: . dmAdapt  - Pointer to the DM object containing the adapted mesh

8127:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

8129:   Level: advanced

8131: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8132: @*/
8133: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8134: {

8142:   *dmAdapt = NULL;
8143:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8144:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8145:   return(0);
8146: }

8148: /*@C
8149:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

8151:  Not Collective

8153:  Input Parameter:
8154:  . dm    - The DM

8156:  Output Parameter:
8157:  . nranks - the number of neighbours
8158:  . ranks - the neighbors ranks

8160:  Notes:
8161:  Do not free the array, it is freed when the DM is destroyed.

8163:  Level: beginner

8165:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8166: @*/
8167: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8168: {

8173:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8174:   (dm->ops->getneighbors)(dm,nranks,ranks);
8175:   return(0);
8176: }

8178: #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */

8180: /*
8181:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8182:     This has be a different function because it requires DM which is not defined in the Mat library
8183: */
8184: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8185: {

8189:   if (coloring->ctype == IS_COLORING_LOCAL) {
8190:     Vec x1local;
8191:     DM  dm;
8192:     MatGetDM(J,&dm);
8193:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8194:     DMGetLocalVector(dm,&x1local);
8195:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8196:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8197:     x1   = x1local;
8198:   }
8199:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8200:   if (coloring->ctype == IS_COLORING_LOCAL) {
8201:     DM  dm;
8202:     MatGetDM(J,&dm);
8203:     DMRestoreLocalVector(dm,&x1);
8204:   }
8205:   return(0);
8206: }

8208: /*@
8209:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

8211:     Input Parameter:
8212: .    coloring - the MatFDColoring object

8214:     Developer Notes:
8215:     this routine exists because the PETSc Mat library does not know about the DM objects

8217:     Level: advanced

8219: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8220: @*/
8221: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8222: {
8224:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8225:   return(0);
8226: }

8228: /*@
8229:     DMGetCompatibility - determine if two DMs are compatible

8231:     Collective

8233:     Input Parameters:
8234: +    dm - the first DM
8235: -    dm2 - the second DM

8237:     Output Parameters:
8238: +    compatible - whether or not the two DMs are compatible
8239: -    set - whether or not the compatible value was set

8241:     Notes:
8242:     Two DMs are deemed compatible if they represent the same parallel decomposition
8243:     of the same topology. This implies that the section (field data) on one
8244:     "makes sense" with respect to the topology and parallel decomposition of the other.
8245:     Loosely speaking, compatible DMs represent the same domain and parallel
8246:     decomposition, but hold different data.

8248:     Typically, one would confirm compatibility if intending to simultaneously iterate
8249:     over a pair of vectors obtained from different DMs.

8251:     For example, two DMDA objects are compatible if they have the same local
8252:     and global sizes and the same stencil width. They can have different numbers
8253:     of degrees of freedom per node. Thus, one could use the node numbering from
8254:     either DM in bounds for a loop over vectors derived from either DM.

8256:     Consider the operation of summing data living on a 2-dof DMDA to data living
8257:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8258: .vb
8259:   ...
8260:   DMGetCompatibility(da1,da2,&compatible,&set);
8261:   if (set && compatible)  {
8262:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8263:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8264:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8265:     for (j=y; j<y+n; ++j) {
8266:       for (i=x; i<x+m, ++i) {
8267:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8268:       }
8269:     }
8270:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8271:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8272:   } else {
8273:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8274:   }
8275:   ...
8276: .ve

8278:     Checking compatibility might be expensive for a given implementation of DM,
8279:     or might be impossible to unambiguously confirm or deny. For this reason,
8280:     this function may decline to determine compatibility, and hence users should
8281:     always check the "set" output parameter.

8283:     A DM is always compatible with itself.

8285:     In the current implementation, DMs which live on "unequal" communicators
8286:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8287:     incompatible.

8289:     This function is labeled "Collective," as information about all subdomains
8290:     is required on each rank. However, in DM implementations which store all this
8291:     information locally, this function may be merely "Logically Collective".

8293:     Developer Notes:
8294:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8295:     iff B is compatible with A. Thus, this function checks the implementations
8296:     of both dm and dm2 (if they are of different types), attempting to determine
8297:     compatibility. It is left to DM implementers to ensure that symmetry is
8298:     preserved. The simplest way to do this is, when implementing type-specific
8299:     logic for this function, is to check for existing logic in the implementation
8300:     of other DM types and let *set = PETSC_FALSE if found.

8302:     Level: advanced

8304: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8305: @*/

8307: PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
8308: {
8310:   PetscMPIInt    compareResult;
8311:   DMType         type,type2;
8312:   PetscBool      sameType;


8318:   /* Declare a DM compatible with itself */
8319:   if (dm == dm2) {
8320:     *set = PETSC_TRUE;
8321:     *compatible = PETSC_TRUE;
8322:     return(0);
8323:   }

8325:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8326:      communicator. Note that this does not preclude compatibility with
8327:      DMs living on "congruent" or "similar" communicators, but this must be
8328:      determined by the implementation-specific logic */
8329:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);
8330:   if (compareResult == MPI_UNEQUAL) {
8331:     *set = PETSC_TRUE;
8332:     *compatible = PETSC_FALSE;
8333:     return(0);
8334:   }

8336:   /* Pass to the implementation-specific routine, if one exists. */
8337:   if (dm->ops->getcompatibility) {
8338:     (*dm->ops->getcompatibility)(dm,dm2,compatible,set);
8339:     if (*set) return(0);
8340:   }

8342:   /* If dm and dm2 are of different types, then attempt to check compatibility
8343:      with an implementation of this function from dm2 */
8344:   DMGetType(dm,&type);
8345:   DMGetType(dm2,&type2);
8346:   PetscStrcmp(type,type2,&sameType);
8347:   if (!sameType && dm2->ops->getcompatibility) {
8348:     (*dm2->ops->getcompatibility)(dm2,dm,compatible,set); /* Note argument order */
8349:   } else {
8350:     *set = PETSC_FALSE;
8351:   }
8352:   return(0);
8353: }

8355: /*@C
8356:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

8358:   Logically Collective on DM

8360:   Input Parameters:
8361: + DM - the DM
8362: . f - the monitor function
8363: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8364: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

8366:   Options Database Keys:
8367: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8368:                             does not cancel those set via the options database.

8370:   Notes:
8371:   Several different monitoring routines may be set by calling
8372:   DMMonitorSet() multiple times; all will be called in the
8373:   order in which they were set.

8375:   Fortran Notes:
8376:   Only a single monitor function can be set for each DM object

8378:   Level: intermediate

8380: .seealso: DMMonitorCancel()
8381: @*/
8382: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8383: {
8384:   PetscInt       m;

8389:   for (m = 0; m < dm->numbermonitors; ++m) {
8390:     PetscBool identical;

8392:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8393:     if (identical) return(0);
8394:   }
8395:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8396:   dm->monitor[dm->numbermonitors]          = f;
8397:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8398:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8399:   return(0);
8400: }

8402: /*@
8403:   DMMonitorCancel - Clears all the monitor functions for a DM object.

8405:   Logically Collective on DM

8407:   Input Parameter:
8408: . dm - the DM

8410:   Options Database Key:
8411: . -dm_monitor_cancel - cancels all monitors that have been hardwired
8412:   into a code by calls to DMonitorSet(), but does not cancel those
8413:   set via the options database

8415:   Notes:
8416:   There is no way to clear one specific monitor from a DM object.

8418:   Level: intermediate

8420: .seealso: DMMonitorSet()
8421: @*/
8422: PetscErrorCode DMMonitorCancel(DM dm)
8423: {
8425:   PetscInt       m;

8429:   for (m = 0; m < dm->numbermonitors; ++m) {
8430:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
8431:   }
8432:   dm->numbermonitors = 0;
8433:   return(0);
8434: }

8436: /*@C
8437:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

8439:   Collective on DM

8441:   Input Parameters:
8442: + dm   - DM object you wish to monitor
8443: . name - the monitor type one is seeking
8444: . help - message indicating what monitoring is done
8445: . manual - manual page for the monitor
8446: . monitor - the monitor function
8447: - 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

8449:   Output Parameter:
8450: . flg - Flag set if the monitor was created

8452:   Level: developer

8454: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
8455:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
8456:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
8457:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
8458:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
8459:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
8460:           PetscOptionsFList(), PetscOptionsEList()
8461: @*/
8462: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8463: {
8464:   PetscViewer       viewer;
8465:   PetscViewerFormat format;
8466:   PetscErrorCode    ierr;

8470:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
8471:   if (*flg) {
8472:     PetscViewerAndFormat *vf;

8474:     PetscViewerAndFormatCreate(viewer, format, &vf);
8475:     PetscObjectDereference((PetscObject) viewer);
8476:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
8477:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
8478:   }
8479:   return(0);
8480: }

8482: /*@
8483:    DMMonitor - runs the user provided monitor routines, if they exist

8485:    Collective on DM

8487:    Input Parameters:
8488: .  dm - The DM

8490:    Level: developer

8492: .seealso: DMMonitorSet()
8493: @*/
8494: PetscErrorCode DMMonitor(DM dm)
8495: {
8496:   PetscInt       m;

8500:   if (!dm) return(0);
8502:   for (m = 0; m < dm->numbermonitors; ++m) {
8503:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8504:   }
8505:   return(0);
8506: }