Actual source code: dm.c

petsc-3.10.0 2018-09-12
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: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction;

 12: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_",0};

 14: static PetscErrorCode DMHasCreateInjection_Default(DM dm, PetscBool *flg)
 15: {
 19:   *flg = PETSC_FALSE;
 20:   return(0);
 21: }

 23: /*@
 24:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

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

 29:   Collective on MPI_Comm

 31:   Input Parameter:
 32: . comm - The communicator for the DM object

 34:   Output Parameter:
 35: . dm - The DM object

 37:   Level: beginner

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

 48:   *dm = NULL;
 49:   PetscSysInitializePackage();
 50:   VecInitializePackage();
 51:   MatInitializePackage();
 52:   DMInitializePackage();

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

 56:   v->ltogmap                  = NULL;
 57:   v->bs                       = 1;
 58:   v->coloringtype             = IS_COLORING_GLOBAL;
 59:   PetscSFCreate(comm, &v->sf);
 60:   PetscSFCreate(comm, &v->defaultSF);
 61:   v->labels                   = NULL;
 62:   v->depthLabel               = NULL;
 63:   v->defaultSection           = NULL;
 64:   v->defaultGlobalSection     = NULL;
 65:   v->defaultConstraintSection = NULL;
 66:   v->defaultConstraintMat     = NULL;
 67:   v->L                        = NULL;
 68:   v->maxCell                  = NULL;
 69:   v->bdtype                   = NULL;
 70:   v->dimEmbed                 = PETSC_DEFAULT;
 71:   v->dim                      = PETSC_DETERMINE;
 72:   {
 73:     PetscInt i;
 74:     for (i = 0; i < 10; ++i) {
 75:       v->nullspaceConstructors[i] = NULL;
 76:     }
 77:   }
 78:   PetscDSCreate(comm, &v->prob);
 79:   v->dmBC = NULL;
 80:   v->coarseMesh = NULL;
 81:   v->outputSequenceNum = -1;
 82:   v->outputSequenceVal = 0.0;
 83:   DMSetVecType(v,VECSTANDARD);
 84:   DMSetMatType(v,MATAIJ);
 85:   PetscNew(&(v->labels));
 86:   v->labels->refct = 1;

 88:   v->ops->hascreateinjection = DMHasCreateInjection_Default;

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

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

 97:   Collective on MPI_Comm

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

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

105:   Level: beginner

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

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

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

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

172:    Logically Collective on DM

174:    Input Parameter:
175: +  da - initial distributed array
176: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

178:    Options Database:
179: .   -dm_vec_type ctype

181:    Level: intermediate

183: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType()
184: @*/
185: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
186: {

191:   PetscFree(da->vectype);
192:   PetscStrallocpy(ctype,(char**)&da->vectype);
193:   return(0);
194: }

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

199:    Logically Collective on DM

201:    Input Parameter:
202: .  da - initial distributed array

204:    Output Parameter:
205: .  ctype - the vector type

207:    Level: intermediate

209: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType
210: @*/
211: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
212: {
215:   *ctype = da->vectype;
216:   return(0);
217: }

219: /*@
220:   VecGetDM - Gets the DM defining the data layout of the vector

222:   Not collective

224:   Input Parameter:
225: . v - The Vec

227:   Output Parameter:
228: . dm - The DM

230:   Level: intermediate

232: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
233: @*/
234: PetscErrorCode VecGetDM(Vec v, DM *dm)
235: {

241:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
242:   return(0);
243: }

245: /*@
246:   VecSetDM - Sets the DM defining the data layout of the vector.

248:   Not collective

250:   Input Parameters:
251: + v - The Vec
252: - dm - The DM

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

256:   Level: intermediate

258: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
259: @*/
260: PetscErrorCode VecSetDM(Vec v, DM dm)
261: {

267:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
268:   return(0);
269: }

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

274:    Logically Collective on DM

276:    Input Parameters:
277: +  dm - the DM context
278: -  ctype - the matrix type

280:    Options Database:
281: .   -dm_is_coloring_type - global or local

283:    Level: intermediate

285: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
286:           DMGetISColoringType()
287: @*/
288: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
289: {
292:   dm->coloringtype = ctype;
293:   return(0);
294: }

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

299:    Logically Collective on DM

301:    Input Parameter:
302: .  dm - the DM context

304:    Output Parameter:
305: .  ctype - the matrix type

307:    Options Database:
308: .   -dm_is_coloring_type - global or local

310:    Level: intermediate

312: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
313:           DMGetISColoringType()
314: @*/
315: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
316: {
319:   *ctype = dm->coloringtype;
320:   return(0);
321: }

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

326:    Logically Collective on DM

328:    Input Parameters:
329: +  dm - the DM context
330: -  ctype - the matrix type

332:    Options Database:
333: .   -dm_mat_type ctype

335:    Level: intermediate

337: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
338: @*/
339: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
340: {

345:   PetscFree(dm->mattype);
346:   PetscStrallocpy(ctype,(char**)&dm->mattype);
347:   return(0);
348: }

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

353:    Logically Collective on DM

355:    Input Parameter:
356: .  dm - the DM context

358:    Output Parameter:
359: .  ctype - the matrix type

361:    Options Database:
362: .   -dm_mat_type ctype

364:    Level: intermediate

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

376: /*@
377:   MatGetDM - Gets the DM defining the data layout of the matrix

379:   Not collective

381:   Input Parameter:
382: . A - The Mat

384:   Output Parameter:
385: . dm - The DM

387:   Level: intermediate

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

392: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
393: @*/
394: PetscErrorCode MatGetDM(Mat A, DM *dm)
395: {

401:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
402:   return(0);
403: }

405: /*@
406:   MatSetDM - Sets the DM defining the data layout of the matrix

408:   Not collective

410:   Input Parameters:
411: + A - The Mat
412: - dm - The DM

414:   Level: intermediate

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


420: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
421: @*/
422: PetscErrorCode MatSetDM(Mat A, DM dm)
423: {

429:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
430:   return(0);
431: }

433: /*@C
434:    DMSetOptionsPrefix - Sets the prefix used for searching for all
435:    DM options in the database.

437:    Logically Collective on DM

439:    Input Parameter:
440: +  da - the DM context
441: -  prefix - the prefix to prepend to all option names

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

447:    Level: advanced

449: .keywords: DM, set, options, prefix, database

451: .seealso: DMSetFromOptions()
452: @*/
453: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
454: {

459:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
460:   if (dm->sf) {
461:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
462:   }
463:   if (dm->defaultSF) {
464:     PetscObjectSetOptionsPrefix((PetscObject)dm->defaultSF,prefix);
465:   }
466:   return(0);
467: }

469: /*@C
470:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
471:    DM options in the database.

473:    Logically Collective on DM

475:    Input Parameters:
476: +  dm - the DM context
477: -  prefix - the prefix string to prepend to all DM option requests

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

483:    Level: advanced

485: .keywords: DM, append, options, prefix, database

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

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

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

503:    Not Collective

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

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

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

515:    Level: advanced

517: .keywords: DM, set, options, prefix, database

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

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

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

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

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

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

573: PetscErrorCode DMDestroyLabelLinkList(DM dm)
574: {

578:   if (!--(dm->labels->refct)) {
579:     DMLabelLink next = dm->labels->next;

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

585:       DMLabelDestroy(&next->label);
586:       PetscFree(next);
587:       next = tmp;
588:     }
589:     PetscFree(dm->labels);
590:   }
591:   return(0);
592: }

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

597:     Collective on DM

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

602:     Level: developer

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

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

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

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

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

706:     /* destroy the labels */
707:     while (next) {
708:       DMLabelLink tmp = next->next;

710:       DMLabelDestroy(&next->label);
711:       PetscFree(next);
712:       next = tmp;
713:     }
714:     PetscFree((*dm)->labels);
715:   }
716:   {
717:     DMBoundary next = (*dm)->boundary;
718:     while (next) {
719:       DMBoundary b = next;

721:       next = b->next;
722:       PetscFree(b);
723:     }
724:   }

726:   PetscObjectDestroy(&(*dm)->dmksp);
727:   PetscObjectDestroy(&(*dm)->dmsnes);
728:   PetscObjectDestroy(&(*dm)->dmts);

730:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
731:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
732:   }
733:   VecDestroy(&(*dm)->x);
734:   MatFDColoringDestroy(&(*dm)->fd);
735:   DMClearGlobalVectors(*dm);
736:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
737:   PetscFree((*dm)->vectype);
738:   PetscFree((*dm)->mattype);

740:   PetscSectionDestroy(&(*dm)->defaultSection);
741:   PetscSectionDestroy(&(*dm)->defaultGlobalSection);
742:   PetscLayoutDestroy(&(*dm)->map);
743:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
744:   MatDestroy(&(*dm)->defaultConstraintMat);
745:   PetscSFDestroy(&(*dm)->sf);
746:   PetscSFDestroy(&(*dm)->defaultSF);
747:   if ((*dm)->useNatural) {
748:     if ((*dm)->sfNatural) {
749:       PetscSFDestroy(&(*dm)->sfNatural);
750:     }
751:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
752:   }
753:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
754:     DMSetFineDM((*dm)->coarseMesh,NULL);
755:   }
756:   DMDestroy(&(*dm)->coarseMesh);
757:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
758:     DMSetCoarseDM((*dm)->fineMesh,NULL);
759:   }
760:   DMDestroy(&(*dm)->fineMesh);
761:   DMFieldDestroy(&(*dm)->coordinateField);
762:   DMDestroy(&(*dm)->coordinateDM);
763:   VecDestroy(&(*dm)->coordinates);
764:   VecDestroy(&(*dm)->coordinatesLocal);
765:   PetscFree3((*dm)->L,(*dm)->maxCell,(*dm)->bdtype);

767:   PetscDSDestroy(&(*dm)->prob);
768:   DMDestroy(&(*dm)->dmBC);
769:   /* if memory was published with SAWs then destroy it */
770:   PetscObjectSAWsViewOff((PetscObject)*dm);

772:   if ((*dm)->ops->destroy) {
773:     (*(*dm)->ops->destroy)(*dm);
774:   }
775:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
776:   PetscHeaderDestroy(dm);
777:   return(0);
778: }

780: /*@
781:     DMSetUp - sets up the data structures inside a DM object

783:     Collective on DM

785:     Input Parameter:
786: .   dm - the DM object to setup

788:     Level: developer

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

792: @*/
793: PetscErrorCode  DMSetUp(DM dm)
794: {

799:   if (dm->setupcalled) return(0);
800:   if (dm->ops->setup) {
801:     (*dm->ops->setup)(dm);
802:   }
803:   dm->setupcalled = PETSC_TRUE;
804:   return(0);
805: }

807: /*@
808:     DMSetFromOptions - sets parameters in a DM from the options database

810:     Collective on DM

812:     Input Parameter:
813: .   dm - the DM object to set options for

815:     Options Database:
816: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
817: .   -dm_vec_type <type>  - type of vector to create inside DM
818: .   -dm_mat_type <type>  - type of matrix to create inside DM
819: -   -dm_is_coloring_type - <global or local>

821:     Level: developer

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

825: @*/
826: PetscErrorCode  DMSetFromOptions(DM dm)
827: {
828:   char           typeName[256];
829:   PetscBool      flg;

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

863: /*@C
864:     DMView - Views a DM

866:     Collective on DM

868:     Input Parameter:
869: +   dm - the DM object to view
870: -   v - the viewer

872:     Level: beginner

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

876: @*/
877: PetscErrorCode  DMView(DM dm,PetscViewer v)
878: {
879:   PetscErrorCode    ierr;
880:   PetscBool         isbinary;
881:   PetscMPIInt       size;
882:   PetscViewerFormat format;

886:   if (!v) {
887:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
888:   }
889:   PetscViewerGetFormat(v,&format);
890:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
891:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
892:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
893:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
894:   if (isbinary) {
895:     PetscInt classid = DM_FILE_CLASSID;
896:     char     type[256];

898:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);
899:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
900:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);
901:   }
902:   if (dm->ops->view) {
903:     (*dm->ops->view)(dm,v);
904:   }
905:   return(0);
906: }

908: /*@
909:     DMCreateGlobalVector - Creates a global vector from a DM object

911:     Collective on DM

913:     Input Parameter:
914: .   dm - the DM object

916:     Output Parameter:
917: .   vec - the global vector

919:     Level: beginner

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

923: @*/
924: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
925: {

930:   (*dm->ops->createglobalvector)(dm,vec);
931:   return(0);
932: }

934: /*@
935:     DMCreateLocalVector - Creates a local vector from a DM object

937:     Not Collective

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

942:     Output Parameter:
943: .   vec - the local vector

945:     Level: beginner

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

949: @*/
950: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
951: {

956:   (*dm->ops->createlocalvector)(dm,vec);
957:   return(0);
958: }

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

963:    Collective on DM

965:    Input Parameter:
966: .  dm - the DM that provides the mapping

968:    Output Parameter:
969: .  ltog - the mapping

971:    Level: intermediate

973:    Notes:
974:    This mapping can then be used by VecSetLocalToGlobalMapping() or
975:    MatSetLocalToGlobalMapping().

977: .seealso: DMCreateLocalVector()
978: @*/
979: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
980: {
981:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

987:   if (!dm->ltogmap) {
988:     PetscSection section, sectionGlobal;

990:     DMGetSection(dm, &section);
991:     if (section) {
992:       const PetscInt *cdofs;
993:       PetscInt       *ltog;
994:       PetscInt        pStart, pEnd, n, p, k, l;

996:       DMGetGlobalSection(dm, &sectionGlobal);
997:       PetscSectionGetChart(section, &pStart, &pEnd);
998:       PetscSectionGetStorageSize(section, &n);
999:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1000:       for (p = pStart, l = 0; p < pEnd; ++p) {
1001:         PetscInt bdof, cdof, dof, off, c, cind = 0;

1003:         /* Should probably use constrained dofs */
1004:         PetscSectionGetDof(section, p, &dof);
1005:         PetscSectionGetConstraintDof(section, p, &cdof);
1006:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1007:         PetscSectionGetOffset(sectionGlobal, p, &off);
1008:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1009:         bdof = cdof && (dof-cdof) ? 1 : dof;
1010:         if (dof) {
1011:           if (bs < 0)          {bs = bdof;}
1012:           else if (bs != bdof) {bs = 1;}
1013:         }
1014:         for (c = 0; c < dof; ++c, ++l) {
1015:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
1016:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
1017:         }
1018:       }
1019:       /* Must have same blocksize on all procs (some might have no points) */
1020:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1021:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1022:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1023:       else                            {bs = bsMinMax[0];}
1024:       bs = bs < 0 ? 1 : bs;
1025:       /* Must reduce indices by blocksize */
1026:       if (bs > 1) {
1027:         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
1028:         n /= bs;
1029:       }
1030:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1031:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1032:     } else {
1033:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
1034:       (*dm->ops->getlocaltoglobalmapping)(dm);
1035:     }
1036:   }
1037:   *ltog = dm->ltogmap;
1038:   return(0);
1039: }

1041: /*@
1042:    DMGetBlockSize - Gets the inherent block size associated with a DM

1044:    Not Collective

1046:    Input Parameter:
1047: .  dm - the DM with block structure

1049:    Output Parameter:
1050: .  bs - the block size, 1 implies no exploitable block structure

1052:    Level: intermediate

1054: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1055: @*/
1056: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1057: {
1061:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
1062:   *bs = dm->bs;
1063:   return(0);
1064: }

1066: /*@
1067:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1069:     Collective on DM

1071:     Input Parameter:
1072: +   dm1 - the DM object
1073: -   dm2 - the second, finer DM object

1075:     Output Parameter:
1076: +  mat - the interpolation
1077: -  vec - the scaling (optional)

1079:     Level: developer

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

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


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

1091: @*/
1092: PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
1093: {

1099:   PetscLogEventBegin(DM_CreateInterpolation,dm1,dm2,0,0);
1100:   (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);
1101:   PetscLogEventEnd(DM_CreateInterpolation,dm1,dm2,0,0);
1102:   return(0);
1103: }

1105: /*@
1106:     DMCreateRestriction - Gets restriction matrix between two DM objects

1108:     Collective on DM

1110:     Input Parameter:
1111: +   dm1 - the DM object
1112: -   dm2 - the second, finer DM object

1114:     Output Parameter:
1115: .  mat - the restriction


1118:     Level: developer

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


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

1127: @*/
1128: PetscErrorCode  DMCreateRestriction(DM dm1,DM dm2,Mat *mat)
1129: {

1135:   PetscLogEventBegin(DM_CreateRestriction,dm1,dm2,0,0);
1136:   if (!dm1->ops->createrestriction) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateRestriction not implemented for this type");
1137:   (*dm1->ops->createrestriction)(dm1,dm2,mat);
1138:   PetscLogEventEnd(DM_CreateRestriction,dm1,dm2,0,0);
1139:   return(0);
1140: }

1142: /*@
1143:     DMCreateInjection - Gets injection matrix between two DM objects

1145:     Collective on DM

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

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

1154:     Level: developer

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

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

1162: @*/
1163: PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,Mat *mat)
1164: {

1170:   if (!dm1->ops->getinjection) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateInjection not implemented for this type");
1171:   (*dm1->ops->getinjection)(dm1,dm2,mat);
1172:   return(0);
1173: }

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

1178:   Collective on DM

1180:   Input Parameter:
1181: + dm1 - the DM object
1182: - dm2 - the second, finer DM object

1184:   Output Parameter:
1185: . mat - the interpolation

1187:   Level: developer

1189: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1190: @*/
1191: PetscErrorCode DMCreateMassMatrix(DM dm1, DM dm2, Mat *mat)
1192: {

1198:   (*dm1->ops->createmassmatrix)(dm1, dm2, mat);
1199:   return(0);
1200: }

1202: /*@
1203:     DMCreateColoring - Gets coloring for a DM

1205:     Collective on DM

1207:     Input Parameter:
1208: +   dm - the DM object
1209: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1211:     Output Parameter:
1212: .   coloring - the coloring

1214:     Level: developer

1216: .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType()

1218: @*/
1219: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1220: {

1225:   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
1226:   (*dm->ops->getcoloring)(dm,ctype,coloring);
1227:   return(0);
1228: }

1230: /*@
1231:     DMCreateMatrix - Gets empty Jacobian for a DM

1233:     Collective on DM

1235:     Input Parameter:
1236: .   dm - the DM object

1238:     Output Parameter:
1239: .   mat - the empty Jacobian

1241:     Level: beginner

1243:     Notes:
1244:     This properly preallocates the number of nonzeros in the sparse matrix so you
1245:        do not need to do it yourself.

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

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

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

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

1258: @*/
1259: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1260: {

1265:   MatInitializePackage();
1268:   (*dm->ops->creatematrix)(dm,mat);
1269:   return(0);
1270: }

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

1276:   Logically Collective on DM

1278:   Input Parameter:
1279: + dm - the DM
1280: - only - PETSC_TRUE if only want preallocation

1282:   Level: developer
1283: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1284: @*/
1285: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1286: {
1289:   dm->prealloc_only = only;
1290:   return(0);
1291: }

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

1297:   Logically Collective on DM

1299:   Input Parameter:
1300: + dm - the DM
1301: - only - PETSC_TRUE if only want matrix stucture

1303:   Level: developer
1304: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1305: @*/
1306: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1307: {
1310:   dm->structure_only = only;
1311:   return(0);
1312: }

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

1317:   Not Collective

1319:   Input Parameters:
1320: + dm - the DM object
1321: . count - The minium size
1322: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1324:   Output Parameter:
1325: . array - the work array

1327:   Level: developer

1329: .seealso DMDestroy(), DMCreate()
1330: @*/
1331: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1332: {
1334:   DMWorkLink     link;
1335:   PetscMPIInt    dsize;

1340:   if (dm->workin) {
1341:     link       = dm->workin;
1342:     dm->workin = dm->workin->next;
1343:   } else {
1344:     PetscNewLog(dm,&link);
1345:   }
1346:   MPI_Type_size(dtype,&dsize);
1347:   if (((size_t)dsize*count) > link->bytes) {
1348:     PetscFree(link->mem);
1349:     PetscMalloc(dsize*count,&link->mem);
1350:     link->bytes = dsize*count;
1351:   }
1352:   link->next   = dm->workout;
1353:   dm->workout  = link;
1354:   *(void**)mem = link->mem;
1355:   return(0);
1356: }

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

1361:   Not Collective

1363:   Input Parameters:
1364: + dm - the DM object
1365: . count - The minium size
1366: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1368:   Output Parameter:
1369: . array - the work array

1371:   Level: developer

1373:   Developer Notes:
1374:     count and dtype are ignored, they are only needed for DMGetWorkArray()
1375: .seealso DMDestroy(), DMCreate()
1376: @*/
1377: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1378: {
1379:   DMWorkLink *p,link;

1384:   for (p=&dm->workout; (link=*p); p=&link->next) {
1385:     if (link->mem == *(void**)mem) {
1386:       *p           = link->next;
1387:       link->next   = dm->workin;
1388:       dm->workin   = link;
1389:       *(void**)mem = NULL;
1390:       return(0);
1391:     }
1392:   }
1393:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1394: }

1396: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1397: {
1400:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1401:   dm->nullspaceConstructors[field] = nullsp;
1402:   return(0);
1403: }

1405: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1406: {
1409:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1410:   *nullsp = dm->nullspaceConstructors[field];
1411:   return(0);
1412: }

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

1417:   Not collective

1419:   Input Parameter:
1420: . dm - the DM object

1422:   Output Parameters:
1423: + numFields  - The number of fields (or NULL if not requested)
1424: . fieldNames - The name for each field (or NULL if not requested)
1425: - fields     - The global indices for each field (or NULL if not requested)

1427:   Level: intermediate

1429:   Notes:
1430:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1431:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1432:   PetscFree().

1434: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1435: @*/
1436: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1437: {
1438:   PetscSection   section, sectionGlobal;

1443:   if (numFields) {
1445:     *numFields = 0;
1446:   }
1447:   if (fieldNames) {
1449:     *fieldNames = NULL;
1450:   }
1451:   if (fields) {
1453:     *fields = NULL;
1454:   }
1455:   DMGetSection(dm, &section);
1456:   if (section) {
1457:     PetscInt *fieldSizes, **fieldIndices;
1458:     PetscInt nF, f, pStart, pEnd, p;

1460:     DMGetGlobalSection(dm, &sectionGlobal);
1461:     PetscSectionGetNumFields(section, &nF);
1462:     PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);
1463:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1464:     for (f = 0; f < nF; ++f) {
1465:       fieldSizes[f] = 0;
1466:     }
1467:     for (p = pStart; p < pEnd; ++p) {
1468:       PetscInt gdof;

1470:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1471:       if (gdof > 0) {
1472:         for (f = 0; f < nF; ++f) {
1473:           PetscInt fdof, fcdof;

1475:           PetscSectionGetFieldDof(section, p, f, &fdof);
1476:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1477:           fieldSizes[f] += fdof-fcdof;
1478:         }
1479:       }
1480:     }
1481:     for (f = 0; f < nF; ++f) {
1482:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1483:       fieldSizes[f] = 0;
1484:     }
1485:     for (p = pStart; p < pEnd; ++p) {
1486:       PetscInt gdof, goff;

1488:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1489:       if (gdof > 0) {
1490:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1491:         for (f = 0; f < nF; ++f) {
1492:           PetscInt fdof, fcdof, fc;

1494:           PetscSectionGetFieldDof(section, p, f, &fdof);
1495:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1496:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1497:             fieldIndices[f][fieldSizes[f]] = goff++;
1498:           }
1499:         }
1500:       }
1501:     }
1502:     if (numFields) *numFields = nF;
1503:     if (fieldNames) {
1504:       PetscMalloc1(nF, fieldNames);
1505:       for (f = 0; f < nF; ++f) {
1506:         const char *fieldName;

1508:         PetscSectionGetFieldName(section, f, &fieldName);
1509:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1510:       }
1511:     }
1512:     if (fields) {
1513:       PetscMalloc1(nF, fields);
1514:       for (f = 0; f < nF; ++f) {
1515:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1516:       }
1517:     }
1518:     PetscFree2(fieldSizes,fieldIndices);
1519:   } else if (dm->ops->createfieldis) {
1520:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1521:   }
1522:   return(0);
1523: }


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

1532:   Not collective

1534:   Input Parameter:
1535: . dm - the DM object

1537:   Output Parameters:
1538: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1539: . namelist  - The name for each field (or NULL if not requested)
1540: . islist    - The global indices for each field (or NULL if not requested)
1541: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1543:   Level: intermediate

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

1550: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1551: @*/
1552: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1553: {

1558:   if (len) {
1560:     *len = 0;
1561:   }
1562:   if (namelist) {
1564:     *namelist = 0;
1565:   }
1566:   if (islist) {
1568:     *islist = 0;
1569:   }
1570:   if (dmlist) {
1572:     *dmlist = 0;
1573:   }
1574:   /*
1575:    Is it a good idea to apply the following check across all impls?
1576:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1577:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1578:    */
1579:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1580:   if (!dm->ops->createfielddecomposition) {
1581:     PetscSection section;
1582:     PetscInt     numFields, f;

1584:     DMGetSection(dm, &section);
1585:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1586:     if (section && numFields && dm->ops->createsubdm) {
1587:       if (len) *len = numFields;
1588:       if (namelist) {PetscMalloc1(numFields,namelist);}
1589:       if (islist)   {PetscMalloc1(numFields,islist);}
1590:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1591:       for (f = 0; f < numFields; ++f) {
1592:         const char *fieldName;

1594:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1595:         if (namelist) {
1596:           PetscSectionGetFieldName(section, f, &fieldName);
1597:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1598:         }
1599:       }
1600:     } else {
1601:       DMCreateFieldIS(dm, len, namelist, islist);
1602:       /* By default there are no DMs associated with subproblems. */
1603:       if (dmlist) *dmlist = NULL;
1604:     }
1605:   } else {
1606:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1607:   }
1608:   return(0);
1609: }

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

1615:   Not collective

1617:   Input Parameters:
1618: + dm        - The DM object
1619: . numFields - The number of fields in this subproblem
1620: - fields    - The field numbers of the selected fields

1622:   Output Parameters:
1623: + is - The global indices for the subproblem
1624: - subdm - The DM for the subproblem

1626:   Level: intermediate

1628: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1629: @*/
1630: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1631: {

1639:   if (dm->ops->createsubdm) {
1640:     (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1641:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1642:   return(0);
1643: }

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

1648:   Not collective

1650:   Input Parameter:
1651: + dms - The DM objects
1652: - len - The number of DMs

1654:   Output Parameters:
1655: + is - The global indices for the subproblem, or NULL
1656: - superdm - The DM for the superproblem

1658:   Level: intermediate

1660: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1661: @*/
1662: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1663: {
1664:   PetscInt       i;

1672:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
1673:   if (len) {
1674:     if (dms[0]->ops->createsuperdm) {(*dms[0]->ops->createsuperdm)(dms, len, is, superdm);}
1675:     else SETERRQ(PetscObjectComm((PetscObject) dms[0]), PETSC_ERR_SUP, "This type has no DMCreateSuperDM implementation defined");
1676:   }
1677:   return(0);
1678: }


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

1688:   Not collective

1690:   Input Parameter:
1691: . dm - the DM object

1693:   Output Parameters:
1694: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1695: . namelist    - The name for each subdomain (or NULL if not requested)
1696: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1697: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1698: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1700:   Level: intermediate

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

1707: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1708: @*/
1709: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1710: {
1711:   PetscErrorCode      ierr;
1712:   DMSubDomainHookLink link;
1713:   PetscInt            i,l;

1722:   /*
1723:    Is it a good idea to apply the following check across all impls?
1724:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1725:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1726:    */
1727:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1728:   if (dm->ops->createdomaindecomposition) {
1729:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1730:     /* copy subdomain hooks and context over to the subdomain DMs */
1731:     if (dmlist && *dmlist) {
1732:       for (i = 0; i < l; i++) {
1733:         for (link=dm->subdomainhook; link; link=link->next) {
1734:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1735:         }
1736:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1737:       }
1738:     }
1739:     if (len) *len = l;
1740:   }
1741:   return(0);
1742: }


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

1748:   Not collective

1750:   Input Parameters:
1751: + dm - the DM object
1752: . n  - the number of subdomain scatters
1753: - subdms - the local subdomains

1755:   Output Parameters:
1756: + n     - the number of scatters returned
1757: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1758: . oscat - scatter from global vector to overlapping global vector entries on subdomain
1759: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

1767:   Level: developer

1769: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1770: @*/
1771: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1772: {

1778:   if (dm->ops->createddscatters) {
1779:     (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
1780:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionScatter implementation defined");
1781:   return(0);
1782: }

1784: /*@
1785:   DMRefine - Refines a DM object

1787:   Collective on DM

1789:   Input Parameter:
1790: + dm   - the DM object
1791: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

1793:   Output Parameter:
1794: . dmf - the refined DM, or NULL

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

1798:   Level: developer

1800: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1801: @*/
1802: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1803: {
1804:   PetscErrorCode   ierr;
1805:   DMRefineHookLink link;

1809:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
1810:   if (!dm->ops->refine) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot refine");
1811:   (*dm->ops->refine)(dm,comm,dmf);
1812:   if (*dmf) {
1813:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

1817:     (*dmf)->ctx       = dm->ctx;
1818:     (*dmf)->leveldown = dm->leveldown;
1819:     (*dmf)->levelup   = dm->levelup + 1;

1821:     DMSetMatType(*dmf,dm->mattype);
1822:     for (link=dm->refinehook; link; link=link->next) {
1823:       if (link->refinehook) {
1824:         (*link->refinehook)(dm,*dmf,link->ctx);
1825:       }
1826:     }
1827:   }
1828:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
1829:   return(0);
1830: }

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

1835:    Logically Collective

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

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

1846: +  coarse - coarse level DM
1847: .  fine - fine level DM to interpolate problem to
1848: -  ctx - optional user-defined function context

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

1853: +  coarse - coarse level DM
1854: .  interp - matrix interpolating a coarse-level solution to the finer grid
1855: .  fine - fine level DM to update
1856: -  ctx - optional user-defined function context

1858:    Level: advanced

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

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

1865:    This function is currently not available from Fortran.

1867: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1868: @*/
1869: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1870: {
1871:   PetscErrorCode   ierr;
1872:   DMRefineHookLink link,*p;

1876:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
1877:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
1878:   }
1879:   PetscNew(&link);
1880:   link->refinehook = refinehook;
1881:   link->interphook = interphook;
1882:   link->ctx        = ctx;
1883:   link->next       = NULL;
1884:   *p               = link;
1885:   return(0);
1886: }

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

1891:    Logically Collective

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

1899:    Level: advanced

1901:    Notes:
1902:    This function does nothing if the hook is not in the list.

1904:    This function is currently not available from Fortran.

1906: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1907: @*/
1908: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1909: {
1910:   PetscErrorCode   ierr;
1911:   DMRefineHookLink link,*p;

1915:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
1916:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
1917:       link = *p;
1918:       *p = link->next;
1919:       PetscFree(link);
1920:       break;
1921:     }
1922:   }
1923:   return(0);
1924: }

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

1929:    Collective if any hooks are

1931:    Input Arguments:
1932: +  coarse - coarser DM to use as a base
1933: .  interp - interpolation matrix, apply using MatInterpolate()
1934: -  fine - finer DM to update

1936:    Level: developer

1938: .seealso: DMRefineHookAdd(), MatInterpolate()
1939: @*/
1940: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1941: {
1942:   PetscErrorCode   ierr;
1943:   DMRefineHookLink link;

1946:   for (link=fine->refinehook; link; link=link->next) {
1947:     if (link->interphook) {
1948:       (*link->interphook)(coarse,interp,fine,link->ctx);
1949:     }
1950:   }
1951:   return(0);
1952: }

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

1957:     Not Collective

1959:     Input Parameter:
1960: .   dm - the DM object

1962:     Output Parameter:
1963: .   level - number of refinements

1965:     Level: developer

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

1969: @*/
1970: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1971: {
1974:   *level = dm->levelup;
1975:   return(0);
1976: }

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

1981:     Not Collective

1983:     Input Parameter:
1984: +   dm - the DM object
1985: -   level - number of refinements

1987:     Level: advanced

1989:     Notes:
1990:     This value is used by PCMG to determine how many multigrid levels to use

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

1994: @*/
1995: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
1996: {
1999:   dm->levelup = level;
2000:   return(0);
2001: }

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

2006:    Logically Collective

2008:    Input Arguments:
2009: +  dm - the DM
2010: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2011: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2012: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2017: +  dm - global DM
2018: .  g - global vector
2019: .  mode - mode
2020: .  l - local vector
2021: -  ctx - optional user-defined function context


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

2027: +  global - global DM
2028: -  ctx - optional user-defined function context

2030:    Level: advanced

2032: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2033: @*/
2034: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2035: {
2036:   PetscErrorCode          ierr;
2037:   DMGlobalToLocalHookLink link,*p;

2041:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2042:   PetscNew(&link);
2043:   link->beginhook = beginhook;
2044:   link->endhook   = endhook;
2045:   link->ctx       = ctx;
2046:   link->next      = NULL;
2047:   *p              = link;
2048:   return(0);
2049: }

2051: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2052: {
2053:   Mat cMat;
2054:   Vec cVec;
2055:   PetscSection section, cSec;
2056:   PetscInt pStart, pEnd, p, dof;

2061:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2062:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2063:     PetscInt nRows;

2065:     MatGetSize(cMat,&nRows,NULL);
2066:     if (nRows <= 0) return(0);
2067:     DMGetSection(dm,&section);
2068:     MatCreateVecs(cMat,NULL,&cVec);
2069:     MatMult(cMat,l,cVec);
2070:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2071:     for (p = pStart; p < pEnd; p++) {
2072:       PetscSectionGetDof(cSec,p,&dof);
2073:       if (dof) {
2074:         PetscScalar *vals;
2075:         VecGetValuesSection(cVec,cSec,p,&vals);
2076:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2077:       }
2078:     }
2079:     VecDestroy(&cVec);
2080:   }
2081:   return(0);
2082: }

2084: /*@
2085:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2087:     Neighbor-wise Collective on DM

2089:     Input Parameters:
2090: +   dm - the DM object
2091: .   g - the global vector
2092: .   mode - INSERT_VALUES or ADD_VALUES
2093: -   l - the local vector


2096:     Level: beginner

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

2100: @*/
2101: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2102: {
2103:   PetscSF                 sf;
2104:   PetscErrorCode          ierr;
2105:   DMGlobalToLocalHookLink link;

2109:   for (link=dm->gtolhook; link; link=link->next) {
2110:     if (link->beginhook) {
2111:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2112:     }
2113:   }
2114:   DMGetDefaultSF(dm, &sf);
2115:   if (sf) {
2116:     const PetscScalar *gArray;
2117:     PetscScalar       *lArray;

2119:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2120:     VecGetArray(l, &lArray);
2121:     VecGetArrayRead(g, &gArray);
2122:     PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
2123:     VecRestoreArray(l, &lArray);
2124:     VecRestoreArrayRead(g, &gArray);
2125:   } else {
2126:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2127:   }
2128:   return(0);
2129: }

2131: /*@
2132:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2134:     Neighbor-wise Collective on DM

2136:     Input Parameters:
2137: +   dm - the DM object
2138: .   g - the global vector
2139: .   mode - INSERT_VALUES or ADD_VALUES
2140: -   l - the local vector


2143:     Level: beginner

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

2147: @*/
2148: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2149: {
2150:   PetscSF                 sf;
2151:   PetscErrorCode          ierr;
2152:   const PetscScalar      *gArray;
2153:   PetscScalar            *lArray;
2154:   DMGlobalToLocalHookLink link;

2158:   DMGetDefaultSF(dm, &sf);
2159:   if (sf) {
2160:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

2162:     VecGetArray(l, &lArray);
2163:     VecGetArrayRead(g, &gArray);
2164:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2165:     VecRestoreArray(l, &lArray);
2166:     VecRestoreArrayRead(g, &gArray);
2167:   } else {
2168:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2169:   }
2170:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2171:   for (link=dm->gtolhook; link; link=link->next) {
2172:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2173:   }
2174:   return(0);
2175: }

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

2180:    Logically Collective

2182:    Input Arguments:
2183: +  dm - the DM
2184: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2185: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2186: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2191: +  dm - global DM
2192: .  l - local vector
2193: .  mode - mode
2194: .  g - global vector
2195: -  ctx - optional user-defined function context


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

2201: +  global - global DM
2202: .  l - local vector
2203: .  mode - mode
2204: .  g - global vector
2205: -  ctx - optional user-defined function context

2207:    Level: advanced

2209: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2210: @*/
2211: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2212: {
2213:   PetscErrorCode          ierr;
2214:   DMLocalToGlobalHookLink link,*p;

2218:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2219:   PetscNew(&link);
2220:   link->beginhook = beginhook;
2221:   link->endhook   = endhook;
2222:   link->ctx       = ctx;
2223:   link->next      = NULL;
2224:   *p              = link;
2225:   return(0);
2226: }

2228: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2229: {
2230:   Mat cMat;
2231:   Vec cVec;
2232:   PetscSection section, cSec;
2233:   PetscInt pStart, pEnd, p, dof;

2238:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2239:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2240:     PetscInt nRows;

2242:     MatGetSize(cMat,&nRows,NULL);
2243:     if (nRows <= 0) return(0);
2244:     DMGetSection(dm,&section);
2245:     MatCreateVecs(cMat,NULL,&cVec);
2246:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2247:     for (p = pStart; p < pEnd; p++) {
2248:       PetscSectionGetDof(cSec,p,&dof);
2249:       if (dof) {
2250:         PetscInt d;
2251:         PetscScalar *vals;
2252:         VecGetValuesSection(l,section,p,&vals);
2253:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2254:         /* for this to be the true transpose, we have to zero the values that
2255:          * we just extracted */
2256:         for (d = 0; d < dof; d++) {
2257:           vals[d] = 0.;
2258:         }
2259:       }
2260:     }
2261:     MatMultTransposeAdd(cMat,cVec,l,l);
2262:     VecDestroy(&cVec);
2263:   }
2264:   return(0);
2265: }

2267: /*@
2268:     DMLocalToGlobalBegin - updates global vectors from local vectors

2270:     Neighbor-wise Collective on DM

2272:     Input Parameters:
2273: +   dm - the DM object
2274: .   l - the local vector
2275: .   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.
2276: -   g - the global vector

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

2282:     Level: beginner

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

2286: @*/
2287: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2288: {
2289:   PetscSF                 sf;
2290:   PetscSection            s, gs;
2291:   DMLocalToGlobalHookLink link;
2292:   const PetscScalar      *lArray;
2293:   PetscScalar            *gArray;
2294:   PetscBool               isInsert;
2295:   PetscErrorCode          ierr;

2299:   for (link=dm->ltoghook; link; link=link->next) {
2300:     if (link->beginhook) {
2301:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2302:     }
2303:   }
2304:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2305:   DMGetDefaultSF(dm, &sf);
2306:   DMGetSection(dm, &s);
2307:   switch (mode) {
2308:   case INSERT_VALUES:
2309:   case INSERT_ALL_VALUES:
2310:   case INSERT_BC_VALUES:
2311:     isInsert = PETSC_TRUE; break;
2312:   case ADD_VALUES:
2313:   case ADD_ALL_VALUES:
2314:   case ADD_BC_VALUES:
2315:     isInsert = PETSC_FALSE; break;
2316:   default:
2317:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2318:   }
2319:   if (sf && !isInsert) {
2320:     VecGetArrayRead(l, &lArray);
2321:     VecGetArray(g, &gArray);
2322:     PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2323:     VecRestoreArrayRead(l, &lArray);
2324:     VecRestoreArray(g, &gArray);
2325:   } else if (s && isInsert) {
2326:     PetscInt gStart, pStart, pEnd, p;

2328:     DMGetGlobalSection(dm, &gs);
2329:     PetscSectionGetChart(s, &pStart, &pEnd);
2330:     VecGetOwnershipRange(g, &gStart, NULL);
2331:     VecGetArrayRead(l, &lArray);
2332:     VecGetArray(g, &gArray);
2333:     for (p = pStart; p < pEnd; ++p) {
2334:       PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2336:       PetscSectionGetDof(s, p, &dof);
2337:       PetscSectionGetDof(gs, p, &gdof);
2338:       PetscSectionGetConstraintDof(s, p, &cdof);
2339:       PetscSectionGetConstraintDof(gs, p, &gcdof);
2340:       PetscSectionGetOffset(s, p, &off);
2341:       PetscSectionGetOffset(gs, p, &goff);
2342:       /* Ignore off-process data and points with no global data */
2343:       if (!gdof || goff < 0) continue;
2344:       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);
2345:       /* If no constraints are enforced in the global vector */
2346:       if (!gcdof) {
2347:         for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2348:       /* If constraints are enforced in the global vector */
2349:       } else if (cdof == gcdof) {
2350:         const PetscInt *cdofs;
2351:         PetscInt        cind = 0;

2353:         PetscSectionGetConstraintIndices(s, p, &cdofs);
2354:         for (d = 0, e = 0; d < dof; ++d) {
2355:           if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2356:           gArray[goff-gStart+e++] = lArray[off+d];
2357:         }
2358:       } 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);
2359:     }
2360:     VecRestoreArrayRead(l, &lArray);
2361:     VecRestoreArray(g, &gArray);
2362:   } else {
2363:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2364:   }
2365:   return(0);
2366: }

2368: /*@
2369:     DMLocalToGlobalEnd - updates global vectors from local vectors

2371:     Neighbor-wise Collective on DM

2373:     Input Parameters:
2374: +   dm - the DM object
2375: .   l - the local vector
2376: .   mode - INSERT_VALUES or ADD_VALUES
2377: -   g - the global vector


2380:     Level: beginner

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

2384: @*/
2385: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2386: {
2387:   PetscSF                 sf;
2388:   PetscSection            s;
2389:   DMLocalToGlobalHookLink link;
2390:   PetscBool               isInsert;
2391:   PetscErrorCode          ierr;

2395:   DMGetDefaultSF(dm, &sf);
2396:   DMGetSection(dm, &s);
2397:   switch (mode) {
2398:   case INSERT_VALUES:
2399:   case INSERT_ALL_VALUES:
2400:     isInsert = PETSC_TRUE; break;
2401:   case ADD_VALUES:
2402:   case ADD_ALL_VALUES:
2403:     isInsert = PETSC_FALSE; break;
2404:   default:
2405:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2406:   }
2407:   if (sf && !isInsert) {
2408:     const PetscScalar *lArray;
2409:     PetscScalar       *gArray;

2411:     VecGetArrayRead(l, &lArray);
2412:     VecGetArray(g, &gArray);
2413:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2414:     VecRestoreArrayRead(l, &lArray);
2415:     VecRestoreArray(g, &gArray);
2416:   } else if (s && isInsert) {
2417:   } else {
2418:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2419:   }
2420:   for (link=dm->ltoghook; link; link=link->next) {
2421:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2422:   }
2423:   return(0);
2424: }

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

2431:    Neighbor-wise Collective on DM and Vec

2433:    Input Parameters:
2434: +  dm - the DM object
2435: .  g - the original local vector
2436: -  mode - one of INSERT_VALUES or ADD_VALUES

2438:    Output Parameter:
2439: .  l  - the local vector with correct ghost values

2441:    Level: intermediate

2443:    Notes:
2444:    The local vectors used here need not be the same as those
2445:    obtained from DMCreateLocalVector(), BUT they
2446:    must have the same parallel data layout; they could, for example, be
2447:    obtained with VecDuplicate() from the DM originating vectors.

2449: .keywords: DM, local-to-local, begin
2450: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()

2452: @*/
2453: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2454: {
2455:   PetscErrorCode          ierr;

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

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

2469:    Neighbor-wise Collective on DM and Vec

2471:    Input Parameters:
2472: +  da - the DM object
2473: .  g - the original local vector
2474: -  mode - one of INSERT_VALUES or ADD_VALUES

2476:    Output Parameter:
2477: .  l  - the local vector with correct ghost values

2479:    Level: intermediate

2481:    Notes:
2482:    The local vectors used here need not be the same as those
2483:    obtained from DMCreateLocalVector(), BUT they
2484:    must have the same parallel data layout; they could, for example, be
2485:    obtained with VecDuplicate() from the DM originating vectors.

2487: .keywords: DM, local-to-local, end
2488: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()

2490: @*/
2491: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2492: {
2493:   PetscErrorCode          ierr;

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


2503: /*@
2504:     DMCoarsen - Coarsens a DM object

2506:     Collective on DM

2508:     Input Parameter:
2509: +   dm - the DM object
2510: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2512:     Output Parameter:
2513: .   dmc - the coarsened DM

2515:     Level: developer

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

2519: @*/
2520: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2521: {
2522:   PetscErrorCode    ierr;
2523:   DMCoarsenHookLink link;

2527:   if (!dm->ops->coarsen) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot coarsen");
2528:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2529:   (*dm->ops->coarsen)(dm, comm, dmc);
2530:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2531:   DMSetCoarseDM(dm,*dmc);
2532:   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2533:   PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2534:   (*dmc)->ctx               = dm->ctx;
2535:   (*dmc)->levelup           = dm->levelup;
2536:   (*dmc)->leveldown         = dm->leveldown + 1;
2537:   DMSetMatType(*dmc,dm->mattype);
2538:   for (link=dm->coarsenhook; link; link=link->next) {
2539:     if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2540:   }
2541:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
2542:   return(0);
2543: }

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

2548:    Logically Collective

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

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

2559: +  fine - fine level DM
2560: .  coarse - coarse level DM to restrict problem to
2561: -  ctx - optional user-defined function context

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

2566: +  fine - fine level DM
2567: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2568: .  rscale - scaling vector for restriction
2569: .  inject - matrix restricting by injection
2570: .  coarse - coarse level DM to update
2571: -  ctx - optional user-defined function context

2573:    Level: advanced

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

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

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

2583:    This function is currently not available from Fortran.

2585: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2586: @*/
2587: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2588: {
2589:   PetscErrorCode    ierr;
2590:   DMCoarsenHookLink link,*p;

2594:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2595:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2596:   }
2597:   PetscNew(&link);
2598:   link->coarsenhook  = coarsenhook;
2599:   link->restricthook = restricthook;
2600:   link->ctx          = ctx;
2601:   link->next         = NULL;
2602:   *p                 = link;
2603:   return(0);
2604: }

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

2609:    Logically Collective

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

2617:    Level: advanced

2619:    Notes:
2620:    This function does nothing if the hook is not in the list.

2622:    This function is currently not available from Fortran.

2624: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2625: @*/
2626: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2627: {
2628:   PetscErrorCode    ierr;
2629:   DMCoarsenHookLink link,*p;

2633:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2634:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2635:       link = *p;
2636:       *p = link->next;
2637:       PetscFree(link);
2638:       break;
2639:     }
2640:   }
2641:   return(0);
2642: }


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

2648:    Collective if any hooks are

2650:    Input Arguments:
2651: +  fine - finer DM to use as a base
2652: .  restrct - restriction matrix, apply using MatRestrict()
2653: .  rscale - scaling vector for restriction
2654: .  inject - injection matrix, also use MatRestrict()
2655: -  coarse - coarser DM to update

2657:    Level: developer

2659: .seealso: DMCoarsenHookAdd(), MatRestrict()
2660: @*/
2661: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2662: {
2663:   PetscErrorCode    ierr;
2664:   DMCoarsenHookLink link;

2667:   for (link=fine->coarsenhook; link; link=link->next) {
2668:     if (link->restricthook) {
2669:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
2670:     }
2671:   }
2672:   return(0);
2673: }

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

2678:    Logically Collective

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


2687:    Calling sequence for ddhook:
2688: $    ddhook(DM global,DM block,void *ctx)

2690: +  global - global DM
2691: .  block  - block DM
2692: -  ctx - optional user-defined function context

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

2697: +  global - global DM
2698: .  out    - scatter to the outer (with ghost and overlap points) block vector
2699: .  in     - scatter to block vector values only owned locally
2700: .  block  - block DM
2701: -  ctx - optional user-defined function context

2703:    Level: advanced

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

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

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

2713:    This function is currently not available from Fortran.

2715: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2716: @*/
2717: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2718: {
2719:   PetscErrorCode      ierr;
2720:   DMSubDomainHookLink link,*p;

2724:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2725:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2726:   }
2727:   PetscNew(&link);
2728:   link->restricthook = restricthook;
2729:   link->ddhook       = ddhook;
2730:   link->ctx          = ctx;
2731:   link->next         = NULL;
2732:   *p                 = link;
2733:   return(0);
2734: }

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

2739:    Logically Collective

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

2747:    Level: advanced

2749:    Notes:

2751:    This function is currently not available from Fortran.

2753: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2754: @*/
2755: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2756: {
2757:   PetscErrorCode      ierr;
2758:   DMSubDomainHookLink link,*p;

2762:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2763:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2764:       link = *p;
2765:       *p = link->next;
2766:       PetscFree(link);
2767:       break;
2768:     }
2769:   }
2770:   return(0);
2771: }

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

2776:    Collective if any hooks are

2778:    Input Arguments:
2779: +  fine - finer DM to use as a base
2780: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2781: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2782: -  coarse - coarer DM to update

2784:    Level: developer

2786: .seealso: DMCoarsenHookAdd(), MatRestrict()
2787: @*/
2788: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2789: {
2790:   PetscErrorCode      ierr;
2791:   DMSubDomainHookLink link;

2794:   for (link=global->subdomainhook; link; link=link->next) {
2795:     if (link->restricthook) {
2796:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
2797:     }
2798:   }
2799:   return(0);
2800: }

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

2805:     Not Collective

2807:     Input Parameter:
2808: .   dm - the DM object

2810:     Output Parameter:
2811: .   level - number of coarsenings

2813:     Level: developer

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

2817: @*/
2818: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2819: {
2822:   *level = dm->leveldown;
2823:   return(0);
2824: }



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

2831:     Collective on DM

2833:     Input Parameter:
2834: +   dm - the DM object
2835: -   nlevels - the number of levels of refinement

2837:     Output Parameter:
2838: .   dmf - the refined DM hierarchy

2840:     Level: developer

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

2844: @*/
2845: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2846: {

2851:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2852:   if (nlevels == 0) return(0);
2853:   if (dm->ops->refinehierarchy) {
2854:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
2855:   } else if (dm->ops->refine) {
2856:     PetscInt i;

2858:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
2859:     for (i=1; i<nlevels; i++) {
2860:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
2861:     }
2862:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2863:   return(0);
2864: }

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

2869:     Collective on DM

2871:     Input Parameter:
2872: +   dm - the DM object
2873: -   nlevels - the number of levels of coarsening

2875:     Output Parameter:
2876: .   dmc - the coarsened DM hierarchy

2878:     Level: developer

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

2882: @*/
2883: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2884: {

2889:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2890:   if (nlevels == 0) return(0);
2892:   if (dm->ops->coarsenhierarchy) {
2893:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
2894:   } else if (dm->ops->coarsen) {
2895:     PetscInt i;

2897:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
2898:     for (i=1; i<nlevels; i++) {
2899:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
2900:     }
2901:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2902:   return(0);
2903: }

2905: /*@
2906:    DMCreateAggregates - Gets the aggregates that map between
2907:    grids associated with two DMs.

2909:    Collective on DM

2911:    Input Parameters:
2912: +  dmc - the coarse grid DM
2913: -  dmf - the fine grid DM

2915:    Output Parameters:
2916: .  rest - the restriction matrix (transpose of the projection matrix)

2918:    Level: intermediate

2920: .keywords: interpolation, restriction, multigrid

2922: .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2923: @*/
2924: PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2925: {

2931:   (*dmc->ops->getaggregates)(dmc, dmf, rest);
2932:   return(0);
2933: }

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

2938:     Not Collective

2940:     Input Parameters:
2941: +   dm - the DM object
2942: -   destroy - the destroy function

2944:     Level: intermediate

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

2948: @*/
2949: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2950: {
2953:   dm->ctxdestroy = destroy;
2954:   return(0);
2955: }

2957: /*@
2958:     DMSetApplicationContext - Set a user context into a DM object

2960:     Not Collective

2962:     Input Parameters:
2963: +   dm - the DM object
2964: -   ctx - the user context

2966:     Level: intermediate

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

2970: @*/
2971: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2972: {
2975:   dm->ctx = ctx;
2976:   return(0);
2977: }

2979: /*@
2980:     DMGetApplicationContext - Gets a user context from a DM object

2982:     Not Collective

2984:     Input Parameter:
2985: .   dm - the DM object

2987:     Output Parameter:
2988: .   ctx - the user context

2990:     Level: intermediate

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

2994: @*/
2995: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2996: {
2999:   *(void**)ctx = dm->ctx;
3000:   return(0);
3001: }

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

3006:     Logically Collective on DM

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

3012:     Level: intermediate

3014: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3015:          DMSetJacobian()

3017: @*/
3018: PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3019: {
3021:   dm->ops->computevariablebounds = f;
3022:   return(0);
3023: }

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

3028:     Not Collective

3030:     Input Parameter:
3031: .   dm - the DM object to destroy

3033:     Output Parameter:
3034: .   flg - PETSC_TRUE if the variable bounds function exists

3036:     Level: developer

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

3040: @*/
3041: PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
3042: {
3044:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3045:   return(0);
3046: }

3048: /*@C
3049:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3051:     Logically Collective on DM

3053:     Input Parameters:
3054: .   dm - the DM object

3056:     Output parameters:
3057: +   xl - lower bound
3058: -   xu - upper bound

3060:     Level: advanced

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

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

3067: @*/
3068: PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3069: {

3075:   if (dm->ops->computevariablebounds) {
3076:     (*dm->ops->computevariablebounds)(dm, xl,xu);
3077:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
3078:   return(0);
3079: }

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

3084:     Not Collective

3086:     Input Parameter:
3087: .   dm - the DM object

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

3092:     Level: developer

3094: .seealso DMHasFunction(), DMCreateColoring()

3096: @*/
3097: PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
3098: {
3100:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3101:   return(0);
3102: }

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

3107:     Not Collective

3109:     Input Parameter:
3110: .   dm - the DM object

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

3115:     Level: developer

3117: .seealso DMHasFunction(), DMCreateRestriction()

3119: @*/
3120: PetscErrorCode  DMHasCreateRestriction(DM dm,PetscBool  *flg)
3121: {
3123:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3124:   return(0);
3125: }


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

3131:     Not Collective

3133:     Input Parameter:
3134: .   dm - the DM object

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

3139:     Level: developer

3141: .seealso DMHasFunction(), DMCreateInjection()

3143: @*/
3144: PetscErrorCode  DMHasCreateInjection(DM dm,PetscBool  *flg)
3145: {
3148:   if (!dm->ops->hascreateinjection) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DMHasCreateInjection not implemented for this type");
3149:   (*dm->ops->hascreateinjection)(dm,flg);
3150:   return(0);
3151: }

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

3156:     Collective on DM

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

3162:     Level: developer

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

3166: @*/
3167: PetscErrorCode  DMSetVec(DM dm,Vec x)
3168: {

3172:   if (x) {
3173:     if (!dm->x) {
3174:       DMCreateGlobalVector(dm,&dm->x);
3175:     }
3176:     VecCopy(x,dm->x);
3177:   } else if (dm->x) {
3178:     VecDestroy(&dm->x);
3179:   }
3180:   return(0);
3181: }

3183: PetscFunctionList DMList              = NULL;
3184: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3186: /*@C
3187:   DMSetType - Builds a DM, for a particular DM implementation.

3189:   Collective on DM

3191:   Input Parameters:
3192: + dm     - The DM object
3193: - method - The name of the DM type

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

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

3201:   Level: intermediate

3203: .keywords: DM, set, type
3204: .seealso: DMGetType(), DMCreate()
3205: @*/
3206: PetscErrorCode  DMSetType(DM dm, DMType method)
3207: {
3208:   PetscErrorCode (*r)(DM);
3209:   PetscBool      match;

3214:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3215:   if (match) return(0);

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

3221:   if (dm->ops->destroy) {
3222:     (*dm->ops->destroy)(dm);
3223:     dm->ops->destroy = NULL;
3224:   }
3225:   (*r)(dm);
3226:   PetscObjectChangeTypeName((PetscObject)dm,method);
3227:   return(0);
3228: }

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

3233:   Not Collective

3235:   Input Parameter:
3236: . dm  - The DM

3238:   Output Parameter:
3239: . type - The DM type name

3241:   Level: intermediate

3243: .keywords: DM, get, type, name
3244: .seealso: DMSetType(), DMCreate()
3245: @*/
3246: PetscErrorCode  DMGetType(DM dm, DMType *type)
3247: {

3253:   DMRegisterAll();
3254:   *type = ((PetscObject)dm)->type_name;
3255:   return(0);
3256: }

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

3261:   Collective on DM

3263:   Input Parameters:
3264: + dm - the DM
3265: - newtype - new DM type (use "same" for the same type)

3267:   Output Parameter:
3268: . M - pointer to new DM

3270:   Notes:
3271:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3272:   the MPI communicator of the generated DM is always the same as the communicator
3273:   of the input DM.

3275:   Level: intermediate

3277: .seealso: DMCreate()
3278: @*/
3279: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3280: {
3281:   DM             B;
3282:   char           convname[256];
3283:   PetscBool      sametype/*, issame */;

3290:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3291:   /* PetscStrcmp(newtype, "same", &issame); */
3292:   if (sametype) {
3293:     *M   = dm;
3294:     PetscObjectReference((PetscObject) dm);
3295:     return(0);
3296:   } else {
3297:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3299:     /*
3300:        Order of precedence:
3301:        1) See if a specialized converter is known to the current DM.
3302:        2) See if a specialized converter is known to the desired DM class.
3303:        3) See if a good general converter is registered for the desired class
3304:        4) See if a good general converter is known for the current matrix.
3305:        5) Use a really basic converter.
3306:     */

3308:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3309:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3310:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3311:     PetscStrlcat(convname,"_",sizeof(convname));
3312:     PetscStrlcat(convname,newtype,sizeof(convname));
3313:     PetscStrlcat(convname,"_C",sizeof(convname));
3314:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3315:     if (conv) goto foundconv;

3317:     /* 2)  See if a specialized converter is known to the desired DM class. */
3318:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3319:     DMSetType(B, newtype);
3320:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3321:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3322:     PetscStrlcat(convname,"_",sizeof(convname));
3323:     PetscStrlcat(convname,newtype,sizeof(convname));
3324:     PetscStrlcat(convname,"_C",sizeof(convname));
3325:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3326:     if (conv) {
3327:       DMDestroy(&B);
3328:       goto foundconv;
3329:     }

3331: #if 0
3332:     /* 3) See if a good general converter is registered for the desired class */
3333:     conv = B->ops->convertfrom;
3334:     DMDestroy(&B);
3335:     if (conv) goto foundconv;

3337:     /* 4) See if a good general converter is known for the current matrix */
3338:     if (dm->ops->convert) {
3339:       conv = dm->ops->convert;
3340:     }
3341:     if (conv) goto foundconv;
3342: #endif

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

3347: foundconv:
3348:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3349:     (*conv)(dm,newtype,M);
3350:     /* Things that are independent of DM type: We should consult DMClone() here */
3351:     {
3352:       PetscBool             isper;
3353:       const PetscReal      *maxCell, *L;
3354:       const DMBoundaryType *bd;
3355:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3356:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3357:     }
3358:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3359:   }
3360:   PetscObjectStateIncrease((PetscObject) *M);
3361:   return(0);
3362: }

3364: /*--------------------------------------------------------------------------------------------------------------------*/

3366: /*@C
3367:   DMRegister -  Adds a new DM component implementation

3369:   Not Collective

3371:   Input Parameters:
3372: + name        - The name of a new user-defined creation routine
3373: - create_func - The creation routine itself

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


3379:   Sample usage:
3380: .vb
3381:     DMRegister("my_da", MyDMCreate);
3382: .ve

3384:   Then, your DM type can be chosen with the procedural interface via
3385: .vb
3386:     DMCreate(MPI_Comm, DM *);
3387:     DMSetType(DM,"my_da");
3388: .ve
3389:    or at runtime via the option
3390: .vb
3391:     -da_type my_da
3392: .ve

3394:   Level: advanced

3396: .keywords: DM, register
3397: .seealso: DMRegisterAll(), DMRegisterDestroy()

3399: @*/
3400: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3401: {

3405:   PetscFunctionListAdd(&DMList,sname,function);
3406:   return(0);
3407: }

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

3412:   Collective on PetscViewer

3414:   Input Parameters:
3415: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3416:            some related function before a call to DMLoad().
3417: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3418:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3420:    Level: intermediate

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

3425:   Notes for advanced users:
3426:   Most users should not need to know the details of the binary storage
3427:   format, since DMLoad() and DMView() completely hide these details.
3428:   But for anyone who's interested, the standard binary matrix storage
3429:   format is
3430: .vb
3431:      has not yet been determined
3432: .ve

3434: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3435: @*/
3436: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3437: {
3438:   PetscBool      isbinary, ishdf5;

3444:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3445:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3446:   if (isbinary) {
3447:     PetscInt classid;
3448:     char     type[256];

3450:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3451:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3452:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3453:     DMSetType(newdm, type);
3454:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3455:   } else if (ishdf5) {
3456:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3457:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3458:   return(0);
3459: }

3461: /******************************** FEM Support **********************************/

3463: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3464: {
3465:   PetscInt       f;

3469:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3470:   for (f = 0; f < len; ++f) {
3471:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
3472:   }
3473:   return(0);
3474: }

3476: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3477: {
3478:   PetscInt       f, g;

3482:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3483:   for (f = 0; f < rows; ++f) {
3484:     PetscPrintf(PETSC_COMM_SELF, "  |");
3485:     for (g = 0; g < cols; ++g) {
3486:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
3487:     }
3488:     PetscPrintf(PETSC_COMM_SELF, " |\n");
3489:   }
3490:   return(0);
3491: }

3493: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3494: {
3495:   PetscInt          localSize, bs;
3496:   PetscMPIInt       size;
3497:   Vec               x, xglob;
3498:   const PetscScalar *xarray;
3499:   PetscErrorCode    ierr;

3502:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
3503:   VecDuplicate(X, &x);
3504:   VecCopy(X, x);
3505:   VecChop(x, tol);
3506:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
3507:   if (size > 1) {
3508:     VecGetLocalSize(x,&localSize);
3509:     VecGetArrayRead(x,&xarray);
3510:     VecGetBlockSize(x,&bs);
3511:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
3512:   } else {
3513:     xglob = x;
3514:   }
3515:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
3516:   if (size > 1) {
3517:     VecDestroy(&xglob);
3518:     VecRestoreArrayRead(x,&xarray);
3519:   }
3520:   VecDestroy(&x);
3521:   return(0);
3522: }

3524: /*@
3525:   DMGetSection - Get the PetscSection encoding the local data layout for the DM.

3527:   Input Parameter:
3528: . dm - The DM

3530:   Output Parameter:
3531: . section - The PetscSection

3533:   Options Database Keys:
3534: . -dm_petscsection_view - View the Section created by the DM

3536:   Level: intermediate

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

3540: .seealso: DMSetSection(), DMGetGlobalSection()
3541: @*/
3542: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
3543: {

3549:   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3550:     (*dm->ops->createdefaultsection)(dm);
3551:     if (dm->defaultSection) {PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");}
3552:   }
3553:   *section = dm->defaultSection;
3554:   return(0);
3555: }

3557: /*@
3558:   DMSetSection - Set the PetscSection encoding the local data layout for the DM.

3560:   Input Parameters:
3561: + dm - The DM
3562: - section - The PetscSection

3564:   Level: intermediate

3566:   Note: Any existing Section will be destroyed

3568: .seealso: DMSetSection(), DMGetGlobalSection()
3569: @*/
3570: PetscErrorCode DMSetSection(DM dm, PetscSection section)
3571: {
3572:   PetscInt       numFields = 0;
3573:   PetscInt       f;

3578:   if (section) {
3580:     PetscObjectReference((PetscObject)section);
3581:   }
3582:   PetscSectionDestroy(&dm->defaultSection);
3583:   dm->defaultSection = section;
3584:   if (section) {PetscSectionGetNumFields(dm->defaultSection, &numFields);}
3585:   if (numFields) {
3586:     DMSetNumFields(dm, numFields);
3587:     for (f = 0; f < numFields; ++f) {
3588:       PetscObject disc;
3589:       const char *name;

3591:       PetscSectionGetFieldName(dm->defaultSection, f, &name);
3592:       DMGetField(dm, f, &disc);
3593:       PetscObjectSetName(disc, name);
3594:     }
3595:   }
3596:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
3597:   PetscSectionDestroy(&dm->defaultGlobalSection);
3598:   return(0);
3599: }

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

3604:   not collective

3606:   Input Parameter:
3607: . dm - The DM

3609:   Output Parameter:
3610: + 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.
3611: - 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.

3613:   Level: advanced

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

3617: .seealso: DMSetDefaultConstraints()
3618: @*/
3619: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3620: {

3625:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
3626:   if (section) {*section = dm->defaultConstraintSection;}
3627:   if (mat) {*mat = dm->defaultConstraintMat;}
3628:   return(0);
3629: }

3631: /*@
3632:   DMSetDefaultConstraints - Set the PetscSection and Mat the specify the local constraint interpolation.

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

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

3638:   collective on dm

3640:   Input Parameters:
3641: + dm - The DM
3642: + 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).
3643: - 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).

3645:   Level: advanced

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

3649: .seealso: DMGetDefaultConstraints()
3650: @*/
3651: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3652: {
3653:   PetscMPIInt result;

3658:   if (section) {
3660:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
3661:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3662:   }
3663:   if (mat) {
3665:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
3666:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3667:   }
3668:   PetscObjectReference((PetscObject)section);
3669:   PetscSectionDestroy(&dm->defaultConstraintSection);
3670:   dm->defaultConstraintSection = section;
3671:   PetscObjectReference((PetscObject)mat);
3672:   MatDestroy(&dm->defaultConstraintMat);
3673:   dm->defaultConstraintMat = mat;
3674:   return(0);
3675: }

3677: #if defined(PETSC_USE_DEBUG)
3678: /*
3679:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

3681:   Input Parameters:
3682: + dm - The DM
3683: . localSection - PetscSection describing the local data layout
3684: - globalSection - PetscSection describing the global data layout

3686:   Level: intermediate

3688: .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3689: */
3690: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3691: {
3692:   MPI_Comm        comm;
3693:   PetscLayout     layout;
3694:   const PetscInt *ranges;
3695:   PetscInt        pStart, pEnd, p, nroots;
3696:   PetscMPIInt     size, rank;
3697:   PetscBool       valid = PETSC_TRUE, gvalid;
3698:   PetscErrorCode  ierr;

3701:   PetscObjectGetComm((PetscObject)dm,&comm);
3703:   MPI_Comm_size(comm, &size);
3704:   MPI_Comm_rank(comm, &rank);
3705:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
3706:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
3707:   PetscLayoutCreate(comm, &layout);
3708:   PetscLayoutSetBlockSize(layout, 1);
3709:   PetscLayoutSetLocalSize(layout, nroots);
3710:   PetscLayoutSetUp(layout);
3711:   PetscLayoutGetRanges(layout, &ranges);
3712:   for (p = pStart; p < pEnd; ++p) {
3713:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

3715:     PetscSectionGetDof(localSection, p, &dof);
3716:     PetscSectionGetOffset(localSection, p, &off);
3717:     PetscSectionGetConstraintDof(localSection, p, &cdof);
3718:     PetscSectionGetDof(globalSection, p, &gdof);
3719:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3720:     PetscSectionGetOffset(globalSection, p, &goff);
3721:     if (!gdof) continue; /* Censored point */
3722:     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;}
3723:     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;}
3724:     if (gdof < 0) {
3725:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3726:       for (d = 0; d < gsize; ++d) {
3727:         PetscInt offset = -(goff+1) + d, r;

3729:         PetscFindInt(offset,size+1,ranges,&r);
3730:         if (r < 0) r = -(r+2);
3731:         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;}
3732:       }
3733:     }
3734:   }
3735:   PetscLayoutDestroy(&layout);
3736:   PetscSynchronizedFlush(comm, NULL);
3737:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
3738:   if (!gvalid) {
3739:     DMView(dm, NULL);
3740:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3741:   }
3742:   return(0);
3743: }
3744: #endif

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

3749:   Collective on DM

3751:   Input Parameter:
3752: . dm - The DM

3754:   Output Parameter:
3755: . section - The PetscSection

3757:   Level: intermediate

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

3761: .seealso: DMSetSection(), DMGetSection()
3762: @*/
3763: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
3764: {

3770:   if (!dm->defaultGlobalSection) {
3771:     PetscSection s;

3773:     DMGetSection(dm, &s);
3774:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3775:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3776:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);
3777:     PetscLayoutDestroy(&dm->map);
3778:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);
3779:     PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");
3780:   }
3781:   *section = dm->defaultGlobalSection;
3782:   return(0);
3783: }

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

3788:   Input Parameters:
3789: + dm - The DM
3790: - section - The PetscSection, or NULL

3792:   Level: intermediate

3794:   Note: Any existing Section will be destroyed

3796: .seealso: DMGetGlobalSection(), DMSetSection()
3797: @*/
3798: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
3799: {

3805:   PetscObjectReference((PetscObject)section);
3806:   PetscSectionDestroy(&dm->defaultGlobalSection);
3807:   dm->defaultGlobalSection = section;
3808: #if defined(PETSC_USE_DEBUG)
3809:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);}
3810: #endif
3811:   return(0);
3812: }

3814: /*@
3815:   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3816:   it is created from the default PetscSection layouts in the DM.

3818:   Input Parameter:
3819: . dm - The DM

3821:   Output Parameter:
3822: . sf - The PetscSF

3824:   Level: intermediate

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

3828: .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3829: @*/
3830: PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3831: {
3832:   PetscInt       nroots;

3838:   PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);
3839:   if (nroots < 0) {
3840:     PetscSection section, gSection;

3842:     DMGetSection(dm, &section);
3843:     if (section) {
3844:       DMGetGlobalSection(dm, &gSection);
3845:       DMCreateDefaultSF(dm, section, gSection);
3846:     } else {
3847:       *sf = NULL;
3848:       return(0);
3849:     }
3850:   }
3851:   *sf = dm->defaultSF;
3852:   return(0);
3853: }

3855: /*@
3856:   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM

3858:   Input Parameters:
3859: + dm - The DM
3860: - sf - The PetscSF

3862:   Level: intermediate

3864:   Note: Any previous SF is destroyed

3866: .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3867: @*/
3868: PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3869: {

3875:   PetscSFDestroy(&dm->defaultSF);
3876:   dm->defaultSF = sf;
3877:   return(0);
3878: }

3880: /*@C
3881:   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3882:   describing the data layout.

3884:   Input Parameters:
3885: + dm - The DM
3886: . localSection - PetscSection describing the local data layout
3887: - globalSection - PetscSection describing the global data layout

3889:   Level: intermediate

3891: .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3892: @*/
3893: PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3894: {
3895:   MPI_Comm       comm;
3896:   PetscLayout    layout;
3897:   const PetscInt *ranges;
3898:   PetscInt       *local;
3899:   PetscSFNode    *remote;
3900:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3901:   PetscMPIInt    size, rank;

3905:   PetscObjectGetComm((PetscObject)dm,&comm);
3907:   MPI_Comm_size(comm, &size);
3908:   MPI_Comm_rank(comm, &rank);
3909:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
3910:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
3911:   PetscLayoutCreate(comm, &layout);
3912:   PetscLayoutSetBlockSize(layout, 1);
3913:   PetscLayoutSetLocalSize(layout, nroots);
3914:   PetscLayoutSetUp(layout);
3915:   PetscLayoutGetRanges(layout, &ranges);
3916:   for (p = pStart; p < pEnd; ++p) {
3917:     PetscInt gdof, gcdof;

3919:     PetscSectionGetDof(globalSection, p, &gdof);
3920:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3921:     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));
3922:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3923:   }
3924:   PetscMalloc1(nleaves, &local);
3925:   PetscMalloc1(nleaves, &remote);
3926:   for (p = pStart, l = 0; p < pEnd; ++p) {
3927:     const PetscInt *cind;
3928:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

3930:     PetscSectionGetDof(localSection, p, &dof);
3931:     PetscSectionGetOffset(localSection, p, &off);
3932:     PetscSectionGetConstraintDof(localSection, p, &cdof);
3933:     PetscSectionGetConstraintIndices(localSection, p, &cind);
3934:     PetscSectionGetDof(globalSection, p, &gdof);
3935:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3936:     PetscSectionGetOffset(globalSection, p, &goff);
3937:     if (!gdof) continue; /* Censored point */
3938:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3939:     if (gsize != dof-cdof) {
3940:       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);
3941:       cdof = 0; /* Ignore constraints */
3942:     }
3943:     for (d = 0, c = 0; d < dof; ++d) {
3944:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3945:       local[l+d-c] = off+d;
3946:     }
3947:     if (gdof < 0) {
3948:       for (d = 0; d < gsize; ++d, ++l) {
3949:         PetscInt offset = -(goff+1) + d, r;

3951:         PetscFindInt(offset,size+1,ranges,&r);
3952:         if (r < 0) r = -(r+2);
3953:         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);
3954:         remote[l].rank  = r;
3955:         remote[l].index = offset - ranges[r];
3956:       }
3957:     } else {
3958:       for (d = 0; d < gsize; ++d, ++l) {
3959:         remote[l].rank  = rank;
3960:         remote[l].index = goff+d - ranges[rank];
3961:       }
3962:     }
3963:   }
3964:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3965:   PetscLayoutDestroy(&layout);
3966:   PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
3967:   return(0);
3968: }

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

3973:   Input Parameter:
3974: . dm - The DM

3976:   Output Parameter:
3977: . sf - The PetscSF

3979:   Level: intermediate

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

3983: .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3984: @*/
3985: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3986: {
3990:   *sf = dm->sf;
3991:   return(0);
3992: }

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

3997:   Input Parameters:
3998: + dm - The DM
3999: - sf - The PetscSF

4001:   Level: intermediate

4003: .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
4004: @*/
4005: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4006: {

4012:   PetscSFDestroy(&dm->sf);
4013:   PetscObjectReference((PetscObject) sf);
4014:   dm->sf = sf;
4015:   return(0);
4016: }

4018: /*@
4019:   DMGetDS - Get the PetscDS

4021:   Input Parameter:
4022: . dm - The DM

4024:   Output Parameter:
4025: . prob - The PetscDS

4027:   Level: developer

4029: .seealso: DMSetDS()
4030: @*/
4031: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
4032: {
4036:   *prob = dm->prob;
4037:   return(0);
4038: }

4040: /*@
4041:   DMSetDS - Set the PetscDS

4043:   Input Parameters:
4044: + dm - The DM
4045: - prob - The PetscDS

4047:   Level: developer

4049: .seealso: DMGetDS()
4050: @*/
4051: PetscErrorCode DMSetDS(DM dm, PetscDS prob)
4052: {
4053:   PetscInt       dimEmbed;

4059:   PetscObjectReference((PetscObject) prob);
4060:   PetscDSDestroy(&dm->prob);
4061:   dm->prob = prob;
4062:   DMGetCoordinateDim(dm, &dimEmbed);
4063:   PetscDSSetCoordinateDimension(prob, dimEmbed);
4064:   return(0);
4065: }

4067: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4068: {

4073:   PetscDSGetNumFields(dm->prob, numFields);
4074:   return(0);
4075: }

4077: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4078: {
4079:   PetscInt       Nf, f;

4084:   PetscDSGetNumFields(dm->prob, &Nf);
4085:   for (f = Nf; f < numFields; ++f) {
4086:     PetscContainer obj;

4088:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4089:     PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);
4090:     PetscContainerDestroy(&obj);
4091:   }
4092:   return(0);
4093: }

4095: /*@
4096:   DMGetField - Return the discretization object for a given DM field

4098:   Not collective

4100:   Input Parameters:
4101: + dm - The DM
4102: - f  - The field number

4104:   Output Parameter:
4105: . field - The discretization object

4107:   Level: developer

4109: .seealso: DMSetField()
4110: @*/
4111: PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
4112: {

4117:   PetscDSGetDiscretization(dm->prob, f, field);
4118:   return(0);
4119: }

4121: /*@
4122:   DMSetField - Set the discretization object for a given DM field

4124:   Logically collective on DM

4126:   Input Parameters:
4127: + dm - The DM
4128: . f  - The field number
4129: - field - The discretization object

4131:   Level: developer

4133: .seealso: DMGetField()
4134: @*/
4135: PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
4136: {

4141:   PetscDSSetDiscretization(dm->prob, f, field);
4142:   return(0);
4143: }

4145: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
4146: {
4147:   DM dm_coord,dmc_coord;
4149:   Vec coords,ccoords;
4150:   Mat inject;
4152:   DMGetCoordinateDM(dm,&dm_coord);
4153:   DMGetCoordinateDM(dmc,&dmc_coord);
4154:   DMGetCoordinates(dm,&coords);
4155:   DMGetCoordinates(dmc,&ccoords);
4156:   if (coords && !ccoords) {
4157:     DMCreateGlobalVector(dmc_coord,&ccoords);
4158:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
4159:     DMCreateInjection(dmc_coord,dm_coord,&inject);
4160:     MatRestrict(inject,coords,ccoords);
4161:     MatDestroy(&inject);
4162:     DMSetCoordinates(dmc,ccoords);
4163:     VecDestroy(&ccoords);
4164:   }
4165:   return(0);
4166: }

4168: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
4169: {
4170:   DM dm_coord,subdm_coord;
4172:   Vec coords,ccoords,clcoords;
4173:   VecScatter *scat_i,*scat_g;
4175:   DMGetCoordinateDM(dm,&dm_coord);
4176:   DMGetCoordinateDM(subdm,&subdm_coord);
4177:   DMGetCoordinates(dm,&coords);
4178:   DMGetCoordinates(subdm,&ccoords);
4179:   if (coords && !ccoords) {
4180:     DMCreateGlobalVector(subdm_coord,&ccoords);
4181:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
4182:     DMCreateLocalVector(subdm_coord,&clcoords);
4183:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
4184:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
4185:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
4186:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
4187:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
4188:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
4189:     DMSetCoordinates(subdm,ccoords);
4190:     DMSetCoordinatesLocal(subdm,clcoords);
4191:     VecScatterDestroy(&scat_i[0]);
4192:     VecScatterDestroy(&scat_g[0]);
4193:     VecDestroy(&ccoords);
4194:     VecDestroy(&clcoords);
4195:     PetscFree(scat_i);
4196:     PetscFree(scat_g);
4197:   }
4198:   return(0);
4199: }

4201: /*@
4202:   DMGetDimension - Return the topological dimension of the DM

4204:   Not collective

4206:   Input Parameter:
4207: . dm - The DM

4209:   Output Parameter:
4210: . dim - The topological dimension

4212:   Level: beginner

4214: .seealso: DMSetDimension(), DMCreate()
4215: @*/
4216: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
4217: {
4221:   *dim = dm->dim;
4222:   return(0);
4223: }

4225: /*@
4226:   DMSetDimension - Set the topological dimension of the DM

4228:   Collective on dm

4230:   Input Parameters:
4231: + dm - The DM
4232: - dim - The topological dimension

4234:   Level: beginner

4236: .seealso: DMGetDimension(), DMCreate()
4237: @*/
4238: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
4239: {

4245:   dm->dim = dim;
4246:   if (dm->prob->dimEmbed < 0) {PetscDSSetCoordinateDimension(dm->prob, dm->dim);}
4247:   return(0);
4248: }

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

4253:   Collective on DM

4255:   Input Parameters:
4256: + dm - the DM
4257: - dim - the dimension

4259:   Output Parameters:
4260: + pStart - The first point of the given dimension
4261: . pEnd - The first point following points of the given dimension

4263:   Note:
4264:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
4265:   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
4266:   then the interval is empty.

4268:   Level: intermediate

4270: .keywords: point, Hasse Diagram, dimension
4271: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
4272: @*/
4273: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4274: {
4275:   PetscInt       d;

4280:   DMGetDimension(dm, &d);
4281:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
4282:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
4283:   return(0);
4284: }

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

4289:   Collective on DM

4291:   Input Parameters:
4292: + dm - the DM
4293: - c - coordinate vector

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

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

4300:   Level: intermediate

4302: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4303: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4304: @*/
4305: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4306: {

4312:   PetscObjectReference((PetscObject) c);
4313:   VecDestroy(&dm->coordinates);
4314:   dm->coordinates = c;
4315:   VecDestroy(&dm->coordinatesLocal);
4316:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
4317:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
4318:   return(0);
4319: }

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

4324:   Collective on DM

4326:    Input Parameters:
4327: +  dm - the DM
4328: -  c - coordinate vector

4330:   Notes:
4331:   The coordinates of ghost points can be set using DMSetCoordinates()
4332:   followed by DMGetCoordinatesLocal(). This is intended to enable the
4333:   setting of ghost coordinates outside of the domain.

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

4337:   Level: intermediate

4339: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4340: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4341: @*/
4342: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4343: {

4349:   PetscObjectReference((PetscObject) c);
4350:   VecDestroy(&dm->coordinatesLocal);

4352:   dm->coordinatesLocal = c;

4354:   VecDestroy(&dm->coordinates);
4355:   return(0);
4356: }

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

4361:   Not Collective

4363:   Input Parameter:
4364: . dm - the DM

4366:   Output Parameter:
4367: . c - global coordinate vector

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

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

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

4377:   Level: intermediate

4379: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4380: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4381: @*/
4382: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4383: {

4389:   if (!dm->coordinates && dm->coordinatesLocal) {
4390:     DM cdm = NULL;

4392:     DMGetCoordinateDM(dm, &cdm);
4393:     DMCreateGlobalVector(cdm, &dm->coordinates);
4394:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
4395:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
4396:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
4397:   }
4398:   *c = dm->coordinates;
4399:   return(0);
4400: }

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

4405:   Collective on DM

4407:   Input Parameter:
4408: . dm - the DM

4410:   Output Parameter:
4411: . c - coordinate vector

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

4416:   Each process has the local and ghost coordinates

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

4421:   Level: intermediate

4423: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4424: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4425: @*/
4426: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4427: {

4433:   if (!dm->coordinatesLocal && dm->coordinates) {
4434:     DM cdm = NULL;

4436:     DMGetCoordinateDM(dm, &cdm);
4437:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
4438:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
4439:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
4440:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
4441:   }
4442:   *c = dm->coordinatesLocal;
4443:   return(0);
4444: }

4446: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
4447: {

4453:   if (!dm->coordinateField) {
4454:     if (dm->ops->createcoordinatefield) {
4455:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
4456:     }
4457:   }
4458:   *field = dm->coordinateField;
4459:   return(0);
4460: }

4462: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
4463: {

4469:   PetscObjectReference((PetscObject)field);
4470:   DMFieldDestroy(&dm->coordinateField);
4471:   dm->coordinateField = field;
4472:   return(0);
4473: }

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

4478:   Collective on DM

4480:   Input Parameter:
4481: . dm - the DM

4483:   Output Parameter:
4484: . cdm - coordinate DM

4486:   Level: intermediate

4488: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4489: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4490: @*/
4491: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4492: {

4498:   if (!dm->coordinateDM) {
4499:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4500:     (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);
4501:   }
4502:   *cdm = dm->coordinateDM;
4503:   return(0);
4504: }

4506: /*@
4507:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

4509:   Logically Collective on DM

4511:   Input Parameters:
4512: + dm - the DM
4513: - cdm - coordinate DM

4515:   Level: intermediate

4517: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4518: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4519: @*/
4520: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4521: {

4527:   PetscObjectReference((PetscObject)cdm);
4528:   DMDestroy(&dm->coordinateDM);
4529:   dm->coordinateDM = cdm;
4530:   return(0);
4531: }

4533: /*@
4534:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

4536:   Not Collective

4538:   Input Parameter:
4539: . dm - The DM object

4541:   Output Parameter:
4542: . dim - The embedding dimension

4544:   Level: intermediate

4546: .keywords: mesh, coordinates
4547: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4548: @*/
4549: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4550: {
4554:   if (dm->dimEmbed == PETSC_DEFAULT) {
4555:     dm->dimEmbed = dm->dim;
4556:   }
4557:   *dim = dm->dimEmbed;
4558:   return(0);
4559: }

4561: /*@
4562:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

4564:   Not Collective

4566:   Input Parameters:
4567: + dm  - The DM object
4568: - dim - The embedding dimension

4570:   Level: intermediate

4572: .keywords: mesh, coordinates
4573: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4574: @*/
4575: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4576: {

4581:   dm->dimEmbed = dim;
4582:   PetscDSSetCoordinateDimension(dm->prob, dm->dimEmbed);
4583:   return(0);
4584: }

4586: /*@
4587:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

4589:   Not Collective

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

4594:   Output Parameter:
4595: . section - The PetscSection object

4597:   Level: intermediate

4599: .keywords: mesh, coordinates
4600: .seealso: DMGetCoordinateDM(), DMGetSection(), DMSetSection()
4601: @*/
4602: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4603: {
4604:   DM             cdm;

4610:   DMGetCoordinateDM(dm, &cdm);
4611:   DMGetSection(cdm, section);
4612:   return(0);
4613: }

4615: /*@
4616:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

4618:   Not Collective

4620:   Input Parameters:
4621: + dm      - The DM object
4622: . dim     - The embedding dimension, or PETSC_DETERMINE
4623: - section - The PetscSection object

4625:   Level: intermediate

4627: .keywords: mesh, coordinates
4628: .seealso: DMGetCoordinateSection(), DMGetSection(), DMSetSection()
4629: @*/
4630: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4631: {
4632:   DM             cdm;

4638:   DMGetCoordinateDM(dm, &cdm);
4639:   DMSetSection(cdm, section);
4640:   if (dim == PETSC_DETERMINE) {
4641:     PetscInt d = PETSC_DEFAULT;
4642:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

4644:     PetscSectionGetChart(section, &pStart, &pEnd);
4645:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
4646:     pStart = PetscMax(vStart, pStart);
4647:     pEnd   = PetscMin(vEnd, pEnd);
4648:     for (v = pStart; v < pEnd; ++v) {
4649:       PetscSectionGetDof(section, v, &dd);
4650:       if (dd) {d = dd; break;}
4651:     }
4652:     if (d < 0) d = PETSC_DEFAULT;
4653:     DMSetCoordinateDim(dm, d);
4654:   }
4655:   return(0);
4656: }

4658: /*@C
4659:   DMGetPeriodicity - Get the description of mesh periodicity

4661:   Input Parameters:
4662: . dm      - The DM object

4664:   Output Parameters:
4665: + per     - Whether the DM is periodic or not
4666: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4667: . L       - If we assume the mesh is a torus, this is the length of each coordinate
4668: - bd      - This describes the type of periodicity in each topological dimension

4670:   Level: developer

4672: .seealso: DMGetPeriodicity()
4673: @*/
4674: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4675: {
4678:   if (per)     *per     = dm->periodic;
4679:   if (L)       *L       = dm->L;
4680:   if (maxCell) *maxCell = dm->maxCell;
4681:   if (bd)      *bd      = dm->bdtype;
4682:   return(0);
4683: }

4685: /*@C
4686:   DMSetPeriodicity - Set the description of mesh periodicity

4688:   Input Parameters:
4689: + dm      - The DM object
4690: . per     - Whether the DM is periodic or not. If maxCell is not provided, coordinates need to be localized
4691: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
4692: . L       - If we assume the mesh is a torus, this is the length of each coordinate
4693: - bd      - This describes the type of periodicity in each topological dimension

4695:   Level: developer

4697: .seealso: DMGetPeriodicity()
4698: @*/
4699: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4700: {
4701:   PetscInt       dim, d;

4707:   if (maxCell) {
4711:   }
4712:   PetscFree3(dm->L,dm->maxCell,dm->bdtype);
4713:   DMGetDimension(dm, &dim);
4714:   if (maxCell) {
4715:     PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);
4716:     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4717:     dm->periodic = PETSC_TRUE;
4718:   } else {
4719:     dm->periodic = per;
4720:   }
4721:   return(0);
4722: }

4724: /*@
4725:   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.

4727:   Input Parameters:
4728: + dm     - The DM
4729: . in     - The input coordinate point (dim numbers)
4730: - endpoint - Include the endpoint L_i

4732:   Output Parameter:
4733: . out - The localized coordinate point

4735:   Level: developer

4737: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4738: @*/
4739: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4740: {
4741:   PetscInt       dim, d;

4745:   DMGetCoordinateDim(dm, &dim);
4746:   if (!dm->maxCell) {
4747:     for (d = 0; d < dim; ++d) out[d] = in[d];
4748:   } else {
4749:     if (endpoint) {
4750:       for (d = 0; d < dim; ++d) {
4751:         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)) {
4752:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4753:         } else {
4754:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4755:         }
4756:       }
4757:     } else {
4758:       for (d = 0; d < dim; ++d) {
4759:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4760:       }
4761:     }
4762:   }
4763:   return(0);
4764: }

4766: /*
4767:   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.

4769:   Input Parameters:
4770: + dm     - The DM
4771: . dim    - The spatial dimension
4772: . anchor - The anchor point, the input point can be no more than maxCell away from it
4773: - in     - The input coordinate point (dim numbers)

4775:   Output Parameter:
4776: . out - The localized coordinate point

4778:   Level: developer

4780:   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

4782: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4783: */
4784: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4785: {
4786:   PetscInt d;

4789:   if (!dm->maxCell) {
4790:     for (d = 0; d < dim; ++d) out[d] = in[d];
4791:   } else {
4792:     for (d = 0; d < dim; ++d) {
4793:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4794:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4795:       } else {
4796:         out[d] = in[d];
4797:       }
4798:     }
4799:   }
4800:   return(0);
4801: }
4802: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4803: {
4804:   PetscInt d;

4807:   if (!dm->maxCell) {
4808:     for (d = 0; d < dim; ++d) out[d] = in[d];
4809:   } else {
4810:     for (d = 0; d < dim; ++d) {
4811:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4812:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4813:       } else {
4814:         out[d] = in[d];
4815:       }
4816:     }
4817:   }
4818:   return(0);
4819: }

4821: /*
4822:   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.

4824:   Input Parameters:
4825: + dm     - The DM
4826: . dim    - The spatial dimension
4827: . anchor - The anchor point, the input point can be no more than maxCell away from it
4828: . in     - The input coordinate delta (dim numbers)
4829: - out    - The input coordinate point (dim numbers)

4831:   Output Parameter:
4832: . out    - The localized coordinate in + out

4834:   Level: developer

4836:   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

4838: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4839: */
4840: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4841: {
4842:   PetscInt d;

4845:   if (!dm->maxCell) {
4846:     for (d = 0; d < dim; ++d) out[d] += in[d];
4847:   } else {
4848:     for (d = 0; d < dim; ++d) {
4849:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4850:         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4851:       } else {
4852:         out[d] += in[d];
4853:       }
4854:     }
4855:   }
4856:   return(0);
4857: }

4859: /*@
4860:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

4862:   Input Parameter:
4863: . dm - The DM

4865:   Output Parameter:
4866:   areLocalized - True if localized

4868:   Level: developer

4870: .seealso: DMLocalizeCoordinates()
4871: @*/
4872: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4873: {
4874:   DM             cdm;
4875:   PetscSection   coordSection;
4876:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
4877:   PetscBool      isPlex, alreadyLocalized;


4884:   *areLocalized = PETSC_FALSE;
4885:   if (!dm->periodic) return(0); /* This is a hideous optimization hack! */

4887:   /* We need some generic way of refering to cells/vertices */
4888:   DMGetCoordinateDM(dm, &cdm);
4889:   DMGetCoordinateSection(dm, &coordSection);
4890:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
4891:   if (!isPlex) SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");

4893:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
4894:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
4895:   alreadyLocalized = PETSC_FALSE;
4896:   for (c = cStart; c < cEnd; ++c) {
4897:     if (c < sStart || c >= sEnd) continue;
4898:     PetscSectionGetDof(coordSection, c, &dof);
4899:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
4900:   }
4901:   MPIU_Allreduce(&alreadyLocalized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
4902:   return(0);
4903: }


4906: /*@
4907:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

4909:   Input Parameter:
4910: . dm - The DM

4912:   Level: developer

4914: .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4915: @*/
4916: PetscErrorCode DMLocalizeCoordinates(DM dm)
4917: {
4918:   DM             cdm;
4919:   PetscSection   coordSection, cSection;
4920:   Vec            coordinates,  cVec;
4921:   PetscScalar   *coords, *coords2, *anchor, *localized;
4922:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4923:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4924:   PetscInt       maxHeight = 0, h;
4925:   PetscInt       *pStart = NULL, *pEnd = NULL;

4930:   if (!dm->periodic) return(0);
4931:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
4932:   if (alreadyLocalized) return(0);

4934:   /* We need some generic way of refering to cells/vertices */
4935:   DMGetCoordinateDM(dm, &cdm);
4936:   {
4937:     PetscBool isplex;

4939:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
4940:     if (isplex) {
4941:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
4942:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
4943:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
4944:       pEnd = &pStart[maxHeight + 1];
4945:       newStart = vStart;
4946:       newEnd   = vEnd;
4947:       for (h = 0; h <= maxHeight; h++) {
4948:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
4949:         newStart = PetscMin(newStart,pStart[h]);
4950:         newEnd   = PetscMax(newEnd,pEnd[h]);
4951:       }
4952:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4953:   }
4954:   DMGetCoordinatesLocal(dm, &coordinates);
4955:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
4956:   DMGetCoordinateSection(dm, &coordSection);
4957:   VecGetBlockSize(coordinates, &bs);
4958:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

4960:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
4961:   PetscSectionSetNumFields(cSection, 1);
4962:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
4963:   PetscSectionSetFieldComponents(cSection, 0, Nc);
4964:   PetscSectionSetChart(cSection, newStart, newEnd);

4966:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
4967:   localized = &anchor[bs];
4968:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4969:   for (h = 0; h <= maxHeight; h++) {
4970:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

4972:     for (c = cStart; c < cEnd; ++c) {
4973:       PetscScalar *cellCoords = NULL;
4974:       PetscInt     b;

4976:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4977:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4978:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4979:       for (d = 0; d < dof/bs; ++d) {
4980:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
4981:         for (b = 0; b < bs; b++) {
4982:           if (cellCoords[d*bs + b] != localized[b]) break;
4983:         }
4984:         if (b < bs) break;
4985:       }
4986:       if (d < dof/bs) {
4987:         if (c >= sStart && c < sEnd) {
4988:           PetscInt cdof;

4990:           PetscSectionGetDof(coordSection, c, &cdof);
4991:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4992:         }
4993:         PetscSectionSetDof(cSection, c, dof);
4994:         PetscSectionSetFieldDof(cSection, c, 0, dof);
4995:       }
4996:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4997:     }
4998:   }
4999:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
5000:   if (alreadyLocalizedGlobal) {
5001:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
5002:     PetscSectionDestroy(&cSection);
5003:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
5004:     return(0);
5005:   }
5006:   for (v = vStart; v < vEnd; ++v) {
5007:     PetscSectionGetDof(coordSection, v, &dof);
5008:     PetscSectionSetDof(cSection,     v,  dof);
5009:     PetscSectionSetFieldDof(cSection, v, 0, dof);
5010:   }
5011:   PetscSectionSetUp(cSection);
5012:   PetscSectionGetStorageSize(cSection, &coordSize);
5013:   VecCreate(PETSC_COMM_SELF, &cVec);
5014:   PetscObjectSetName((PetscObject)cVec,"coordinates");
5015:   VecSetBlockSize(cVec,         bs);
5016:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
5017:   VecSetType(cVec, VECSTANDARD);
5018:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
5019:   VecGetArray(cVec, &coords2);
5020:   for (v = vStart; v < vEnd; ++v) {
5021:     PetscSectionGetDof(coordSection, v, &dof);
5022:     PetscSectionGetOffset(coordSection, v, &off);
5023:     PetscSectionGetOffset(cSection,     v, &off2);
5024:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
5025:   }
5026:   for (h = 0; h <= maxHeight; h++) {
5027:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

5029:     for (c = cStart; c < cEnd; ++c) {
5030:       PetscScalar *cellCoords = NULL;
5031:       PetscInt     b, cdof;

5033:       PetscSectionGetDof(cSection,c,&cdof);
5034:       if (!cdof) continue;
5035:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
5036:       PetscSectionGetOffset(cSection, c, &off2);
5037:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
5038:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
5039:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
5040:     }
5041:   }
5042:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
5043:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
5044:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
5045:   VecRestoreArray(cVec, &coords2);
5046:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
5047:   DMSetCoordinatesLocal(dm, cVec);
5048:   VecDestroy(&cVec);
5049:   PetscSectionDestroy(&cSection);
5050:   return(0);
5051: }

5053: /*@
5054:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

5056:   Collective on Vec v (see explanation below)

5058:   Input Parameters:
5059: + dm - The DM
5060: . v - The Vec of points
5061: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
5062: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

5064:   Output Parameter:
5065: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
5066: - cells - The PetscSF containing the ranks and local indices of the containing points.


5069:   Level: developer

5071:   Notes:
5072:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
5073:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

5075:   If *cellSF is NULL on input, a PetscSF will be created.
5076:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

5078:   An array that maps each point to its containing cell can be obtained with

5080: $    const PetscSFNode *cells;
5081: $    PetscInt           nFound;
5082: $    const PetscInt    *found;
5083: $
5084: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

5086:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
5087:   the index of the cell in its rank's local numbering.

5089: .keywords: point location, mesh
5090: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
5091: @*/
5092: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
5093: {

5100:   if (*cellSF) {
5101:     PetscMPIInt result;

5104:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
5105:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
5106:   } else {
5107:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
5108:   }
5109:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
5110:   if (dm->ops->locatepoints) {
5111:     (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
5112:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
5113:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
5114:   return(0);
5115: }

5117: /*@
5118:   DMGetOutputDM - Retrieve the DM associated with the layout for output

5120:   Input Parameter:
5121: . dm - The original DM

5123:   Output Parameter:
5124: . odm - The DM which provides the layout for output

5126:   Level: intermediate

5128: .seealso: VecView(), DMGetGlobalSection()
5129: @*/
5130: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
5131: {
5132:   PetscSection   section;
5133:   PetscBool      hasConstraints, ghasConstraints;

5139:   DMGetSection(dm, &section);
5140:   PetscSectionHasConstraints(section, &hasConstraints);
5141:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
5142:   if (!ghasConstraints) {
5143:     *odm = dm;
5144:     return(0);
5145:   }
5146:   if (!dm->dmBC) {
5147:     PetscDS      ds;
5148:     PetscSection newSection, gsection;
5149:     PetscSF      sf;

5151:     DMClone(dm, &dm->dmBC);
5152:     DMGetDS(dm, &ds);
5153:     DMSetDS(dm->dmBC, ds);
5154:     PetscSectionClone(section, &newSection);
5155:     DMSetSection(dm->dmBC, newSection);
5156:     PetscSectionDestroy(&newSection);
5157:     DMGetPointSF(dm->dmBC, &sf);
5158:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
5159:     DMSetGlobalSection(dm->dmBC, gsection);
5160:     PetscSectionDestroy(&gsection);
5161:   }
5162:   *odm = dm->dmBC;
5163:   return(0);
5164: }

5166: /*@
5167:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

5169:   Input Parameter:
5170: . dm - The original DM

5172:   Output Parameters:
5173: + num - The output sequence number
5174: - val - The output sequence value

5176:   Level: intermediate

5178:   Note: This is intended for output that should appear in sequence, for instance
5179:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

5181: .seealso: VecView()
5182: @*/
5183: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
5184: {
5189:   return(0);
5190: }

5192: /*@
5193:   DMSetOutputSequenceNumber - Set the sequence number/value for output

5195:   Input Parameters:
5196: + dm - The original DM
5197: . num - The output sequence number
5198: - val - The output sequence value

5200:   Level: intermediate

5202:   Note: This is intended for output that should appear in sequence, for instance
5203:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

5205: .seealso: VecView()
5206: @*/
5207: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
5208: {
5211:   dm->outputSequenceNum = num;
5212:   dm->outputSequenceVal = val;
5213:   return(0);
5214: }

5216: /*@C
5217:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

5219:   Input Parameters:
5220: + dm   - The original DM
5221: . name - The sequence name
5222: - num  - The output sequence number

5224:   Output Parameter:
5225: . val  - The output sequence value

5227:   Level: intermediate

5229:   Note: This is intended for output that should appear in sequence, for instance
5230:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

5232: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5233: @*/
5234: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5235: {
5236:   PetscBool      ishdf5;

5243:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
5244:   if (ishdf5) {
5245: #if defined(PETSC_HAVE_HDF5)
5246:     PetscScalar value;

5248:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
5249:     *val = PetscRealPart(value);
5250: #endif
5251:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5252:   return(0);
5253: }

5255: /*@
5256:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

5258:   Not collective

5260:   Input Parameter:
5261: . dm - The DM

5263:   Output Parameter:
5264: . useNatural - The flag to build the mapping to a natural order during distribution

5266:   Level: beginner

5268: .seealso: DMSetUseNatural(), DMCreate()
5269: @*/
5270: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5271: {
5275:   *useNatural = dm->useNatural;
5276:   return(0);
5277: }

5279: /*@
5280:   DMSetUseNatural - Set the flag for creating a mapping to the natural order on distribution

5282:   Collective on dm

5284:   Input Parameters:
5285: + dm - The DM
5286: - useNatural - The flag to build the mapping to a natural order during distribution

5288:   Level: beginner

5290: .seealso: DMGetUseNatural(), DMCreate()
5291: @*/
5292: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5293: {
5297:   dm->useNatural = useNatural;
5298:   return(0);
5299: }


5302: /*@C
5303:   DMCreateLabel - Create a label of the given name if it does not already exist

5305:   Not Collective

5307:   Input Parameters:
5308: + dm   - The DM object
5309: - name - The label name

5311:   Level: intermediate

5313: .keywords: mesh
5314: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5315: @*/
5316: PetscErrorCode DMCreateLabel(DM dm, const char name[])
5317: {
5318:   DMLabelLink    next  = dm->labels->next;
5319:   PetscBool      flg   = PETSC_FALSE;

5325:   while (next) {
5326:     PetscStrcmp(name, next->label->name, &flg);
5327:     if (flg) break;
5328:     next = next->next;
5329:   }
5330:   if (!flg) {
5331:     DMLabelLink tmpLabel;

5333:     PetscCalloc1(1, &tmpLabel);
5334:     DMLabelCreate(name, &tmpLabel->label);
5335:     tmpLabel->output = PETSC_TRUE;
5336:     tmpLabel->next   = dm->labels->next;
5337:     dm->labels->next = tmpLabel;
5338:   }
5339:   return(0);
5340: }

5342: /*@C
5343:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

5345:   Not Collective

5347:   Input Parameters:
5348: + dm   - The DM object
5349: . name - The label name
5350: - point - The mesh point

5352:   Output Parameter:
5353: . value - The label value for this point, or -1 if the point is not in the label

5355:   Level: beginner

5357: .keywords: mesh
5358: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5359: @*/
5360: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5361: {
5362:   DMLabel        label;

5368:   DMGetLabel(dm, name, &label);
5369:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5370:   DMLabelGetValue(label, point, value);
5371:   return(0);
5372: }

5374: /*@C
5375:   DMSetLabelValue - Add a point to a Sieve Label with given value

5377:   Not Collective

5379:   Input Parameters:
5380: + dm   - The DM object
5381: . name - The label name
5382: . point - The mesh point
5383: - value - The label value for this point

5385:   Output Parameter:

5387:   Level: beginner

5389: .keywords: mesh
5390: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5391: @*/
5392: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5393: {
5394:   DMLabel        label;

5400:   DMGetLabel(dm, name, &label);
5401:   if (!label) {
5402:     DMCreateLabel(dm, name);
5403:     DMGetLabel(dm, name, &label);
5404:   }
5405:   DMLabelSetValue(label, point, value);
5406:   return(0);
5407: }

5409: /*@C
5410:   DMClearLabelValue - Remove a point from a Sieve Label with given value

5412:   Not Collective

5414:   Input Parameters:
5415: + dm   - The DM object
5416: . name - The label name
5417: . point - The mesh point
5418: - value - The label value for this point

5420:   Output Parameter:

5422:   Level: beginner

5424: .keywords: mesh
5425: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5426: @*/
5427: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5428: {
5429:   DMLabel        label;

5435:   DMGetLabel(dm, name, &label);
5436:   if (!label) return(0);
5437:   DMLabelClearValue(label, point, value);
5438:   return(0);
5439: }

5441: /*@C
5442:   DMGetLabelSize - Get the number of different integer ids in a Label

5444:   Not Collective

5446:   Input Parameters:
5447: + dm   - The DM object
5448: - name - The label name

5450:   Output Parameter:
5451: . size - The number of different integer ids, or 0 if the label does not exist

5453:   Level: beginner

5455: .keywords: mesh
5456: .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5457: @*/
5458: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5459: {
5460:   DMLabel        label;

5467:   DMGetLabel(dm, name, &label);
5468:   *size = 0;
5469:   if (!label) return(0);
5470:   DMLabelGetNumValues(label, size);
5471:   return(0);
5472: }

5474: /*@C
5475:   DMGetLabelIdIS - Get the integer ids in a label

5477:   Not Collective

5479:   Input Parameters:
5480: + mesh - The DM object
5481: - name - The label name

5483:   Output Parameter:
5484: . ids - The integer ids, or NULL if the label does not exist

5486:   Level: beginner

5488: .keywords: mesh
5489: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5490: @*/
5491: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5492: {
5493:   DMLabel        label;

5500:   DMGetLabel(dm, name, &label);
5501:   *ids = NULL;
5502:  if (label) {
5503:     DMLabelGetValueIS(label, ids);
5504:   } else {
5505:     /* returning an empty IS */
5506:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
5507:   }
5508:   return(0);
5509: }

5511: /*@C
5512:   DMGetStratumSize - Get the number of points in a label stratum

5514:   Not Collective

5516:   Input Parameters:
5517: + dm - The DM object
5518: . name - The label name
5519: - value - The stratum value

5521:   Output Parameter:
5522: . size - The stratum size

5524:   Level: beginner

5526: .keywords: mesh
5527: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5528: @*/
5529: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5530: {
5531:   DMLabel        label;

5538:   DMGetLabel(dm, name, &label);
5539:   *size = 0;
5540:   if (!label) return(0);
5541:   DMLabelGetStratumSize(label, value, size);
5542:   return(0);
5543: }

5545: /*@C
5546:   DMGetStratumIS - Get the points in a label stratum

5548:   Not Collective

5550:   Input Parameters:
5551: + dm - The DM object
5552: . name - The label name
5553: - value - The stratum value

5555:   Output Parameter:
5556: . points - The stratum points, or NULL if the label does not exist or does not have that value

5558:   Level: beginner

5560: .keywords: mesh
5561: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5562: @*/
5563: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5564: {
5565:   DMLabel        label;

5572:   DMGetLabel(dm, name, &label);
5573:   *points = NULL;
5574:   if (!label) return(0);
5575:   DMLabelGetStratumIS(label, value, points);
5576:   return(0);
5577: }

5579: /*@C
5580:   DMSetStratumIS - Set the points in a label stratum

5582:   Not Collective

5584:   Input Parameters:
5585: + dm - The DM object
5586: . name - The label name
5587: . value - The stratum value
5588: - points - The stratum points

5590:   Level: beginner

5592: .keywords: mesh
5593: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5594: @*/
5595: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5596: {
5597:   DMLabel        label;

5604:   DMGetLabel(dm, name, &label);
5605:   if (!label) return(0);
5606:   DMLabelSetStratumIS(label, value, points);
5607:   return(0);
5608: }

5610: /*@C
5611:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

5613:   Not Collective

5615:   Input Parameters:
5616: + dm   - The DM object
5617: . name - The label name
5618: - value - The label value for this point

5620:   Output Parameter:

5622:   Level: beginner

5624: .keywords: mesh
5625: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
5626: @*/
5627: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
5628: {
5629:   DMLabel        label;

5635:   DMGetLabel(dm, name, &label);
5636:   if (!label) return(0);
5637:   DMLabelClearStratum(label, value);
5638:   return(0);
5639: }

5641: /*@
5642:   DMGetNumLabels - Return the number of labels defined by the mesh

5644:   Not Collective

5646:   Input Parameter:
5647: . dm   - The DM object

5649:   Output Parameter:
5650: . numLabels - the number of Labels

5652:   Level: intermediate

5654: .keywords: mesh
5655: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5656: @*/
5657: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5658: {
5659:   DMLabelLink next = dm->labels->next;
5660:   PetscInt  n    = 0;

5665:   while (next) {++n; next = next->next;}
5666:   *numLabels = n;
5667:   return(0);
5668: }

5670: /*@C
5671:   DMGetLabelName - Return the name of nth label

5673:   Not Collective

5675:   Input Parameters:
5676: + dm - The DM object
5677: - n  - the label number

5679:   Output Parameter:
5680: . name - the label name

5682:   Level: intermediate

5684: .keywords: mesh
5685: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5686: @*/
5687: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5688: {
5689:   DMLabelLink next = dm->labels->next;
5690:   PetscInt  l    = 0;

5695:   while (next) {
5696:     if (l == n) {
5697:       *name = next->label->name;
5698:       return(0);
5699:     }
5700:     ++l;
5701:     next = next->next;
5702:   }
5703:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5704: }

5706: /*@C
5707:   DMHasLabel - Determine whether the mesh has a label of a given name

5709:   Not Collective

5711:   Input Parameters:
5712: + dm   - The DM object
5713: - name - The label name

5715:   Output Parameter:
5716: . hasLabel - PETSC_TRUE if the label is present

5718:   Level: intermediate

5720: .keywords: mesh
5721: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5722: @*/
5723: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5724: {
5725:   DMLabelLink    next = dm->labels->next;

5732:   *hasLabel = PETSC_FALSE;
5733:   while (next) {
5734:     PetscStrcmp(name, next->label->name, hasLabel);
5735:     if (*hasLabel) break;
5736:     next = next->next;
5737:   }
5738:   return(0);
5739: }

5741: /*@C
5742:   DMGetLabel - Return the label of a given name, or NULL

5744:   Not Collective

5746:   Input Parameters:
5747: + dm   - The DM object
5748: - name - The label name

5750:   Output Parameter:
5751: . label - The DMLabel, or NULL if the label is absent

5753:   Level: intermediate

5755: .keywords: mesh
5756: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5757: @*/
5758: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5759: {
5760:   DMLabelLink    next = dm->labels->next;
5761:   PetscBool      hasLabel;

5768:   *label = NULL;
5769:   while (next) {
5770:     PetscStrcmp(name, next->label->name, &hasLabel);
5771:     if (hasLabel) {
5772:       *label = next->label;
5773:       break;
5774:     }
5775:     next = next->next;
5776:   }
5777:   return(0);
5778: }

5780: /*@C
5781:   DMGetLabelByNum - Return the nth label

5783:   Not Collective

5785:   Input Parameters:
5786: + dm - The DM object
5787: - n  - the label number

5789:   Output Parameter:
5790: . label - the label

5792:   Level: intermediate

5794: .keywords: mesh
5795: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5796: @*/
5797: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5798: {
5799:   DMLabelLink next = dm->labels->next;
5800:   PetscInt    l    = 0;

5805:   while (next) {
5806:     if (l == n) {
5807:       *label = next->label;
5808:       return(0);
5809:     }
5810:     ++l;
5811:     next = next->next;
5812:   }
5813:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5814: }

5816: /*@C
5817:   DMAddLabel - Add the label to this mesh

5819:   Not Collective

5821:   Input Parameters:
5822: + dm   - The DM object
5823: - label - The DMLabel

5825:   Level: developer

5827: .keywords: mesh
5828: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5829: @*/
5830: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5831: {
5832:   DMLabelLink    tmpLabel;
5833:   PetscBool      hasLabel;

5838:   DMHasLabel(dm, label->name, &hasLabel);
5839:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5840:   PetscCalloc1(1, &tmpLabel);
5841:   tmpLabel->label  = label;
5842:   tmpLabel->output = PETSC_TRUE;
5843:   tmpLabel->next   = dm->labels->next;
5844:   dm->labels->next = tmpLabel;
5845:   return(0);
5846: }

5848: /*@C
5849:   DMRemoveLabel - Remove the label from this mesh

5851:   Not Collective

5853:   Input Parameters:
5854: + dm   - The DM object
5855: - name - The label name

5857:   Output Parameter:
5858: . label - The DMLabel, or NULL if the label is absent

5860:   Level: developer

5862: .keywords: mesh
5863: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5864: @*/
5865: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5866: {
5867:   DMLabelLink    next = dm->labels->next;
5868:   DMLabelLink    last = NULL;
5869:   PetscBool      hasLabel;

5874:   DMHasLabel(dm, name, &hasLabel);
5875:   *label = NULL;
5876:   if (!hasLabel) return(0);
5877:   while (next) {
5878:     PetscStrcmp(name, next->label->name, &hasLabel);
5879:     if (hasLabel) {
5880:       if (last) last->next       = next->next;
5881:       else      dm->labels->next = next->next;
5882:       next->next = NULL;
5883:       *label     = next->label;
5884:       PetscStrcmp(name, "depth", &hasLabel);
5885:       if (hasLabel) {
5886:         dm->depthLabel = NULL;
5887:       }
5888:       PetscFree(next);
5889:       break;
5890:     }
5891:     last = next;
5892:     next = next->next;
5893:   }
5894:   return(0);
5895: }

5897: /*@C
5898:   DMGetLabelOutput - Get the output flag for a given label

5900:   Not Collective

5902:   Input Parameters:
5903: + dm   - The DM object
5904: - name - The label name

5906:   Output Parameter:
5907: . output - The flag for output

5909:   Level: developer

5911: .keywords: mesh
5912: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5913: @*/
5914: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5915: {
5916:   DMLabelLink    next = dm->labels->next;

5923:   while (next) {
5924:     PetscBool flg;

5926:     PetscStrcmp(name, next->label->name, &flg);
5927:     if (flg) {*output = next->output; return(0);}
5928:     next = next->next;
5929:   }
5930:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5931: }

5933: /*@C
5934:   DMSetLabelOutput - Set the output flag for a given label

5936:   Not Collective

5938:   Input Parameters:
5939: + dm     - The DM object
5940: . name   - The label name
5941: - output - The flag for output

5943:   Level: developer

5945: .keywords: mesh
5946: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5947: @*/
5948: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5949: {
5950:   DMLabelLink    next = dm->labels->next;

5956:   while (next) {
5957:     PetscBool flg;

5959:     PetscStrcmp(name, next->label->name, &flg);
5960:     if (flg) {next->output = output; return(0);}
5961:     next = next->next;
5962:   }
5963:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5964: }


5967: /*@
5968:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

5970:   Collective on DM

5972:   Input Parameter:
5973: . dmA - The DM object with initial labels

5975:   Output Parameter:
5976: . dmB - The DM object with copied labels

5978:   Level: intermediate

5980:   Note: This is typically used when interpolating or otherwise adding to a mesh

5982: .keywords: mesh
5983: .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5984: @*/
5985: PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5986: {
5987:   PetscInt       numLabels, l;

5991:   if (dmA == dmB) return(0);
5992:   DMGetNumLabels(dmA, &numLabels);
5993:   for (l = 0; l < numLabels; ++l) {
5994:     DMLabel     label, labelNew;
5995:     const char *name;
5996:     PetscBool   flg;

5998:     DMGetLabelName(dmA, l, &name);
5999:     PetscStrcmp(name, "depth", &flg);
6000:     if (flg) continue;
6001:     PetscStrcmp(name, "dim", &flg);
6002:     if (flg) continue;
6003:     DMGetLabel(dmA, name, &label);
6004:     DMLabelDuplicate(label, &labelNew);
6005:     DMAddLabel(dmB, labelNew);
6006:   }
6007:   return(0);
6008: }

6010: /*@
6011:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

6013:   Input Parameter:
6014: . dm - The DM object

6016:   Output Parameter:
6017: . cdm - The coarse DM

6019:   Level: intermediate

6021: .seealso: DMSetCoarseDM()
6022: @*/
6023: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
6024: {
6028:   *cdm = dm->coarseMesh;
6029:   return(0);
6030: }

6032: /*@
6033:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

6035:   Input Parameters:
6036: + dm - The DM object
6037: - cdm - The coarse DM

6039:   Level: intermediate

6041: .seealso: DMGetCoarseDM()
6042: @*/
6043: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
6044: {

6050:   PetscObjectReference((PetscObject)cdm);
6051:   DMDestroy(&dm->coarseMesh);
6052:   dm->coarseMesh = cdm;
6053:   return(0);
6054: }

6056: /*@
6057:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

6059:   Input Parameter:
6060: . dm - The DM object

6062:   Output Parameter:
6063: . fdm - The fine DM

6065:   Level: intermediate

6067: .seealso: DMSetFineDM()
6068: @*/
6069: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
6070: {
6074:   *fdm = dm->fineMesh;
6075:   return(0);
6076: }

6078: /*@
6079:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

6081:   Input Parameters:
6082: + dm - The DM object
6083: - fdm - The fine DM

6085:   Level: intermediate

6087: .seealso: DMGetFineDM()
6088: @*/
6089: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
6090: {

6096:   PetscObjectReference((PetscObject)fdm);
6097:   DMDestroy(&dm->fineMesh);
6098:   dm->fineMesh = fdm;
6099:   return(0);
6100: }

6102: /*=== DMBoundary code ===*/

6104: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
6105: {

6109:   PetscDSCopyBoundary(dm->prob,dmNew->prob);
6110:   return(0);
6111: }

6113: /*@C
6114:   DMAddBoundary - Add a boundary condition to the model

6116:   Input Parameters:
6117: + dm          - The DM, with a PetscDS that matches the problem being constrained
6118: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6119: . name        - The BC name
6120: . labelname   - The label defining constrained points
6121: . field       - The field to constrain
6122: . numcomps    - The number of constrained field components
6123: . comps       - An array of constrained component numbers
6124: . bcFunc      - A pointwise function giving boundary values
6125: . numids      - The number of DMLabel ids for constrained points
6126: . ids         - An array of ids for constrained points
6127: - ctx         - An optional user context for bcFunc

6129:   Options Database Keys:
6130: + -bc_<boundary name> <num> - Overrides the boundary ids
6131: - -bc_<boundary name>_comp <num> - Overrides the boundary components

6133:   Level: developer

6135: .seealso: DMGetBoundary()
6136: @*/
6137: 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)
6138: {

6143:   PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);
6144:   return(0);
6145: }

6147: /*@
6148:   DMGetNumBoundary - Get the number of registered BC

6150:   Input Parameters:
6151: . dm - The mesh object

6153:   Output Parameters:
6154: . numBd - The number of BC

6156:   Level: intermediate

6158: .seealso: DMAddBoundary(), DMGetBoundary()
6159: @*/
6160: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
6161: {

6166:   PetscDSGetNumBoundary(dm->prob,numBd);
6167:   return(0);
6168: }

6170: /*@C
6171:   DMGetBoundary - Get a model boundary condition

6173:   Input Parameters:
6174: + dm          - The mesh object
6175: - bd          - The BC number

6177:   Output Parameters:
6178: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
6179: . name        - The BC name
6180: . labelname   - The label defining constrained points
6181: . field       - The field to constrain
6182: . numcomps    - The number of constrained field components
6183: . comps       - An array of constrained component numbers
6184: . bcFunc      - A pointwise function giving boundary values
6185: . numids      - The number of DMLabel ids for constrained points
6186: . ids         - An array of ids for constrained points
6187: - ctx         - An optional user context for bcFunc

6189:   Options Database Keys:
6190: + -bc_<boundary name> <num> - Overrides the boundary ids
6191: - -bc_<boundary name>_comp <num> - Overrides the boundary components

6193:   Level: developer

6195: .seealso: DMAddBoundary()
6196: @*/
6197: 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)
6198: {

6203:   PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);
6204:   return(0);
6205: }

6207: static PetscErrorCode DMPopulateBoundary(DM dm)
6208: {
6209:   DMBoundary *lastnext;
6210:   DSBoundary dsbound;

6214:   dsbound = dm->prob->boundary;
6215:   if (dm->boundary) {
6216:     DMBoundary next = dm->boundary;

6218:     /* quick check to see if the PetscDS has changed */
6219:     if (next->dsboundary == dsbound) return(0);
6220:     /* the PetscDS has changed: tear down and rebuild */
6221:     while (next) {
6222:       DMBoundary b = next;

6224:       next = b->next;
6225:       PetscFree(b);
6226:     }
6227:     dm->boundary = NULL;
6228:   }

6230:   lastnext = &(dm->boundary);
6231:   while (dsbound) {
6232:     DMBoundary dmbound;

6234:     PetscNew(&dmbound);
6235:     dmbound->dsboundary = dsbound;
6236:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
6237:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
6238:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6239:     *lastnext = dmbound;
6240:     lastnext = &(dmbound->next);
6241:     dsbound = dsbound->next;
6242:   }
6243:   return(0);
6244: }

6246: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6247: {
6248:   DMBoundary     b;

6254:   *isBd = PETSC_FALSE;
6255:   DMPopulateBoundary(dm);
6256:   b = dm->boundary;
6257:   while (b && !(*isBd)) {
6258:     DMLabel    label = b->label;
6259:     DSBoundary dsb = b->dsboundary;

6261:     if (label) {
6262:       PetscInt i;

6264:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6265:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
6266:       }
6267:     }
6268:     b = b->next;
6269:   }
6270:   return(0);
6271: }

6273: /*@C
6274:   DMProjectFunction - This projects the given function into the function space provided.

6276:   Input Parameters:
6277: + dm      - The DM
6278: . time    - The time
6279: . funcs   - The coordinate functions to evaluate, one per field
6280: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6281: - mode    - The insertion mode for values

6283:   Output Parameter:
6284: . X - vector

6286:    Calling sequence of func:
6287: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

6289: +  dim - The spatial dimension
6290: .  x   - The coordinates
6291: .  Nf  - The number of fields
6292: .  u   - The output field values
6293: -  ctx - optional user-defined function context

6295:   Level: developer

6297: .seealso: DMComputeL2Diff()
6298: @*/
6299: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6300: {
6301:   Vec            localX;

6306:   DMGetLocalVector(dm, &localX);
6307:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
6308:   DMLocalToGlobalBegin(dm, localX, mode, X);
6309:   DMLocalToGlobalEnd(dm, localX, mode, X);
6310:   DMRestoreLocalVector(dm, &localX);
6311:   return(0);
6312: }

6314: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6315: {

6321:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6322:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
6323:   return(0);
6324: }

6326: 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)
6327: {
6328:   Vec            localX;

6333:   DMGetLocalVector(dm, &localX);
6334:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
6335:   DMLocalToGlobalBegin(dm, localX, mode, X);
6336:   DMLocalToGlobalEnd(dm, localX, mode, X);
6337:   DMRestoreLocalVector(dm, &localX);
6338:   return(0);
6339: }

6341: 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)
6342: {

6348:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6349:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
6350:   return(0);
6351: }

6353: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6354:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6355:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6356:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6357:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6358:                                    InsertMode mode, Vec localX)
6359: {

6366:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6367:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
6368:   return(0);
6369: }

6371: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6372:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6373:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6374:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6375:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6376:                                         InsertMode mode, Vec localX)
6377: {

6384:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
6385:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
6386:   return(0);
6387: }

6389: /*@C
6390:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

6392:   Input Parameters:
6393: + dm    - The DM
6394: . time  - The time
6395: . funcs - The functions to evaluate for each field component
6396: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6397: - X     - The coefficient vector u_h, a global vector

6399:   Output Parameter:
6400: . diff - The diff ||u - u_h||_2

6402:   Level: developer

6404: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6405: @*/
6406: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6407: {

6413:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
6414:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
6415:   return(0);
6416: }

6418: /*@C
6419:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

6421:   Input Parameters:
6422: + dm    - The DM
6423: , time  - The time
6424: . funcs - The gradient functions to evaluate for each field component
6425: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6426: . X     - The coefficient vector u_h, a global vector
6427: - n     - The vector to project along

6429:   Output Parameter:
6430: . diff - The diff ||(grad u - grad u_h) . n||_2

6432:   Level: developer

6434: .seealso: DMProjectFunction(), DMComputeL2Diff()
6435: @*/
6436: 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)
6437: {

6443:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6444:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
6445:   return(0);
6446: }

6448: /*@C
6449:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

6451:   Input Parameters:
6452: + dm    - The DM
6453: . time  - The time
6454: . funcs - The functions to evaluate for each field component
6455: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6456: - X     - The coefficient vector u_h, a global vector

6458:   Output Parameter:
6459: . diff - The array of differences, ||u^f - u^f_h||_2

6461:   Level: developer

6463: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6464: @*/
6465: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6466: {

6472:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6473:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
6474:   return(0);
6475: }

6477: /*@C
6478:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6479:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

6481:   Collective on dm

6483:   Input parameters:
6484: + dm - the pre-adaptation DM object
6485: - label - label with the flags

6487:   Output parameters:
6488: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

6490:   Level: intermediate

6492: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6493: @*/
6494: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6495: {

6502:   *dmAdapt = NULL;
6503:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6504:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
6505:   return(0);
6506: }

6508: /*@C
6509:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

6511:   Input Parameters:
6512: + dm - The DM object
6513: . metric - The metric to which the mesh is adapted, defined vertex-wise.
6514: - 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_".

6516:   Output Parameter:
6517: . dmAdapt  - Pointer to the DM object containing the adapted mesh

6519:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

6521:   Level: advanced

6523: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6524: @*/
6525: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6526: {

6534:   *dmAdapt = NULL;
6535:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6536:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
6537:   return(0);
6538: }

6540: /*@C
6541:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

6543:  Not Collective

6545:  Input Parameter:
6546:  . dm    - The DM

6548:  Output Parameter:
6549:  . nranks - the number of neighbours
6550:  . ranks - the neighbors ranks

6552:  Notes:
6553:  Do not free the array, it is freed when the DM is destroyed.

6555:  Level: beginner

6557:  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6558: @*/
6559: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6560: {

6565:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
6566:   (dm->ops->getneighbors)(dm,nranks,ranks);
6567:   return(0);
6568: }

6570: #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */

6572: /*
6573:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6574:     This has be a different function because it requires DM which is not defined in the Mat library
6575: */
6576: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6577: {

6581:   if (coloring->ctype == IS_COLORING_LOCAL) {
6582:     Vec x1local;
6583:     DM  dm;
6584:     MatGetDM(J,&dm);
6585:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6586:     DMGetLocalVector(dm,&x1local);
6587:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
6588:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
6589:     x1   = x1local;
6590:   }
6591:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
6592:   if (coloring->ctype == IS_COLORING_LOCAL) {
6593:     DM  dm;
6594:     MatGetDM(J,&dm);
6595:     DMRestoreLocalVector(dm,&x1);
6596:   }
6597:   return(0);
6598: }

6600: /*@
6601:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

6603:     Input Parameter:
6604: .    coloring - the MatFDColoring object

6606:     Developer Notes:
6607:     this routine exists because the PETSc Mat library does not know about the DM objects

6609:     Level: advanced

6611: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6612: @*/
6613: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6614: {
6616:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6617:   return(0);
6618: }

6620: /*@
6621:     DMGetCompatibility - determine if two DMs are compatible

6623:     Collective

6625:     Input Parameters:
6626: +    dm - the first DM
6627: -    dm2 - the second DM

6629:     Output Parameters:
6630: +    compatible - whether or not the two DMs are compatible
6631: -    set - whether or not the compatible value was set

6633:     Notes:
6634:     Two DMs are deemed compatible if they represent the same parallel decomposition
6635:     of the same topology. This implies that the the section (field data) on one
6636:     "makes sense" with respect to the topology and parallel decomposition of the other.
6637:     Loosely speaking, compatibile DMs represent the same domain, with the same parallel
6638:     decomposition, with different data.

6640:     Typically, one would confirm compatibility if intending to simultaneously iterate
6641:     over a pair of vectors obtained from different DMs.

6643:     For example, two DMDA objects are compatible if they have the same local
6644:     and global sizes and the same stencil width. They can have different numbers
6645:     of degrees of freedom per node. Thus, one could use the node numbering from
6646:     either DM in bounds for a loop over vectors derived from either DM.

6648:     Consider the operation of summing data living on a 2-dof DMDA to data living
6649:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
6650: .vb
6651:   ...
6652:   DMGetCompatibility(da1,da2,&compatible,&set);
6653:   if (set && compatible)  {
6654:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
6655:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
6656:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n);
6657:     for (j=y; j<y+n; ++j) {
6658:       for (i=x; i<x+m, ++i) {
6659:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
6660:       }
6661:     }
6662:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
6663:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
6664:   } else {
6665:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
6666:   }
6667:   ...
6668: .ve

6670:     Checking compatibility might be expensive for a given implementation of DM,
6671:     or might be impossible to unambiguously confirm or deny. For this reason,
6672:     this function may decline to determine compatibility, and hence users should
6673:     always check the "set" output parameter.

6675:     A DM is always compatible with itself.

6677:     In the current implementation, DMs which live on "unequal" communicators
6678:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
6679:     incompatible.

6681:     This function is labeled "Collective," as information about all subdomains
6682:     is required on each rank. However, in DM implementations which store all this
6683:     information locally, this function may be merely "Logically Collective".

6685:     Developer Notes:
6686:     Compatibility is assumed to be a symmetric concept; if DM A is compatible with DM B,
6687:     the DM B is compatible with DM A. Thus, this function checks the implementations
6688:     of both dm and dm2 (if they are of different types), attempting to determine
6689:     compatibility. It is left to DM implementers to ensure that symmetry is
6690:     preserved. The simplest way to do this is, when implementing type-specific
6691:     logic for this function, to check for existing logic in the implementation
6692:     of other DM types and let *set = PETSC_FALSE if found; the logic of this
6693:     function will then call that logic.

6695:     Level: advanced

6697: .seealso: DM, DMDACreateCompatibleDMDA()
6698: @*/

6700: PetscErrorCode DMGetCompatibility(DM dm,DM dm2,PetscBool *compatible,PetscBool *set)
6701: {
6703:   PetscMPIInt    compareResult;
6704:   DMType         type,type2;
6705:   PetscBool      sameType;


6711:   /* Declare a DM compatible with itself */
6712:   if (dm == dm2) {
6713:     *set = PETSC_TRUE;
6714:     *compatible = PETSC_TRUE;
6715:     return(0);
6716:   }

6718:   /* Declare a DM incompatible with a DM that lives on an "unequal"
6719:      communicator. Note that this does not preclude compatibility with
6720:      DMs living on "congruent" or "similar" communicators, but this must be
6721:      determined by the implementation-specific logic */
6722:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm),PetscObjectComm((PetscObject)dm2),&compareResult);
6723:   if (compareResult == MPI_UNEQUAL) {
6724:     *set = PETSC_TRUE;
6725:     *compatible = PETSC_FALSE;
6726:     return(0);
6727:   }

6729:   /* Pass to the implementation-specific routine, if one exists. */
6730:   if (dm->ops->getcompatibility) {
6731:     (*dm->ops->getcompatibility)(dm,dm2,compatible,set);
6732:     if (*set) {
6733:       return(0);
6734:     }
6735:   }

6737:   /* If dm and dm2 are of different types, then attempt to check compatibility
6738:      with an implementation of this function from dm2 */
6739:   DMGetType(dm,&type);
6740:   DMGetType(dm2,&type2);
6741:   PetscStrcmp(type,type2,&sameType);
6742:   if (!sameType && dm2->ops->getcompatibility) {
6743:     (*dm2->ops->getcompatibility)(dm2,dm,compatible,set); /* Note argument order */
6744:   } else {
6745:     *set = PETSC_FALSE;
6746:   }
6747:   return(0);
6748: }