Actual source code: dm.c

petsc-3.8.3 2017-12-09
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 <petscsf.h>
  6:  #include <petscds.h>

  8: PetscClassId  DM_CLASSID;
  9: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction;

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

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

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

 19:   Collective on MPI_Comm

 21:   Input Parameter:
 22: . comm - The communicator for the DM object

 24:   Output Parameter:
 25: . dm - The DM object

 27:   Level: beginner

 29: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
 30: @*/
 31: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
 32: {
 33:   DM             v;

 38:   *dm = NULL;
 39:   PetscSysInitializePackage();
 40:   VecInitializePackage();
 41:   MatInitializePackage();
 42:   DMInitializePackage();

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

 46:   v->ltogmap                  = NULL;
 47:   v->bs                       = 1;
 48:   v->coloringtype             = IS_COLORING_GLOBAL;
 49:   PetscSFCreate(comm, &v->sf);
 50:   PetscSFCreate(comm, &v->defaultSF);
 51:   v->labels                   = NULL;
 52:   v->depthLabel               = NULL;
 53:   v->defaultSection           = NULL;
 54:   v->defaultGlobalSection     = NULL;
 55:   v->defaultConstraintSection = NULL;
 56:   v->defaultConstraintMat     = NULL;
 57:   v->L                        = NULL;
 58:   v->maxCell                  = NULL;
 59:   v->bdtype                   = NULL;
 60:   v->dimEmbed                 = PETSC_DEFAULT;
 61:   {
 62:     PetscInt i;
 63:     for (i = 0; i < 10; ++i) {
 64:       v->nullspaceConstructors[i] = NULL;
 65:     }
 66:   }
 67:   PetscDSCreate(comm, &v->prob);
 68:   v->dmBC = NULL;
 69:   v->coarseMesh = NULL;
 70:   v->outputSequenceNum = -1;
 71:   v->outputSequenceVal = 0.0;
 72:   DMSetVecType(v,VECSTANDARD);
 73:   DMSetMatType(v,MATAIJ);
 74:   PetscNew(&(v->labels));
 75:   v->labels->refct = 1;
 76:   *dm = v;
 77:   return(0);
 78: }

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

 83:   Collective on MPI_Comm

 85:   Input Parameter:
 86: . dm - The original DM object

 88:   Output Parameter:
 89: . newdm  - The new DM object

 91:   Level: beginner

 93: .keywords: DM, topology, create
 94: @*/
 95: PetscErrorCode DMClone(DM dm, DM *newdm)
 96: {
 97:   PetscSF        sf;
 98:   Vec            coords;
 99:   void          *ctx;
100:   PetscInt       dim, cdim;

106:   DMCreate(PetscObjectComm((PetscObject) dm), newdm);
107:   PetscFree((*newdm)->labels);
108:   dm->labels->refct++;
109:   (*newdm)->labels = dm->labels;
110:   (*newdm)->depthLabel = dm->depthLabel;
111:   DMGetDimension(dm, &dim);
112:   DMSetDimension(*newdm, dim);
113:   if (dm->ops->clone) {
114:     (*dm->ops->clone)(dm, newdm);
115:   }
116:   (*newdm)->setupcalled = dm->setupcalled;
117:   DMGetPointSF(dm, &sf);
118:   DMSetPointSF(*newdm, sf);
119:   DMGetApplicationContext(dm, &ctx);
120:   DMSetApplicationContext(*newdm, ctx);
121:   if (dm->coordinateDM) {
122:     DM           ncdm;
123:     PetscSection cs;
124:     PetscInt     pEnd = -1, pEndMax = -1;

126:     DMGetDefaultSection(dm->coordinateDM, &cs);
127:     if (cs) {PetscSectionGetChart(cs, NULL, &pEnd);}
128:     MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
129:     if (pEndMax >= 0) {
130:       DMClone(dm->coordinateDM, &ncdm);
131:       DMSetDefaultSection(ncdm, cs);
132:       DMSetCoordinateDM(*newdm, ncdm);
133:       DMDestroy(&ncdm);
134:     }
135:   }
136:   DMGetCoordinateDim(dm, &cdim);
137:   DMSetCoordinateDim(*newdm, cdim);
138:   DMGetCoordinatesLocal(dm, &coords);
139:   if (coords) {
140:     DMSetCoordinatesLocal(*newdm, coords);
141:   } else {
142:     DMGetCoordinates(dm, &coords);
143:     if (coords) {DMSetCoordinates(*newdm, coords);}
144:   }
145:   {
146:     PetscBool             isper;
147:     const PetscReal      *maxCell, *L;
148:     const DMBoundaryType *bd;
149:     DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
150:     DMSetPeriodicity(*newdm, isper, maxCell,  L,  bd);
151:   }
152:   return(0);
153: }

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

158:    Logically Collective on DM

160:    Input Parameter:
161: +  da - initial distributed array
162: .  ctype - the vector type, currently either VECSTANDARD or VECCUSP

164:    Options Database:
165: .   -dm_vec_type ctype

167:    Level: intermediate

169: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType()
170: @*/
171: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
172: {

177:   PetscFree(da->vectype);
178:   PetscStrallocpy(ctype,(char**)&da->vectype);
179:   return(0);
180: }

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

185:    Logically Collective on DM

187:    Input Parameter:
188: .  da - initial distributed array

190:    Output Parameter:
191: .  ctype - the vector type

193:    Level: intermediate

195: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType
196: @*/
197: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
198: {
201:   *ctype = da->vectype;
202:   return(0);
203: }

205: /*@
206:   VecGetDM - Gets the DM defining the data layout of the vector

208:   Not collective

210:   Input Parameter:
211: . v - The Vec

213:   Output Parameter:
214: . dm - The DM

216:   Level: intermediate

218: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
219: @*/
220: PetscErrorCode VecGetDM(Vec v, DM *dm)
221: {

227:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
228:   return(0);
229: }

231: /*@
232:   VecSetDM - Sets the DM defining the data layout of the vector.

234:   Not collective

236:   Input Parameters:
237: + v - The Vec
238: - dm - The DM

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

242:   Level: intermediate

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

253:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
254:   return(0);
255: }

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

260:    Logically Collective on DM

262:    Input Parameter:
263: +  dm - the DM context
264: -  ctype - the matrix type

266:    Options Database:
267: .   -dm_mat_type ctype

269:    Level: intermediate

271: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
272: @*/
273: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
274: {

279:   PetscFree(dm->mattype);
280:   PetscStrallocpy(ctype,(char**)&dm->mattype);
281:   return(0);
282: }

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

287:    Logically Collective on DM

289:    Input Parameter:
290: .  dm - the DM context

292:    Output Parameter:
293: .  ctype - the matrix type

295:    Options Database:
296: .   -dm_mat_type ctype

298:    Level: intermediate

300: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType()
301: @*/
302: PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
303: {
306:   *ctype = dm->mattype;
307:   return(0);
308: }

310: /*@
311:   MatGetDM - Gets the DM defining the data layout of the matrix

313:   Not collective

315:   Input Parameter:
316: . A - The Mat

318:   Output Parameter:
319: . dm - The DM

321:   Level: intermediate

323: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
324: @*/
325: PetscErrorCode MatGetDM(Mat A, DM *dm)
326: {

332:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
333:   return(0);
334: }

336: /*@
337:   MatSetDM - Sets the DM defining the data layout of the matrix

339:   Not collective

341:   Input Parameters:
342: + A - The Mat
343: - dm - The DM

345:   Level: intermediate

347: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
348: @*/
349: PetscErrorCode MatSetDM(Mat A, DM dm)
350: {

356:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
357:   return(0);
358: }

360: /*@C
361:    DMSetOptionsPrefix - Sets the prefix used for searching for all
362:    DM options in the database.

364:    Logically Collective on DM

366:    Input Parameter:
367: +  da - the DM context
368: -  prefix - the prefix to prepend to all option names

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

374:    Level: advanced

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

378: .seealso: DMSetFromOptions()
379: @*/
380: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
381: {

386:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
387:   if (dm->sf) {
388:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
389:   }
390:   if (dm->defaultSF) {
391:     PetscObjectSetOptionsPrefix((PetscObject)dm->defaultSF,prefix);
392:   }
393:   return(0);
394: }

396: /*@C
397:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
398:    DM options in the database.

400:    Logically Collective on DM

402:    Input Parameters:
403: +  dm - the DM context
404: -  prefix - the prefix string to prepend to all DM option requests

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

410:    Level: advanced

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

414: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
415: @*/
416: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
417: {

422:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
423:   return(0);
424: }

426: /*@C
427:    DMGetOptionsPrefix - Gets the prefix used for searching for all
428:    DM options in the database.

430:    Not Collective

432:    Input Parameters:
433: .  dm - the DM context

435:    Output Parameters:
436: .  prefix - pointer to the prefix string used is returned

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

441:    Level: advanced

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

445: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
446: @*/
447: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
448: {

453:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
454:   return(0);
455: }

457: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
458: {
459:   PetscInt i, refct = ((PetscObject) dm)->refct;
460:   DMNamedVecLink nlink;

464:   *ncrefct = 0;
465:   /* count all the circular references of DM and its contained Vecs */
466:   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
467:     if (dm->localin[i])  refct--;
468:     if (dm->globalin[i]) refct--;
469:   }
470:   for (nlink=dm->namedglobal; nlink; nlink=nlink->next) refct--;
471:   for (nlink=dm->namedlocal; nlink; nlink=nlink->next) refct--;
472:   if (dm->x) {
473:     DM obj;
474:     VecGetDM(dm->x, &obj);
475:     if (obj == dm) refct--;
476:   }
477:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
478:     refct--;
479:     if (recurseCoarse) {
480:       PetscInt coarseCount;

482:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
483:       refct += coarseCount;
484:     }
485:   }
486:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
487:     refct--;
488:     if (recurseFine) {
489:       PetscInt fineCount;

491:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
492:       refct += fineCount;
493:     }
494:   }
495:   *ncrefct = refct;
496:   return(0);
497: }

499: PetscErrorCode DMDestroyLabelLinkList(DM dm)
500: {

504:   if (!--(dm->labels->refct)) {
505:     DMLabelLink next = dm->labels->next;

507:     /* destroy the labels */
508:     while (next) {
509:       DMLabelLink tmp = next->next;

511:       DMLabelDestroy(&next->label);
512:       PetscFree(next);
513:       next = tmp;
514:     }
515:     PetscFree(dm->labels);
516:   }
517:   return(0);
518: }

520: /*@
521:     DMDestroy - Destroys a vector packer or DM.

523:     Collective on DM

525:     Input Parameter:
526: .   dm - the DM object to destroy

528:     Level: developer

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

532: @*/
533: PetscErrorCode  DMDestroy(DM *dm)
534: {
535:   PetscInt       i, cnt;
536:   DMNamedVecLink nlink,nnext;

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

543:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
544:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
545:   --((PetscObject)(*dm))->refct;
546:   if (--cnt > 0) {*dm = 0; return(0);}
547:   /*
548:      Need this test because the dm references the vectors that
549:      reference the dm, so destroying the dm calls destroy on the
550:      vectors that cause another destroy on the dm
551:   */
552:   if (((PetscObject)(*dm))->refct < 0) return(0);
553:   ((PetscObject) (*dm))->refct = 0;
554:   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
555:     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
556:     VecDestroy(&(*dm)->localin[i]);
557:   }
558:   nnext=(*dm)->namedglobal;
559:   (*dm)->namedglobal = NULL;
560:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
561:     nnext = nlink->next;
562:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
563:     PetscFree(nlink->name);
564:     VecDestroy(&nlink->X);
565:     PetscFree(nlink);
566:   }
567:   nnext=(*dm)->namedlocal;
568:   (*dm)->namedlocal = NULL;
569:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
570:     nnext = nlink->next;
571:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
572:     PetscFree(nlink->name);
573:     VecDestroy(&nlink->X);
574:     PetscFree(nlink);
575:   }

577:   /* Destroy the list of hooks */
578:   {
579:     DMCoarsenHookLink link,next;
580:     for (link=(*dm)->coarsenhook; link; link=next) {
581:       next = link->next;
582:       PetscFree(link);
583:     }
584:     (*dm)->coarsenhook = NULL;
585:   }
586:   {
587:     DMRefineHookLink link,next;
588:     for (link=(*dm)->refinehook; link; link=next) {
589:       next = link->next;
590:       PetscFree(link);
591:     }
592:     (*dm)->refinehook = NULL;
593:   }
594:   {
595:     DMSubDomainHookLink link,next;
596:     for (link=(*dm)->subdomainhook; link; link=next) {
597:       next = link->next;
598:       PetscFree(link);
599:     }
600:     (*dm)->subdomainhook = NULL;
601:   }
602:   {
603:     DMGlobalToLocalHookLink link,next;
604:     for (link=(*dm)->gtolhook; link; link=next) {
605:       next = link->next;
606:       PetscFree(link);
607:     }
608:     (*dm)->gtolhook = NULL;
609:   }
610:   {
611:     DMLocalToGlobalHookLink link,next;
612:     for (link=(*dm)->ltoghook; link; link=next) {
613:       next = link->next;
614:       PetscFree(link);
615:     }
616:     (*dm)->ltoghook = NULL;
617:   }
618:   /* Destroy the work arrays */
619:   {
620:     DMWorkLink link,next;
621:     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
622:     for (link=(*dm)->workin; link; link=next) {
623:       next = link->next;
624:       PetscFree(link->mem);
625:       PetscFree(link);
626:     }
627:     (*dm)->workin = NULL;
628:   }
629:   if (!--((*dm)->labels->refct)) {
630:     DMLabelLink next = (*dm)->labels->next;

632:     /* destroy the labels */
633:     while (next) {
634:       DMLabelLink tmp = next->next;

636:       DMLabelDestroy(&next->label);
637:       PetscFree(next);
638:       next = tmp;
639:     }
640:     PetscFree((*dm)->labels);
641:   }
642:   {
643:     DMBoundary next = (*dm)->boundary;
644:     while (next) {
645:       DMBoundary b = next;

647:       next = b->next;
648:       PetscFree(b);
649:     }
650:   }

652:   PetscObjectDestroy(&(*dm)->dmksp);
653:   PetscObjectDestroy(&(*dm)->dmsnes);
654:   PetscObjectDestroy(&(*dm)->dmts);

656:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
657:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
658:   }
659:   VecDestroy(&(*dm)->x);
660:   MatFDColoringDestroy(&(*dm)->fd);
661:   DMClearGlobalVectors(*dm);
662:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
663:   PetscFree((*dm)->vectype);
664:   PetscFree((*dm)->mattype);

666:   PetscSectionDestroy(&(*dm)->defaultSection);
667:   PetscSectionDestroy(&(*dm)->defaultGlobalSection);
668:   PetscLayoutDestroy(&(*dm)->map);
669:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
670:   MatDestroy(&(*dm)->defaultConstraintMat);
671:   PetscSFDestroy(&(*dm)->sf);
672:   PetscSFDestroy(&(*dm)->defaultSF);
673:   PetscSFDestroy(&(*dm)->sfNatural);

675:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
676:     DMSetFineDM((*dm)->coarseMesh,NULL);
677:   }
678:   DMDestroy(&(*dm)->coarseMesh);
679:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
680:     DMSetCoarseDM((*dm)->fineMesh,NULL);
681:   }
682:   DMDestroy(&(*dm)->fineMesh);
683:   DMDestroy(&(*dm)->coordinateDM);
684:   VecDestroy(&(*dm)->coordinates);
685:   VecDestroy(&(*dm)->coordinatesLocal);
686:   PetscFree3((*dm)->L,(*dm)->maxCell,(*dm)->bdtype);

688:   PetscDSDestroy(&(*dm)->prob);
689:   DMDestroy(&(*dm)->dmBC);
690:   /* if memory was published with SAWs then destroy it */
691:   PetscObjectSAWsViewOff((PetscObject)*dm);

693:   (*(*dm)->ops->destroy)(*dm);
694:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
695:   PetscHeaderDestroy(dm);
696:   return(0);
697: }

699: /*@
700:     DMSetUp - sets up the data structures inside a DM object

702:     Collective on DM

704:     Input Parameter:
705: .   dm - the DM object to setup

707:     Level: developer

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

711: @*/
712: PetscErrorCode  DMSetUp(DM dm)
713: {

718:   if (dm->setupcalled) return(0);
719:   if (dm->ops->setup) {
720:     (*dm->ops->setup)(dm);
721:   }
722:   dm->setupcalled = PETSC_TRUE;
723:   return(0);
724: }

726: /*@
727:     DMSetFromOptions - sets parameters in a DM from the options database

729:     Collective on DM

731:     Input Parameter:
732: .   dm - the DM object to set options for

734:     Options Database:
735: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
736: .   -dm_vec_type <type>  - type of vector to create inside DM
737: .   -dm_mat_type <type>  - type of matrix to create inside DM
738: -   -dm_coloring_type    - <global or ghosted>

740:     Level: developer

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

744: @*/
745: PetscErrorCode  DMSetFromOptions(DM dm)
746: {
747:   char           typeName[256];
748:   PetscBool      flg;

753:   if (dm->prob) {
754:     PetscDSSetFromOptions(dm->prob);
755:   }
756:   if (dm->sf) {
757:     PetscSFSetFromOptions(dm->sf);
758:   }
759:   if (dm->defaultSF) {
760:     PetscSFSetFromOptions(dm->defaultSF);
761:   }
762:   PetscObjectOptionsBegin((PetscObject)dm);
763:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
764:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
765:   if (flg) {
766:     DMSetVecType(dm,typeName);
767:   }
768:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
769:   if (flg) {
770:     DMSetMatType(dm,typeName);
771:   }
772:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","ISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
773:   if (dm->ops->setfromoptions) {
774:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
775:   }
776:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
777:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
778:   PetscOptionsEnd();
779:   return(0);
780: }

782: /*@C
783:     DMView - Views a DM

785:     Collective on DM

787:     Input Parameter:
788: +   dm - the DM object to view
789: -   v - the viewer

791:     Level: beginner

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

795: @*/
796: PetscErrorCode  DMView(DM dm,PetscViewer v)
797: {
799:   PetscBool      isbinary;

803:   if (!v) {
804:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
805:   }
806:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
807:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
808:   if (isbinary) {
809:     PetscInt classid = DM_FILE_CLASSID;
810:     char     type[256];

812:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);
813:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
814:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);
815:   }
816:   if (dm->ops->view) {
817:     (*dm->ops->view)(dm,v);
818:   }
819:   return(0);
820: }

822: /*@
823:     DMCreateGlobalVector - Creates a global vector from a DM object

825:     Collective on DM

827:     Input Parameter:
828: .   dm - the DM object

830:     Output Parameter:
831: .   vec - the global vector

833:     Level: beginner

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

837: @*/
838: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
839: {

844:   (*dm->ops->createglobalvector)(dm,vec);
845:   return(0);
846: }

848: /*@
849:     DMCreateLocalVector - Creates a local vector from a DM object

851:     Not Collective

853:     Input Parameter:
854: .   dm - the DM object

856:     Output Parameter:
857: .   vec - the local vector

859:     Level: beginner

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

863: @*/
864: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
865: {

870:   (*dm->ops->createlocalvector)(dm,vec);
871:   return(0);
872: }

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

877:    Collective on DM

879:    Input Parameter:
880: .  dm - the DM that provides the mapping

882:    Output Parameter:
883: .  ltog - the mapping

885:    Level: intermediate

887:    Notes:
888:    This mapping can then be used by VecSetLocalToGlobalMapping() or
889:    MatSetLocalToGlobalMapping().

891: .seealso: DMCreateLocalVector()
892: @*/
893: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
894: {
895:   PetscInt       bs = -1, bsLocal, bsMin, bsMax;

901:   if (!dm->ltogmap) {
902:     PetscSection section, sectionGlobal;

904:     DMGetDefaultSection(dm, &section);
905:     if (section) {
906:       const PetscInt *cdofs;
907:       PetscInt       *ltog;
908:       PetscInt        pStart, pEnd, n, p, k, l;

910:       DMGetDefaultGlobalSection(dm, &sectionGlobal);
911:       PetscSectionGetChart(section, &pStart, &pEnd);
912:       PetscSectionGetStorageSize(section, &n);
913:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
914:       for (p = pStart, l = 0; p < pEnd; ++p) {
915:         PetscInt bdof, cdof, dof, off, c, cind = 0;

917:         /* Should probably use constrained dofs */
918:         PetscSectionGetDof(section, p, &dof);
919:         PetscSectionGetConstraintDof(section, p, &cdof);
920:         PetscSectionGetConstraintIndices(section, p, &cdofs);
921:         PetscSectionGetOffset(sectionGlobal, p, &off);
922:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
923:         bdof = cdof && (dof-cdof) ? 1 : dof;
924:         if (dof) {
925:           if (bs < 0)          {bs = bdof;}
926:           else if (bs != bdof) {bs = 1;}
927:         }
928:         for (c = 0; c < dof; ++c, ++l) {
929:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
930:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
931:         }
932:       }
933:       /* Must have same blocksize on all procs (some might have no points) */
934:       bsLocal = bs;
935:       MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
936:       bsLocal = bs < 0 ? bsMax : bs;
937:       MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));
938:       if (bsMin != bsMax) {bs = 1;}
939:       else                {bs = bsMax;}
940:       bs   = bs < 0 ? 1 : bs;
941:       /* Must reduce indices by blocksize */
942:       if (bs > 1) {
943:         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
944:         n /= bs;
945:       }
946:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
947:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
948:     } else {
949:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
950:       (*dm->ops->getlocaltoglobalmapping)(dm);
951:     }
952:   }
953:   *ltog = dm->ltogmap;
954:   return(0);
955: }

957: /*@
958:    DMGetBlockSize - Gets the inherent block size associated with a DM

960:    Not Collective

962:    Input Parameter:
963: .  dm - the DM with block structure

965:    Output Parameter:
966: .  bs - the block size, 1 implies no exploitable block structure

968:    Level: intermediate

970: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
971: @*/
972: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
973: {
977:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
978:   *bs = dm->bs;
979:   return(0);
980: }

982: /*@
983:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

985:     Collective on DM

987:     Input Parameter:
988: +   dm1 - the DM object
989: -   dm2 - the second, finer DM object

991:     Output Parameter:
992: +  mat - the interpolation
993: -  vec - the scaling (optional)

995:     Level: developer

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

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


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

1006: @*/
1007: PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
1008: {

1014:   PetscLogEventBegin(DM_CreateInterpolation,dm1,dm2,0,0);
1015:   (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);
1016:   PetscLogEventEnd(DM_CreateInterpolation,dm1,dm2,0,0);
1017:   return(0);
1018: }

1020: /*@
1021:     DMCreateRestriction - Gets restriction matrix between two DM objects

1023:     Collective on DM

1025:     Input Parameter:
1026: +   dm1 - the DM object
1027: -   dm2 - the second, finer DM object

1029:     Output Parameter:
1030: .  mat - the restriction


1033:     Level: developer

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


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

1041: @*/
1042: PetscErrorCode  DMCreateRestriction(DM dm1,DM dm2,Mat *mat)
1043: {

1049:   PetscLogEventBegin(DM_CreateRestriction,dm1,dm2,0,0);
1050:   if (!dm1->ops->createrestriction) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateRestriction not implemented for this type");
1051:   (*dm1->ops->createrestriction)(dm1,dm2,mat);
1052:   PetscLogEventEnd(DM_CreateRestriction,dm1,dm2,0,0);
1053:   return(0);
1054: }

1056: /*@
1057:     DMCreateInjection - Gets injection matrix between two DM objects

1059:     Collective on DM

1061:     Input Parameter:
1062: +   dm1 - the DM object
1063: -   dm2 - the second, finer DM object

1065:     Output Parameter:
1066: .   mat - the injection

1068:     Level: developer

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

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

1075: @*/
1076: PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,Mat *mat)
1077: {

1083:   if (!dm1->ops->getinjection) SETERRQ(PetscObjectComm((PetscObject)dm1),PETSC_ERR_SUP,"DMCreateInjection not implemented for this type");
1084:   (*dm1->ops->getinjection)(dm1,dm2,mat);
1085:   return(0);
1086: }

1088: /*@
1089:     DMCreateColoring - Gets coloring for a DM

1091:     Collective on DM

1093:     Input Parameter:
1094: +   dm - the DM object
1095: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1097:     Output Parameter:
1098: .   coloring - the coloring

1100:     Level: developer

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

1104: @*/
1105: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1106: {

1111:   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
1112:   (*dm->ops->getcoloring)(dm,ctype,coloring);
1113:   return(0);
1114: }

1116: /*@
1117:     DMCreateMatrix - Gets empty Jacobian for a DM

1119:     Collective on DM

1121:     Input Parameter:
1122: .   dm - the DM object

1124:     Output Parameter:
1125: .   mat - the empty Jacobian

1127:     Level: beginner

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

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

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

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

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

1143: @*/
1144: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1145: {

1150:   MatInitializePackage();
1153:   (*dm->ops->creatematrix)(dm,mat);
1154:   return(0);
1155: }

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

1161:   Logically Collective on DM

1163:   Input Parameter:
1164: + dm - the DM
1165: - only - PETSC_TRUE if only want preallocation

1167:   Level: developer
1168: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1169: @*/
1170: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1171: {
1174:   dm->prealloc_only = only;
1175:   return(0);
1176: }

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

1182:   Logically Collective on DM

1184:   Input Parameter:
1185: + dm - the DM
1186: - only - PETSC_TRUE if only want matrix stucture

1188:   Level: developer
1189: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1190: @*/
1191: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1192: {
1195:   dm->structure_only = only;
1196:   return(0);
1197: }

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

1202:   Not Collective

1204:   Input Parameters:
1205: + dm - the DM object
1206: . count - The minium size
1207: - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)

1209:   Output Parameter:
1210: . array - the work array

1212:   Level: developer

1214: .seealso DMDestroy(), DMCreate()
1215: @*/
1216: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1217: {
1219:   DMWorkLink     link;
1220:   size_t         dsize;

1225:   if (dm->workin) {
1226:     link       = dm->workin;
1227:     dm->workin = dm->workin->next;
1228:   } else {
1229:     PetscNewLog(dm,&link);
1230:   }
1231:   PetscDataTypeGetSize(dtype,&dsize);
1232:   if (dsize*count > link->bytes) {
1233:     PetscFree(link->mem);
1234:     PetscMalloc(dsize*count,&link->mem);
1235:     link->bytes = dsize*count;
1236:   }
1237:   link->next   = dm->workout;
1238:   dm->workout  = link;
1239:   *(void**)mem = link->mem;
1240:   return(0);
1241: }

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

1246:   Not Collective

1248:   Input Parameters:
1249: + dm - the DM object
1250: . count - The minium size
1251: - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)

1253:   Output Parameter:
1254: . array - the work array

1256:   Level: developer

1258: .seealso DMDestroy(), DMCreate()
1259: @*/
1260: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1261: {
1262:   DMWorkLink *p,link;

1267:   for (p=&dm->workout; (link=*p); p=&link->next) {
1268:     if (link->mem == *(void**)mem) {
1269:       *p           = link->next;
1270:       link->next   = dm->workin;
1271:       dm->workin   = link;
1272:       *(void**)mem = NULL;
1273:       return(0);
1274:     }
1275:   }
1276:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1277: }

1279: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1280: {
1283:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1284:   dm->nullspaceConstructors[field] = nullsp;
1285:   return(0);
1286: }

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

1291:   Not collective

1293:   Input Parameter:
1294: . dm - the DM object

1296:   Output Parameters:
1297: + numFields  - The number of fields (or NULL if not requested)
1298: . fieldNames - The name for each field (or NULL if not requested)
1299: - fields     - The global indices for each field (or NULL if not requested)

1301:   Level: intermediate

1303:   Notes:
1304:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1305:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1306:   PetscFree().

1308: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1309: @*/
1310: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1311: {
1312:   PetscSection   section, sectionGlobal;

1317:   if (numFields) {
1319:     *numFields = 0;
1320:   }
1321:   if (fieldNames) {
1323:     *fieldNames = NULL;
1324:   }
1325:   if (fields) {
1327:     *fields = NULL;
1328:   }
1329:   DMGetDefaultSection(dm, &section);
1330:   if (section) {
1331:     PetscInt *fieldSizes, **fieldIndices;
1332:     PetscInt nF, f, pStart, pEnd, p;

1334:     DMGetDefaultGlobalSection(dm, &sectionGlobal);
1335:     PetscSectionGetNumFields(section, &nF);
1336:     PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);
1337:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1338:     for (f = 0; f < nF; ++f) {
1339:       fieldSizes[f] = 0;
1340:     }
1341:     for (p = pStart; p < pEnd; ++p) {
1342:       PetscInt gdof;

1344:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1345:       if (gdof > 0) {
1346:         for (f = 0; f < nF; ++f) {
1347:           PetscInt fdof, fcdof;

1349:           PetscSectionGetFieldDof(section, p, f, &fdof);
1350:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1351:           fieldSizes[f] += fdof-fcdof;
1352:         }
1353:       }
1354:     }
1355:     for (f = 0; f < nF; ++f) {
1356:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1357:       fieldSizes[f] = 0;
1358:     }
1359:     for (p = pStart; p < pEnd; ++p) {
1360:       PetscInt gdof, goff;

1362:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1363:       if (gdof > 0) {
1364:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1365:         for (f = 0; f < nF; ++f) {
1366:           PetscInt fdof, fcdof, fc;

1368:           PetscSectionGetFieldDof(section, p, f, &fdof);
1369:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1370:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1371:             fieldIndices[f][fieldSizes[f]] = goff++;
1372:           }
1373:         }
1374:       }
1375:     }
1376:     if (numFields) *numFields = nF;
1377:     if (fieldNames) {
1378:       PetscMalloc1(nF, fieldNames);
1379:       for (f = 0; f < nF; ++f) {
1380:         const char *fieldName;

1382:         PetscSectionGetFieldName(section, f, &fieldName);
1383:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1384:       }
1385:     }
1386:     if (fields) {
1387:       PetscMalloc1(nF, fields);
1388:       for (f = 0; f < nF; ++f) {
1389:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1390:       }
1391:     }
1392:     PetscFree2(fieldSizes,fieldIndices);
1393:   } else if (dm->ops->createfieldis) {
1394:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1395:   }
1396:   return(0);
1397: }


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

1406:   Not collective

1408:   Input Parameter:
1409: . dm - the DM object

1411:   Output Parameters:
1412: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1413: . namelist  - The name for each field (or NULL if not requested)
1414: . islist    - The global indices for each field (or NULL if not requested)
1415: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1417:   Level: intermediate

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

1424: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1425: @*/
1426: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1427: {

1432:   if (len) {
1434:     *len = 0;
1435:   }
1436:   if (namelist) {
1438:     *namelist = 0;
1439:   }
1440:   if (islist) {
1442:     *islist = 0;
1443:   }
1444:   if (dmlist) {
1446:     *dmlist = 0;
1447:   }
1448:   /*
1449:    Is it a good idea to apply the following check across all impls?
1450:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1451:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1452:    */
1453:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1454:   if (!dm->ops->createfielddecomposition) {
1455:     PetscSection section;
1456:     PetscInt     numFields, f;

1458:     DMGetDefaultSection(dm, &section);
1459:     if (section) {PetscSectionGetNumFields(section, &numFields);}
1460:     if (section && numFields && dm->ops->createsubdm) {
1461:       if (len) *len = numFields;
1462:       if (namelist) {PetscMalloc1(numFields,namelist);}
1463:       if (islist)   {PetscMalloc1(numFields,islist);}
1464:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
1465:       for (f = 0; f < numFields; ++f) {
1466:         const char *fieldName;

1468:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1469:         if (namelist) {
1470:           PetscSectionGetFieldName(section, f, &fieldName);
1471:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1472:         }
1473:       }
1474:     } else {
1475:       DMCreateFieldIS(dm, len, namelist, islist);
1476:       /* By default there are no DMs associated with subproblems. */
1477:       if (dmlist) *dmlist = NULL;
1478:     }
1479:   } else {
1480:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1481:   }
1482:   return(0);
1483: }

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

1489:   Not collective

1491:   Input Parameters:
1492: + dm - the DM object
1493: . numFields - the number of fields in this subproblem
1494: - fields - the fields in the subproblem

1496:   Output Parameters:
1497: + is - the global indices for the subproblem
1498: - dm - the DM for the subproblem

1500:   Level: intermediate

1502: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1503: @*/
1504: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1505: {

1513:   if (dm->ops->createsubdm) {
1514:     (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1515:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1516:   return(0);
1517: }


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

1527:   Not collective

1529:   Input Parameter:
1530: . dm - the DM object

1532:   Output Parameters:
1533: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1534: . namelist    - The name for each subdomain (or NULL if not requested)
1535: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1536: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1537: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1539:   Level: intermediate

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

1546: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1547: @*/
1548: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1549: {
1550:   PetscErrorCode      ierr;
1551:   DMSubDomainHookLink link;
1552:   PetscInt            i,l;

1561:   /*
1562:    Is it a good idea to apply the following check across all impls?
1563:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1564:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1565:    */
1566:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1567:   if (dm->ops->createdomaindecomposition) {
1568:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
1569:     /* copy subdomain hooks and context over to the subdomain DMs */
1570:     if (dmlist && *dmlist) {
1571:       for (i = 0; i < l; i++) {
1572:         for (link=dm->subdomainhook; link; link=link->next) {
1573:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
1574:         }
1575:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
1576:       }
1577:     }
1578:     if (len) *len = l;
1579:   }
1580:   return(0);
1581: }


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

1587:   Not collective

1589:   Input Parameters:
1590: + dm - the DM object
1591: . n  - the number of subdomain scatters
1592: - subdms - the local subdomains

1594:   Output Parameters:
1595: + n     - the number of scatters returned
1596: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1597: . oscat - scatter from global vector to overlapping global vector entries on subdomain
1598: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

1605:   Level: developer

1607: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1608: @*/
1609: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1610: {

1616:   if (dm->ops->createddscatters) {
1617:     (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
1618:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionScatter implementation defined");
1619:   return(0);
1620: }

1622: /*@
1623:   DMRefine - Refines a DM object

1625:   Collective on DM

1627:   Input Parameter:
1628: + dm   - the DM object
1629: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

1631:   Output Parameter:
1632: . dmf - the refined DM, or NULL

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

1636:   Level: developer

1638: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1639: @*/
1640: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1641: {
1642:   PetscErrorCode   ierr;
1643:   DMRefineHookLink link;

1647:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
1648:   if (!dm->ops->refine) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot refine");
1649:   (*dm->ops->refine)(dm,comm,dmf);
1650:   if (*dmf) {
1651:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

1655:     (*dmf)->ctx       = dm->ctx;
1656:     (*dmf)->leveldown = dm->leveldown;
1657:     (*dmf)->levelup   = dm->levelup + 1;

1659:     DMSetMatType(*dmf,dm->mattype);
1660:     for (link=dm->refinehook; link; link=link->next) {
1661:       if (link->refinehook) {
1662:         (*link->refinehook)(dm,*dmf,link->ctx);
1663:       }
1664:     }
1665:   }
1666:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
1667:   return(0);
1668: }

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

1673:    Logically Collective

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

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

1684: +  coarse - coarse level DM
1685: .  fine - fine level DM to interpolate problem to
1686: -  ctx - optional user-defined function context

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

1691: +  coarse - coarse level DM
1692: .  interp - matrix interpolating a coarse-level solution to the finer grid
1693: .  fine - fine level DM to update
1694: -  ctx - optional user-defined function context

1696:    Level: advanced

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

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

1703:    This function is currently not available from Fortran.

1705: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1706: @*/
1707: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1708: {
1709:   PetscErrorCode   ierr;
1710:   DMRefineHookLink link,*p;

1714:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
1715:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
1716:   }
1717:   PetscNew(&link);
1718:   link->refinehook = refinehook;
1719:   link->interphook = interphook;
1720:   link->ctx        = ctx;
1721:   link->next       = NULL;
1722:   *p               = link;
1723:   return(0);
1724: }

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

1729:    Logically Collective

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

1737:    Level: advanced

1739:    Notes:
1740:    This function does nothing if the hook is not in the list.

1742:    This function is currently not available from Fortran.

1744: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1745: @*/
1746: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1747: {
1748:   PetscErrorCode   ierr;
1749:   DMRefineHookLink link,*p;

1753:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
1754:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
1755:       link = *p;
1756:       *p = link->next;
1757:       PetscFree(link);
1758:       break;
1759:     }
1760:   }
1761:   return(0);
1762: }

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

1767:    Collective if any hooks are

1769:    Input Arguments:
1770: +  coarse - coarser DM to use as a base
1771: .  interp - interpolation matrix, apply using MatInterpolate()
1772: -  fine - finer DM to update

1774:    Level: developer

1776: .seealso: DMRefineHookAdd(), MatInterpolate()
1777: @*/
1778: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1779: {
1780:   PetscErrorCode   ierr;
1781:   DMRefineHookLink link;

1784:   for (link=fine->refinehook; link; link=link->next) {
1785:     if (link->interphook) {
1786:       (*link->interphook)(coarse,interp,fine,link->ctx);
1787:     }
1788:   }
1789:   return(0);
1790: }

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

1795:     Not Collective

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

1800:     Output Parameter:
1801: .   level - number of refinements

1803:     Level: developer

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

1807: @*/
1808: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1809: {
1812:   *level = dm->levelup;
1813:   return(0);
1814: }

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

1819:     Not Collective

1821:     Input Parameter:
1822: +   dm - the DM object
1823: -   level - number of refinements

1825:     Level: advanced

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

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

1831: @*/
1832: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
1833: {
1836:   dm->levelup = level;
1837:   return(0);
1838: }

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

1843:    Logically Collective

1845:    Input Arguments:
1846: +  dm - the DM
1847: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
1848: .  endhook - function to run after DMGlobalToLocalEnd() has completed
1849: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

1854: +  dm - global DM
1855: .  g - global vector
1856: .  mode - mode
1857: .  l - local vector
1858: -  ctx - optional user-defined function context


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

1864: +  global - global DM
1865: -  ctx - optional user-defined function context

1867:    Level: advanced

1869: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1870: @*/
1871: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1872: {
1873:   PetscErrorCode          ierr;
1874:   DMGlobalToLocalHookLink link,*p;

1878:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1879:   PetscNew(&link);
1880:   link->beginhook = beginhook;
1881:   link->endhook   = endhook;
1882:   link->ctx       = ctx;
1883:   link->next      = NULL;
1884:   *p              = link;
1885:   return(0);
1886: }

1888: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
1889: {
1890:   Mat cMat;
1891:   Vec cVec;
1892:   PetscSection section, cSec;
1893:   PetscInt pStart, pEnd, p, dof;

1898:   DMGetDefaultConstraints(dm,&cSec,&cMat);
1899:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
1900:     PetscInt nRows;

1902:     MatGetSize(cMat,&nRows,NULL);
1903:     if (nRows <= 0) return(0);
1904:     DMGetDefaultSection(dm,&section);
1905:     MatCreateVecs(cMat,NULL,&cVec);
1906:     MatMult(cMat,l,cVec);
1907:     PetscSectionGetChart(cSec,&pStart,&pEnd);
1908:     for (p = pStart; p < pEnd; p++) {
1909:       PetscSectionGetDof(cSec,p,&dof);
1910:       if (dof) {
1911:         PetscScalar *vals;
1912:         VecGetValuesSection(cVec,cSec,p,&vals);
1913:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
1914:       }
1915:     }
1916:     VecDestroy(&cVec);
1917:   }
1918:   return(0);
1919: }

1921: /*@
1922:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

1924:     Neighbor-wise Collective on DM

1926:     Input Parameters:
1927: +   dm - the DM object
1928: .   g - the global vector
1929: .   mode - INSERT_VALUES or ADD_VALUES
1930: -   l - the local vector


1933:     Level: beginner

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

1937: @*/
1938: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1939: {
1940:   PetscSF                 sf;
1941:   PetscErrorCode          ierr;
1942:   DMGlobalToLocalHookLink link;

1946:   for (link=dm->gtolhook; link; link=link->next) {
1947:     if (link->beginhook) {
1948:       (*link->beginhook)(dm,g,mode,l,link->ctx);
1949:     }
1950:   }
1951:   DMGetDefaultSF(dm, &sf);
1952:   if (sf) {
1953:     const PetscScalar *gArray;
1954:     PetscScalar       *lArray;

1956:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1957:     VecGetArray(l, &lArray);
1958:     VecGetArrayRead(g, &gArray);
1959:     PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);
1960:     VecRestoreArray(l, &lArray);
1961:     VecRestoreArrayRead(g, &gArray);
1962:   } else {
1963:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
1964:   }
1965:   return(0);
1966: }

1968: /*@
1969:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

1971:     Neighbor-wise Collective on DM

1973:     Input Parameters:
1974: +   dm - the DM object
1975: .   g - the global vector
1976: .   mode - INSERT_VALUES or ADD_VALUES
1977: -   l - the local vector


1980:     Level: beginner

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

1984: @*/
1985: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1986: {
1987:   PetscSF                 sf;
1988:   PetscErrorCode          ierr;
1989:   const PetscScalar      *gArray;
1990:   PetscScalar            *lArray;
1991:   DMGlobalToLocalHookLink link;

1995:   DMGetDefaultSF(dm, &sf);
1996:   if (sf) {
1997:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

1999:     VecGetArray(l, &lArray);
2000:     VecGetArrayRead(g, &gArray);
2001:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
2002:     VecRestoreArray(l, &lArray);
2003:     VecRestoreArrayRead(g, &gArray);
2004:   } else {
2005:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2006:   }
2007:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2008:   for (link=dm->gtolhook; link; link=link->next) {
2009:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2010:   }
2011:   return(0);
2012: }

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

2017:    Logically Collective

2019:    Input Arguments:
2020: +  dm - the DM
2021: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2022: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2023: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2028: +  dm - global DM
2029: .  l - local vector
2030: .  mode - mode
2031: .  g - global vector
2032: -  ctx - optional user-defined function context


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

2038: +  global - global DM
2039: .  l - local vector
2040: .  mode - mode
2041: .  g - global vector
2042: -  ctx - optional user-defined function context

2044:    Level: advanced

2046: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2047: @*/
2048: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2049: {
2050:   PetscErrorCode          ierr;
2051:   DMLocalToGlobalHookLink link,*p;

2055:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2056:   PetscNew(&link);
2057:   link->beginhook = beginhook;
2058:   link->endhook   = endhook;
2059:   link->ctx       = ctx;
2060:   link->next      = NULL;
2061:   *p              = link;
2062:   return(0);
2063: }

2065: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2066: {
2067:   Mat cMat;
2068:   Vec cVec;
2069:   PetscSection section, cSec;
2070:   PetscInt pStart, pEnd, p, dof;

2075:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2076:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2077:     PetscInt nRows;

2079:     MatGetSize(cMat,&nRows,NULL);
2080:     if (nRows <= 0) return(0);
2081:     DMGetDefaultSection(dm,&section);
2082:     MatCreateVecs(cMat,NULL,&cVec);
2083:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2084:     for (p = pStart; p < pEnd; p++) {
2085:       PetscSectionGetDof(cSec,p,&dof);
2086:       if (dof) {
2087:         PetscInt d;
2088:         PetscScalar *vals;
2089:         VecGetValuesSection(l,section,p,&vals);
2090:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2091:         /* for this to be the true transpose, we have to zero the values that
2092:          * we just extracted */
2093:         for (d = 0; d < dof; d++) {
2094:           vals[d] = 0.;
2095:         }
2096:       }
2097:     }
2098:     MatMultTransposeAdd(cMat,cVec,l,l);
2099:     VecDestroy(&cVec);
2100:   }
2101:   return(0);
2102: }

2104: /*@
2105:     DMLocalToGlobalBegin - updates global vectors from local vectors

2107:     Neighbor-wise Collective on DM

2109:     Input Parameters:
2110: +   dm - the DM object
2111: .   l - the local vector
2112: .   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.
2113: -   g - the global vector

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

2118:     Level: beginner

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

2122: @*/
2123: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2124: {
2125:   PetscSF                 sf;
2126:   PetscSection            s, gs;
2127:   DMLocalToGlobalHookLink link;
2128:   const PetscScalar      *lArray;
2129:   PetscScalar            *gArray;
2130:   PetscBool               isInsert;
2131:   PetscErrorCode          ierr;

2135:   for (link=dm->ltoghook; link; link=link->next) {
2136:     if (link->beginhook) {
2137:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2138:     }
2139:   }
2140:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2141:   DMGetDefaultSF(dm, &sf);
2142:   DMGetDefaultSection(dm, &s);
2143:   switch (mode) {
2144:   case INSERT_VALUES:
2145:   case INSERT_ALL_VALUES:
2146:   case INSERT_BC_VALUES:
2147:     isInsert = PETSC_TRUE; break;
2148:   case ADD_VALUES:
2149:   case ADD_ALL_VALUES:
2150:   case ADD_BC_VALUES:
2151:     isInsert = PETSC_FALSE; break;
2152:   default:
2153:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2154:   }
2155:   if (sf && !isInsert) {
2156:     VecGetArrayRead(l, &lArray);
2157:     VecGetArray(g, &gArray);
2158:     PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2159:     VecRestoreArrayRead(l, &lArray);
2160:     VecRestoreArray(g, &gArray);
2161:   } else if (s && isInsert) {
2162:     PetscInt gStart, pStart, pEnd, p;

2164:     DMGetDefaultGlobalSection(dm, &gs);
2165:     PetscSectionGetChart(s, &pStart, &pEnd);
2166:     VecGetOwnershipRange(g, &gStart, NULL);
2167:     VecGetArrayRead(l, &lArray);
2168:     VecGetArray(g, &gArray);
2169:     for (p = pStart; p < pEnd; ++p) {
2170:       PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2172:       PetscSectionGetDof(s, p, &dof);
2173:       PetscSectionGetDof(gs, p, &gdof);
2174:       PetscSectionGetConstraintDof(s, p, &cdof);
2175:       PetscSectionGetConstraintDof(gs, p, &gcdof);
2176:       PetscSectionGetOffset(s, p, &off);
2177:       PetscSectionGetOffset(gs, p, &goff);
2178:       /* Ignore off-process data and points with no global data */
2179:       if (!gdof || goff < 0) continue;
2180:       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);
2181:       /* If no constraints are enforced in the global vector */
2182:       if (!gcdof) {
2183:         for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2184:       /* If constraints are enforced in the global vector */
2185:       } else if (cdof == gcdof) {
2186:         const PetscInt *cdofs;
2187:         PetscInt        cind = 0;

2189:         PetscSectionGetConstraintIndices(s, p, &cdofs);
2190:         for (d = 0, e = 0; d < dof; ++d) {
2191:           if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2192:           gArray[goff-gStart+e++] = lArray[off+d];
2193:         }
2194:       } 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);
2195:     }
2196:     VecRestoreArrayRead(l, &lArray);
2197:     VecRestoreArray(g, &gArray);
2198:   } else {
2199:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2200:   }
2201:   return(0);
2202: }

2204: /*@
2205:     DMLocalToGlobalEnd - updates global vectors from local vectors

2207:     Neighbor-wise Collective on DM

2209:     Input Parameters:
2210: +   dm - the DM object
2211: .   l - the local vector
2212: .   mode - INSERT_VALUES or ADD_VALUES
2213: -   g - the global vector


2216:     Level: beginner

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

2220: @*/
2221: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2222: {
2223:   PetscSF                 sf;
2224:   PetscSection            s;
2225:   DMLocalToGlobalHookLink link;
2226:   PetscBool               isInsert;
2227:   PetscErrorCode          ierr;

2231:   DMGetDefaultSF(dm, &sf);
2232:   DMGetDefaultSection(dm, &s);
2233:   switch (mode) {
2234:   case INSERT_VALUES:
2235:   case INSERT_ALL_VALUES:
2236:     isInsert = PETSC_TRUE; break;
2237:   case ADD_VALUES:
2238:   case ADD_ALL_VALUES:
2239:     isInsert = PETSC_FALSE; break;
2240:   default:
2241:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2242:   }
2243:   if (sf && !isInsert) {
2244:     const PetscScalar *lArray;
2245:     PetscScalar       *gArray;

2247:     VecGetArrayRead(l, &lArray);
2248:     VecGetArray(g, &gArray);
2249:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2250:     VecRestoreArrayRead(l, &lArray);
2251:     VecRestoreArray(g, &gArray);
2252:   } else if (s && isInsert) {
2253:   } else {
2254:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2255:   }
2256:   for (link=dm->ltoghook; link; link=link->next) {
2257:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
2258:   }
2259:   return(0);
2260: }

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

2267:    Neighbor-wise Collective on DM and Vec

2269:    Input Parameters:
2270: +  dm - the DM object
2271: .  g - the original local vector
2272: -  mode - one of INSERT_VALUES or ADD_VALUES

2274:    Output Parameter:
2275: .  l  - the local vector with correct ghost values

2277:    Level: intermediate

2279:    Notes:
2280:    The local vectors used here need not be the same as those
2281:    obtained from DMCreateLocalVector(), BUT they
2282:    must have the same parallel data layout; they could, for example, be
2283:    obtained with VecDuplicate() from the DM originating vectors.

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

2288: @*/
2289: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2290: {
2291:   PetscErrorCode          ierr;

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

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

2305:    Neighbor-wise Collective on DM and Vec

2307:    Input Parameters:
2308: +  da - the DM object
2309: .  g - the original local vector
2310: -  mode - one of INSERT_VALUES or ADD_VALUES

2312:    Output Parameter:
2313: .  l  - the local vector with correct ghost values

2315:    Level: intermediate

2317:    Notes:
2318:    The local vectors used here need not be the same as those
2319:    obtained from DMCreateLocalVector(), BUT they
2320:    must have the same parallel data layout; they could, for example, be
2321:    obtained with VecDuplicate() from the DM originating vectors.

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

2326: @*/
2327: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2328: {
2329:   PetscErrorCode          ierr;

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


2339: /*@
2340:     DMCoarsen - Coarsens a DM object

2342:     Collective on DM

2344:     Input Parameter:
2345: +   dm - the DM object
2346: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2348:     Output Parameter:
2349: .   dmc - the coarsened DM

2351:     Level: developer

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

2355: @*/
2356: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2357: {
2358:   PetscErrorCode    ierr;
2359:   DMCoarsenHookLink link;

2363:   if (!dm->ops->coarsen) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"This DM cannot coarsen");
2364:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
2365:   (*dm->ops->coarsen)(dm, comm, dmc);
2366:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
2367:   DMSetCoarseDM(dm,*dmc);
2368:   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
2369:   PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
2370:   (*dmc)->ctx               = dm->ctx;
2371:   (*dmc)->levelup           = dm->levelup;
2372:   (*dmc)->leveldown         = dm->leveldown + 1;
2373:   DMSetMatType(*dmc,dm->mattype);
2374:   for (link=dm->coarsenhook; link; link=link->next) {
2375:     if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
2376:   }
2377:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
2378:   return(0);
2379: }

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

2384:    Logically Collective

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

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

2395: +  fine - fine level DM
2396: .  coarse - coarse level DM to restrict problem to
2397: -  ctx - optional user-defined function context

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

2402: +  fine - fine level DM
2403: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2404: .  rscale - scaling vector for restriction
2405: .  inject - matrix restricting by injection
2406: .  coarse - coarse level DM to update
2407: -  ctx - optional user-defined function context

2409:    Level: advanced

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

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

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

2419:    This function is currently not available from Fortran.

2421: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2422: @*/
2423: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2424: {
2425:   PetscErrorCode    ierr;
2426:   DMCoarsenHookLink link,*p;

2430:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2431:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2432:   }
2433:   PetscNew(&link);
2434:   link->coarsenhook  = coarsenhook;
2435:   link->restricthook = restricthook;
2436:   link->ctx          = ctx;
2437:   link->next         = NULL;
2438:   *p                 = link;
2439:   return(0);
2440: }

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

2445:    Logically Collective

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

2453:    Level: advanced

2455:    Notes:
2456:    This function does nothing if the hook is not in the list.

2458:    This function is currently not available from Fortran.

2460: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2461: @*/
2462: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2463: {
2464:   PetscErrorCode    ierr;
2465:   DMCoarsenHookLink link,*p;

2469:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2470:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2471:       link = *p;
2472:       *p = link->next;
2473:       PetscFree(link);
2474:       break;
2475:     }
2476:   }
2477:   return(0);
2478: }


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

2484:    Collective if any hooks are

2486:    Input Arguments:
2487: +  fine - finer DM to use as a base
2488: .  restrct - restriction matrix, apply using MatRestrict()
2489: .  rscale - scaling vector for restriction
2490: .  inject - injection matrix, also use MatRestrict()
2491: -  coarse - coarser DM to update

2493:    Level: developer

2495: .seealso: DMCoarsenHookAdd(), MatRestrict()
2496: @*/
2497: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2498: {
2499:   PetscErrorCode    ierr;
2500:   DMCoarsenHookLink link;

2503:   for (link=fine->coarsenhook; link; link=link->next) {
2504:     if (link->restricthook) {
2505:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
2506:     }
2507:   }
2508:   return(0);
2509: }

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

2514:    Logically Collective

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


2523:    Calling sequence for ddhook:
2524: $    ddhook(DM global,DM block,void *ctx)

2526: +  global - global DM
2527: .  block  - block DM
2528: -  ctx - optional user-defined function context

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

2533: +  global - global DM
2534: .  out    - scatter to the outer (with ghost and overlap points) block vector
2535: .  in     - scatter to block vector values only owned locally
2536: .  block  - block DM
2537: -  ctx - optional user-defined function context

2539:    Level: advanced

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

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

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

2549:    This function is currently not available from Fortran.

2551: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2552: @*/
2553: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2554: {
2555:   PetscErrorCode      ierr;
2556:   DMSubDomainHookLink link,*p;

2560:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2561:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
2562:   }
2563:   PetscNew(&link);
2564:   link->restricthook = restricthook;
2565:   link->ddhook       = ddhook;
2566:   link->ctx          = ctx;
2567:   link->next         = NULL;
2568:   *p                 = link;
2569:   return(0);
2570: }

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

2575:    Logically Collective

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

2583:    Level: advanced

2585:    Notes:

2587:    This function is currently not available from Fortran.

2589: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2590: @*/
2591: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2592: {
2593:   PetscErrorCode      ierr;
2594:   DMSubDomainHookLink link,*p;

2598:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2599:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
2600:       link = *p;
2601:       *p = link->next;
2602:       PetscFree(link);
2603:       break;
2604:     }
2605:   }
2606:   return(0);
2607: }

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

2612:    Collective if any hooks are

2614:    Input Arguments:
2615: +  fine - finer DM to use as a base
2616: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2617: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2618: -  coarse - coarer DM to update

2620:    Level: developer

2622: .seealso: DMCoarsenHookAdd(), MatRestrict()
2623: @*/
2624: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2625: {
2626:   PetscErrorCode      ierr;
2627:   DMSubDomainHookLink link;

2630:   for (link=global->subdomainhook; link; link=link->next) {
2631:     if (link->restricthook) {
2632:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
2633:     }
2634:   }
2635:   return(0);
2636: }

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

2641:     Not Collective

2643:     Input Parameter:
2644: .   dm - the DM object

2646:     Output Parameter:
2647: .   level - number of coarsenings

2649:     Level: developer

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

2653: @*/
2654: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2655: {
2658:   *level = dm->leveldown;
2659:   return(0);
2660: }



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

2667:     Collective on DM

2669:     Input Parameter:
2670: +   dm - the DM object
2671: -   nlevels - the number of levels of refinement

2673:     Output Parameter:
2674: .   dmf - the refined DM hierarchy

2676:     Level: developer

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

2680: @*/
2681: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2682: {

2687:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2688:   if (nlevels == 0) return(0);
2689:   if (dm->ops->refinehierarchy) {
2690:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
2691:   } else if (dm->ops->refine) {
2692:     PetscInt i;

2694:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
2695:     for (i=1; i<nlevels; i++) {
2696:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
2697:     }
2698:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2699:   return(0);
2700: }

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

2705:     Collective on DM

2707:     Input Parameter:
2708: +   dm - the DM object
2709: -   nlevels - the number of levels of coarsening

2711:     Output Parameter:
2712: .   dmc - the coarsened DM hierarchy

2714:     Level: developer

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

2718: @*/
2719: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2720: {

2725:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2726:   if (nlevels == 0) return(0);
2728:   if (dm->ops->coarsenhierarchy) {
2729:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
2730:   } else if (dm->ops->coarsen) {
2731:     PetscInt i;

2733:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
2734:     for (i=1; i<nlevels; i++) {
2735:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
2736:     }
2737:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2738:   return(0);
2739: }

2741: /*@
2742:    DMCreateAggregates - Gets the aggregates that map between
2743:    grids associated with two DMs.

2745:    Collective on DM

2747:    Input Parameters:
2748: +  dmc - the coarse grid DM
2749: -  dmf - the fine grid DM

2751:    Output Parameters:
2752: .  rest - the restriction matrix (transpose of the projection matrix)

2754:    Level: intermediate

2756: .keywords: interpolation, restriction, multigrid

2758: .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2759: @*/
2760: PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2761: {

2767:   (*dmc->ops->getaggregates)(dmc, dmf, rest);
2768:   return(0);
2769: }

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

2774:     Not Collective

2776:     Input Parameters:
2777: +   dm - the DM object
2778: -   destroy - the destroy function

2780:     Level: intermediate

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

2784: @*/
2785: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2786: {
2789:   dm->ctxdestroy = destroy;
2790:   return(0);
2791: }

2793: /*@
2794:     DMSetApplicationContext - Set a user context into a DM object

2796:     Not Collective

2798:     Input Parameters:
2799: +   dm - the DM object
2800: -   ctx - the user context

2802:     Level: intermediate

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

2806: @*/
2807: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2808: {
2811:   dm->ctx = ctx;
2812:   return(0);
2813: }

2815: /*@
2816:     DMGetApplicationContext - Gets a user context from a DM object

2818:     Not Collective

2820:     Input Parameter:
2821: .   dm - the DM object

2823:     Output Parameter:
2824: .   ctx - the user context

2826:     Level: intermediate

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

2830: @*/
2831: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2832: {
2835:   *(void**)ctx = dm->ctx;
2836:   return(0);
2837: }

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

2842:     Logically Collective on DM

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

2848:     Level: intermediate

2850: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2851:          DMSetJacobian()

2853: @*/
2854: PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2855: {
2857:   dm->ops->computevariablebounds = f;
2858:   return(0);
2859: }

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

2864:     Not Collective

2866:     Input Parameter:
2867: .   dm - the DM object to destroy

2869:     Output Parameter:
2870: .   flg - PETSC_TRUE if the variable bounds function exists

2872:     Level: developer

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

2876: @*/
2877: PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2878: {
2880:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2881:   return(0);
2882: }

2884: /*@C
2885:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

2887:     Logically Collective on DM

2889:     Input Parameters:
2890: .   dm - the DM object

2892:     Output parameters:
2893: +   xl - lower bound
2894: -   xu - upper bound

2896:     Level: advanced

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

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

2902: @*/
2903: PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2904: {

2910:   if (dm->ops->computevariablebounds) {
2911:     (*dm->ops->computevariablebounds)(dm, xl,xu);
2912:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2913:   return(0);
2914: }

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

2919:     Not Collective

2921:     Input Parameter:
2922: .   dm - the DM object

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

2927:     Level: developer

2929: .seealso DMHasFunction(), DMCreateColoring()

2931: @*/
2932: PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2933: {
2935:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2936:   return(0);
2937: }

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

2942:     Not Collective

2944:     Input Parameter:
2945: .   dm - the DM object

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

2950:     Level: developer

2952: .seealso DMHasFunction(), DMCreateRestriction()

2954: @*/
2955: PetscErrorCode  DMHasCreateRestriction(DM dm,PetscBool  *flg)
2956: {
2958:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
2959:   return(0);
2960: }

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

2965:     Collective on DM

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

2971:     Level: developer

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

2975: @*/
2976: PetscErrorCode  DMSetVec(DM dm,Vec x)
2977: {

2981:   if (x) {
2982:     if (!dm->x) {
2983:       DMCreateGlobalVector(dm,&dm->x);
2984:     }
2985:     VecCopy(x,dm->x);
2986:   } else if (dm->x) {
2987:     VecDestroy(&dm->x);
2988:   }
2989:   return(0);
2990: }

2992: PetscFunctionList DMList              = NULL;
2993: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

2995: /*@C
2996:   DMSetType - Builds a DM, for a particular DM implementation.

2998:   Collective on DM

3000:   Input Parameters:
3001: + dm     - The DM object
3002: - method - The name of the DM type

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

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

3010:   Level: intermediate

3012: .keywords: DM, set, type
3013: .seealso: DMGetType(), DMCreate()
3014: @*/
3015: PetscErrorCode  DMSetType(DM dm, DMType method)
3016: {
3017:   PetscErrorCode (*r)(DM);
3018:   PetscBool      match;

3023:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3024:   if (match) return(0);

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

3030:   if (dm->ops->destroy) {
3031:     (*dm->ops->destroy)(dm);
3032:     dm->ops->destroy = NULL;
3033:   }
3034:   (*r)(dm);
3035:   PetscObjectChangeTypeName((PetscObject)dm,method);
3036:   return(0);
3037: }

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

3042:   Not Collective

3044:   Input Parameter:
3045: . dm  - The DM

3047:   Output Parameter:
3048: . type - The DM type name

3050:   Level: intermediate

3052: .keywords: DM, get, type, name
3053: .seealso: DMSetType(), DMCreate()
3054: @*/
3055: PetscErrorCode  DMGetType(DM dm, DMType *type)
3056: {

3062:   DMRegisterAll();
3063:   *type = ((PetscObject)dm)->type_name;
3064:   return(0);
3065: }

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

3070:   Collective on DM

3072:   Input Parameters:
3073: + dm - the DM
3074: - newtype - new DM type (use "same" for the same type)

3076:   Output Parameter:
3077: . M - pointer to new DM

3079:   Notes:
3080:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3081:   the MPI communicator of the generated DM is always the same as the communicator
3082:   of the input DM.

3084:   Level: intermediate

3086: .seealso: DMCreate()
3087: @*/
3088: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3089: {
3090:   DM             B;
3091:   char           convname[256];
3092:   PetscBool      sametype/*, issame */;

3099:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3100:   /* PetscStrcmp(newtype, "same", &issame); */
3101:   if (sametype) {
3102:     *M   = dm;
3103:     PetscObjectReference((PetscObject) dm);
3104:     return(0);
3105:   } else {
3106:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3108:     /*
3109:        Order of precedence:
3110:        1) See if a specialized converter is known to the current DM.
3111:        2) See if a specialized converter is known to the desired DM class.
3112:        3) See if a good general converter is registered for the desired class
3113:        4) See if a good general converter is known for the current matrix.
3114:        5) Use a really basic converter.
3115:     */

3117:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3118:     PetscStrcpy(convname,"DMConvert_");
3119:     PetscStrcat(convname,((PetscObject) dm)->type_name);
3120:     PetscStrcat(convname,"_");
3121:     PetscStrcat(convname,newtype);
3122:     PetscStrcat(convname,"_C");
3123:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3124:     if (conv) goto foundconv;

3126:     /* 2)  See if a specialized converter is known to the desired DM class. */
3127:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3128:     DMSetType(B, newtype);
3129:     PetscStrcpy(convname,"DMConvert_");
3130:     PetscStrcat(convname,((PetscObject) dm)->type_name);
3131:     PetscStrcat(convname,"_");
3132:     PetscStrcat(convname,newtype);
3133:     PetscStrcat(convname,"_C");
3134:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3135:     if (conv) {
3136:       DMDestroy(&B);
3137:       goto foundconv;
3138:     }

3140: #if 0
3141:     /* 3) See if a good general converter is registered for the desired class */
3142:     conv = B->ops->convertfrom;
3143:     DMDestroy(&B);
3144:     if (conv) goto foundconv;

3146:     /* 4) See if a good general converter is known for the current matrix */
3147:     if (dm->ops->convert) {
3148:       conv = dm->ops->convert;
3149:     }
3150:     if (conv) goto foundconv;
3151: #endif

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

3156: foundconv:
3157:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3158:     (*conv)(dm,newtype,M);
3159:     /* Things that are independent of DM type: We should consult DMClone() here */
3160:     {
3161:       PetscBool             isper;
3162:       const PetscReal      *maxCell, *L;
3163:       const DMBoundaryType *bd;
3164:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3165:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3166:     }
3167:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3168:   }
3169:   PetscObjectStateIncrease((PetscObject) *M);
3170:   return(0);
3171: }

3173: /*--------------------------------------------------------------------------------------------------------------------*/

3175: /*@C
3176:   DMRegister -  Adds a new DM component implementation

3178:   Not Collective

3180:   Input Parameters:
3181: + name        - The name of a new user-defined creation routine
3182: - create_func - The creation routine itself

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


3188:   Sample usage:
3189: .vb
3190:     DMRegister("my_da", MyDMCreate);
3191: .ve

3193:   Then, your DM type can be chosen with the procedural interface via
3194: .vb
3195:     DMCreate(MPI_Comm, DM *);
3196:     DMSetType(DM,"my_da");
3197: .ve
3198:    or at runtime via the option
3199: .vb
3200:     -da_type my_da
3201: .ve

3203:   Level: advanced

3205: .keywords: DM, register
3206: .seealso: DMRegisterAll(), DMRegisterDestroy()

3208: @*/
3209: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3210: {

3214:   PetscFunctionListAdd(&DMList,sname,function);
3215:   return(0);
3216: }

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

3221:   Collective on PetscViewer

3223:   Input Parameters:
3224: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3225:            some related function before a call to DMLoad().
3226: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3227:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3229:    Level: intermediate

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

3234:   Notes for advanced users:
3235:   Most users should not need to know the details of the binary storage
3236:   format, since DMLoad() and DMView() completely hide these details.
3237:   But for anyone who's interested, the standard binary matrix storage
3238:   format is
3239: .vb
3240:      has not yet been determined
3241: .ve

3243: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3244: @*/
3245: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3246: {
3247:   PetscBool      isbinary, ishdf5;

3253:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3254:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3255:   if (isbinary) {
3256:     PetscInt classid;
3257:     char     type[256];

3259:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3260:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
3261:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3262:     DMSetType(newdm, type);
3263:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3264:   } else if (ishdf5) {
3265:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
3266:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3267:   return(0);
3268: }

3270: /******************************** FEM Support **********************************/

3272: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3273: {
3274:   PetscInt       f;

3278:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3279:   for (f = 0; f < len; ++f) {
3280:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
3281:   }
3282:   return(0);
3283: }

3285: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
3286: {
3287:   PetscInt       f, g;

3291:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
3292:   for (f = 0; f < rows; ++f) {
3293:     PetscPrintf(PETSC_COMM_SELF, "  |");
3294:     for (g = 0; g < cols; ++g) {
3295:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
3296:     }
3297:     PetscPrintf(PETSC_COMM_SELF, " |\n");
3298:   }
3299:   return(0);
3300: }

3302: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
3303: {
3304:   PetscInt          localSize, bs;
3305:   PetscMPIInt       size;
3306:   Vec               x, xglob;
3307:   const PetscScalar *xarray;
3308:   PetscErrorCode    ierr;

3311:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
3312:   VecDuplicate(X, &x);
3313:   VecCopy(X, x);
3314:   VecChop(x, tol);
3315:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
3316:   if (size > 1) {
3317:     VecGetLocalSize(x,&localSize);
3318:     VecGetArrayRead(x,&xarray);
3319:     VecGetBlockSize(x,&bs);
3320:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
3321:   } else {
3322:     xglob = x;
3323:   }
3324:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
3325:   if (size > 1) {
3326:     VecDestroy(&xglob);
3327:     VecRestoreArrayRead(x,&xarray);
3328:   }
3329:   VecDestroy(&x);
3330:   return(0);
3331: }

3333: /*@
3334:   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.

3336:   Input Parameter:
3337: . dm - The DM

3339:   Output Parameter:
3340: . section - The PetscSection

3342:   Level: intermediate

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

3346: .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3347: @*/
3348: PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
3349: {

3355:   if (!dm->defaultSection && dm->ops->createdefaultsection) {
3356:     (*dm->ops->createdefaultsection)(dm);
3357:     if (dm->defaultSection) {PetscObjectViewFromOptions((PetscObject) dm->defaultSection, NULL, "-dm_petscsection_view");}
3358:   }
3359:   *section = dm->defaultSection;
3360:   return(0);
3361: }

3363: /*@
3364:   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.

3366:   Input Parameters:
3367: + dm - The DM
3368: - section - The PetscSection

3370:   Level: intermediate

3372:   Note: Any existing Section will be destroyed

3374: .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
3375: @*/
3376: PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
3377: {
3378:   PetscInt       numFields = 0;
3379:   PetscInt       f;

3384:   if (section) {
3386:     PetscObjectReference((PetscObject)section);
3387:   }
3388:   PetscSectionDestroy(&dm->defaultSection);
3389:   dm->defaultSection = section;
3390:   if (section) {PetscSectionGetNumFields(dm->defaultSection, &numFields);}
3391:   if (numFields) {
3392:     DMSetNumFields(dm, numFields);
3393:     for (f = 0; f < numFields; ++f) {
3394:       PetscObject disc;
3395:       const char *name;

3397:       PetscSectionGetFieldName(dm->defaultSection, f, &name);
3398:       DMGetField(dm, f, &disc);
3399:       PetscObjectSetName(disc, name);
3400:     }
3401:   }
3402:   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
3403:   PetscSectionDestroy(&dm->defaultGlobalSection);
3404:   return(0);
3405: }

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

3410:   not collective

3412:   Input Parameter:
3413: . dm - The DM

3415:   Output Parameter:
3416: + 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.
3417: - 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.

3419:   Level: advanced

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

3423: .seealso: DMSetDefaultConstraints()
3424: @*/
3425: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
3426: {

3431:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
3432:   if (section) {*section = dm->defaultConstraintSection;}
3433:   if (mat) {*mat = dm->defaultConstraintMat;}
3434:   return(0);
3435: }

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

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

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

3444:   collective on dm

3446:   Input Parameters:
3447: + dm - The DM
3448: + 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).
3449: - 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).

3451:   Level: advanced

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

3455: .seealso: DMGetDefaultConstraints()
3456: @*/
3457: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
3458: {
3459:   PetscMPIInt result;

3464:   if (section) {
3466:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
3467:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
3468:   }
3469:   if (mat) {
3471:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
3472:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
3473:   }
3474:   PetscObjectReference((PetscObject)section);
3475:   PetscSectionDestroy(&dm->defaultConstraintSection);
3476:   dm->defaultConstraintSection = section;
3477:   PetscObjectReference((PetscObject)mat);
3478:   MatDestroy(&dm->defaultConstraintMat);
3479:   dm->defaultConstraintMat = mat;
3480:   return(0);
3481: }

3483: #ifdef PETSC_USE_DEBUG
3484: /*
3485:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

3487:   Input Parameters:
3488: + dm - The DM
3489: . localSection - PetscSection describing the local data layout
3490: - globalSection - PetscSection describing the global data layout

3492:   Level: intermediate

3494: .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3495: */
3496: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
3497: {
3498:   MPI_Comm        comm;
3499:   PetscLayout     layout;
3500:   const PetscInt *ranges;
3501:   PetscInt        pStart, pEnd, p, nroots;
3502:   PetscMPIInt     size, rank;
3503:   PetscBool       valid = PETSC_TRUE, gvalid;
3504:   PetscErrorCode  ierr;

3507:   PetscObjectGetComm((PetscObject)dm,&comm);
3509:   MPI_Comm_size(comm, &size);
3510:   MPI_Comm_rank(comm, &rank);
3511:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
3512:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
3513:   PetscLayoutCreate(comm, &layout);
3514:   PetscLayoutSetBlockSize(layout, 1);
3515:   PetscLayoutSetLocalSize(layout, nroots);
3516:   PetscLayoutSetUp(layout);
3517:   PetscLayoutGetRanges(layout, &ranges);
3518:   for (p = pStart; p < pEnd; ++p) {
3519:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

3521:     PetscSectionGetDof(localSection, p, &dof);
3522:     PetscSectionGetOffset(localSection, p, &off);
3523:     PetscSectionGetConstraintDof(localSection, p, &cdof);
3524:     PetscSectionGetDof(globalSection, p, &gdof);
3525:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3526:     PetscSectionGetOffset(globalSection, p, &goff);
3527:     if (!gdof) continue; /* Censored point */
3528:     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;}
3529:     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;}
3530:     if (gdof < 0) {
3531:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3532:       for (d = 0; d < gsize; ++d) {
3533:         PetscInt offset = -(goff+1) + d, r;

3535:         PetscFindInt(offset,size+1,ranges,&r);
3536:         if (r < 0) r = -(r+2);
3537:         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;}
3538:       }
3539:     }
3540:   }
3541:   PetscLayoutDestroy(&layout);
3542:   PetscSynchronizedFlush(comm, NULL);
3543:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
3544:   if (!gvalid) {
3545:     DMView(dm, NULL);
3546:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
3547:   }
3548:   return(0);
3549: }
3550: #endif

3552: /*@
3553:   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.

3555:   Collective on DM

3557:   Input Parameter:
3558: . dm - The DM

3560:   Output Parameter:
3561: . section - The PetscSection

3563:   Level: intermediate

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

3567: .seealso: DMSetDefaultSection(), DMGetDefaultSection()
3568: @*/
3569: PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
3570: {

3576:   if (!dm->defaultGlobalSection) {
3577:     PetscSection s;

3579:     DMGetDefaultSection(dm, &s);
3580:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
3581:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
3582:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->defaultGlobalSection);
3583:     PetscLayoutDestroy(&dm->map);
3584:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);
3585:     PetscSectionViewFromOptions(dm->defaultGlobalSection, NULL, "-global_section_view");
3586:   }
3587:   *section = dm->defaultGlobalSection;
3588:   return(0);
3589: }

3591: /*@
3592:   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.

3594:   Input Parameters:
3595: + dm - The DM
3596: - section - The PetscSection, or NULL

3598:   Level: intermediate

3600:   Note: Any existing Section will be destroyed

3602: .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3603: @*/
3604: PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3605: {

3611:   PetscObjectReference((PetscObject)section);
3612:   PetscSectionDestroy(&dm->defaultGlobalSection);
3613:   dm->defaultGlobalSection = section;
3614: #ifdef PETSC_USE_DEBUG
3615:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->defaultSection, section);}
3616: #endif
3617:   return(0);
3618: }

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

3624:   Input Parameter:
3625: . dm - The DM

3627:   Output Parameter:
3628: . sf - The PetscSF

3630:   Level: intermediate

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

3634: .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3635: @*/
3636: PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3637: {
3638:   PetscInt       nroots;

3644:   PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);
3645:   if (nroots < 0) {
3646:     PetscSection section, gSection;

3648:     DMGetDefaultSection(dm, &section);
3649:     if (section) {
3650:       DMGetDefaultGlobalSection(dm, &gSection);
3651:       DMCreateDefaultSF(dm, section, gSection);
3652:     } else {
3653:       *sf = NULL;
3654:       return(0);
3655:     }
3656:   }
3657:   *sf = dm->defaultSF;
3658:   return(0);
3659: }

3661: /*@
3662:   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM

3664:   Input Parameters:
3665: + dm - The DM
3666: - sf - The PetscSF

3668:   Level: intermediate

3670:   Note: Any previous SF is destroyed

3672: .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3673: @*/
3674: PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3675: {

3681:   PetscSFDestroy(&dm->defaultSF);
3682:   dm->defaultSF = sf;
3683:   return(0);
3684: }

3686: /*@C
3687:   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3688:   describing the data layout.

3690:   Input Parameters:
3691: + dm - The DM
3692: . localSection - PetscSection describing the local data layout
3693: - globalSection - PetscSection describing the global data layout

3695:   Level: intermediate

3697: .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3698: @*/
3699: PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3700: {
3701:   MPI_Comm       comm;
3702:   PetscLayout    layout;
3703:   const PetscInt *ranges;
3704:   PetscInt       *local;
3705:   PetscSFNode    *remote;
3706:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3707:   PetscMPIInt    size, rank;

3711:   PetscObjectGetComm((PetscObject)dm,&comm);
3713:   MPI_Comm_size(comm, &size);
3714:   MPI_Comm_rank(comm, &rank);
3715:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
3716:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
3717:   PetscLayoutCreate(comm, &layout);
3718:   PetscLayoutSetBlockSize(layout, 1);
3719:   PetscLayoutSetLocalSize(layout, nroots);
3720:   PetscLayoutSetUp(layout);
3721:   PetscLayoutGetRanges(layout, &ranges);
3722:   for (p = pStart; p < pEnd; ++p) {
3723:     PetscInt gdof, gcdof;

3725:     PetscSectionGetDof(globalSection, p, &gdof);
3726:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3727:     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));
3728:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3729:   }
3730:   PetscMalloc1(nleaves, &local);
3731:   PetscMalloc1(nleaves, &remote);
3732:   for (p = pStart, l = 0; p < pEnd; ++p) {
3733:     const PetscInt *cind;
3734:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

3736:     PetscSectionGetDof(localSection, p, &dof);
3737:     PetscSectionGetOffset(localSection, p, &off);
3738:     PetscSectionGetConstraintDof(localSection, p, &cdof);
3739:     PetscSectionGetConstraintIndices(localSection, p, &cind);
3740:     PetscSectionGetDof(globalSection, p, &gdof);
3741:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
3742:     PetscSectionGetOffset(globalSection, p, &goff);
3743:     if (!gdof) continue; /* Censored point */
3744:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3745:     if (gsize != dof-cdof) {
3746:       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);
3747:       cdof = 0; /* Ignore constraints */
3748:     }
3749:     for (d = 0, c = 0; d < dof; ++d) {
3750:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3751:       local[l+d-c] = off+d;
3752:     }
3753:     if (gdof < 0) {
3754:       for (d = 0; d < gsize; ++d, ++l) {
3755:         PetscInt offset = -(goff+1) + d, r;

3757:         PetscFindInt(offset,size+1,ranges,&r);
3758:         if (r < 0) r = -(r+2);
3759:         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);
3760:         remote[l].rank  = r;
3761:         remote[l].index = offset - ranges[r];
3762:       }
3763:     } else {
3764:       for (d = 0; d < gsize; ++d, ++l) {
3765:         remote[l].rank  = rank;
3766:         remote[l].index = goff+d - ranges[rank];
3767:       }
3768:     }
3769:   }
3770:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3771:   PetscLayoutDestroy(&layout);
3772:   PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
3773:   return(0);
3774: }

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

3779:   Input Parameter:
3780: . dm - The DM

3782:   Output Parameter:
3783: . sf - The PetscSF

3785:   Level: intermediate

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

3789: .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3790: @*/
3791: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3792: {
3796:   *sf = dm->sf;
3797:   return(0);
3798: }

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

3803:   Input Parameters:
3804: + dm - The DM
3805: - sf - The PetscSF

3807:   Level: intermediate

3809: .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3810: @*/
3811: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3812: {

3818:   PetscSFDestroy(&dm->sf);
3819:   PetscObjectReference((PetscObject) sf);
3820:   dm->sf = sf;
3821:   return(0);
3822: }

3824: /*@
3825:   DMGetDS - Get the PetscDS

3827:   Input Parameter:
3828: . dm - The DM

3830:   Output Parameter:
3831: . prob - The PetscDS

3833:   Level: developer

3835: .seealso: DMSetDS()
3836: @*/
3837: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3838: {
3842:   *prob = dm->prob;
3843:   return(0);
3844: }

3846: /*@
3847:   DMSetDS - Set the PetscDS

3849:   Input Parameters:
3850: + dm - The DM
3851: - prob - The PetscDS

3853:   Level: developer

3855: .seealso: DMGetDS()
3856: @*/
3857: PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3858: {

3864:   PetscObjectReference((PetscObject) prob);
3865:   PetscDSDestroy(&dm->prob);
3866:   dm->prob = prob;
3867:   return(0);
3868: }

3870: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3871: {

3876:   PetscDSGetNumFields(dm->prob, numFields);
3877:   return(0);
3878: }

3880: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3881: {
3882:   PetscInt       Nf, f;

3887:   PetscDSGetNumFields(dm->prob, &Nf);
3888:   for (f = Nf; f < numFields; ++f) {
3889:     PetscContainer obj;

3891:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
3892:     PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);
3893:     PetscContainerDestroy(&obj);
3894:   }
3895:   return(0);
3896: }

3898: /*@
3899:   DMGetField - Return the discretization object for a given DM field

3901:   Not collective

3903:   Input Parameters:
3904: + dm - The DM
3905: - f  - The field number

3907:   Output Parameter:
3908: . field - The discretization object

3910:   Level: developer

3912: .seealso: DMSetField()
3913: @*/
3914: PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3915: {

3920:   PetscDSGetDiscretization(dm->prob, f, field);
3921:   return(0);
3922: }

3924: /*@
3925:   DMSetField - Set the discretization object for a given DM field

3927:   Logically collective on DM

3929:   Input Parameters:
3930: + dm - The DM
3931: . f  - The field number
3932: - field - The discretization object

3934:   Level: developer

3936: .seealso: DMGetField()
3937: @*/
3938: PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3939: {

3944:   PetscDSSetDiscretization(dm->prob, f, field);
3945:   return(0);
3946: }

3948: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3949: {
3950:   DM dm_coord,dmc_coord;
3952:   Vec coords,ccoords;
3953:   Mat inject;
3955:   DMGetCoordinateDM(dm,&dm_coord);
3956:   DMGetCoordinateDM(dmc,&dmc_coord);
3957:   DMGetCoordinates(dm,&coords);
3958:   DMGetCoordinates(dmc,&ccoords);
3959:   if (coords && !ccoords) {
3960:     DMCreateGlobalVector(dmc_coord,&ccoords);
3961:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
3962:     DMCreateInjection(dmc_coord,dm_coord,&inject);
3963:     MatRestrict(inject,coords,ccoords);
3964:     MatDestroy(&inject);
3965:     DMSetCoordinates(dmc,ccoords);
3966:     VecDestroy(&ccoords);
3967:   }
3968:   return(0);
3969: }

3971: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3972: {
3973:   DM dm_coord,subdm_coord;
3975:   Vec coords,ccoords,clcoords;
3976:   VecScatter *scat_i,*scat_g;
3978:   DMGetCoordinateDM(dm,&dm_coord);
3979:   DMGetCoordinateDM(subdm,&subdm_coord);
3980:   DMGetCoordinates(dm,&coords);
3981:   DMGetCoordinates(subdm,&ccoords);
3982:   if (coords && !ccoords) {
3983:     DMCreateGlobalVector(subdm_coord,&ccoords);
3984:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
3985:     DMCreateLocalVector(subdm_coord,&clcoords);
3986:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
3987:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
3988:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
3989:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
3990:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
3991:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
3992:     DMSetCoordinates(subdm,ccoords);
3993:     DMSetCoordinatesLocal(subdm,clcoords);
3994:     VecScatterDestroy(&scat_i[0]);
3995:     VecScatterDestroy(&scat_g[0]);
3996:     VecDestroy(&ccoords);
3997:     VecDestroy(&clcoords);
3998:     PetscFree(scat_i);
3999:     PetscFree(scat_g);
4000:   }
4001:   return(0);
4002: }

4004: /*@
4005:   DMGetDimension - Return the topological dimension of the DM

4007:   Not collective

4009:   Input Parameter:
4010: . dm - The DM

4012:   Output Parameter:
4013: . dim - The topological dimension

4015:   Level: beginner

4017: .seealso: DMSetDimension(), DMCreate()
4018: @*/
4019: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
4020: {
4024:   *dim = dm->dim;
4025:   return(0);
4026: }

4028: /*@
4029:   DMSetDimension - Set the topological dimension of the DM

4031:   Collective on dm

4033:   Input Parameters:
4034: + dm - The DM
4035: - dim - The topological dimension

4037:   Level: beginner

4039: .seealso: DMGetDimension(), DMCreate()
4040: @*/
4041: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
4042: {
4046:   dm->dim = dim;
4047:   return(0);
4048: }

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

4053:   Collective on DM

4055:   Input Parameters:
4056: + dm - the DM
4057: - dim - the dimension

4059:   Output Parameters:
4060: + pStart - The first point of the given dimension
4061: . pEnd - The first point following points of the given dimension

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

4068:   Level: intermediate

4070: .keywords: point, Hasse Diagram, dimension
4071: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
4072: @*/
4073: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
4074: {
4075:   PetscInt       d;

4080:   DMGetDimension(dm, &d);
4081:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
4082:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
4083:   return(0);
4084: }

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

4089:   Collective on DM

4091:   Input Parameters:
4092: + dm - the DM
4093: - c - coordinate vector

4095:   Note:
4096:   The coordinates do include those for ghost points, which are in the local vector

4098:   Level: intermediate

4100: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4101: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
4102: @*/
4103: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
4104: {

4110:   PetscObjectReference((PetscObject) c);
4111:   VecDestroy(&dm->coordinates);
4112:   dm->coordinates = c;
4113:   VecDestroy(&dm->coordinatesLocal);
4114:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
4115:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
4116:   return(0);
4117: }

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

4122:   Collective on DM

4124:    Input Parameters:
4125: +  dm - the DM
4126: -  c - coordinate vector

4128:   Note:
4129:   The coordinates of ghost points can be set using DMSetCoordinates()
4130:   followed by DMGetCoordinatesLocal(). This is intended to enable the
4131:   setting of ghost coordinates outside of the domain.

4133:   Level: intermediate

4135: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4136: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
4137: @*/
4138: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
4139: {

4145:   PetscObjectReference((PetscObject) c);
4146:   VecDestroy(&dm->coordinatesLocal);

4148:   dm->coordinatesLocal = c;

4150:   VecDestroy(&dm->coordinates);
4151:   return(0);
4152: }

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

4157:   Not Collective

4159:   Input Parameter:
4160: . dm - the DM

4162:   Output Parameter:
4163: . c - global coordinate vector

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

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

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

4173:   Level: intermediate

4175: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4176: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
4177: @*/
4178: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
4179: {

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

4188:     DMGetCoordinateDM(dm, &cdm);
4189:     DMCreateGlobalVector(cdm, &dm->coordinates);
4190:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
4191:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
4192:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
4193:   }
4194:   *c = dm->coordinates;
4195:   return(0);
4196: }

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

4201:   Collective on DM

4203:   Input Parameter:
4204: . dm - the DM

4206:   Output Parameter:
4207: . c - coordinate vector

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

4212:   Each process has the local and ghost coordinates

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

4217:   Level: intermediate

4219: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4220: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
4221: @*/
4222: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
4223: {

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

4232:     DMGetCoordinateDM(dm, &cdm);
4233:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
4234:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
4235:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
4236:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
4237:   }
4238:   *c = dm->coordinatesLocal;
4239:   return(0);
4240: }

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

4245:   Collective on DM

4247:   Input Parameter:
4248: . dm - the DM

4250:   Output Parameter:
4251: . cdm - coordinate DM

4253:   Level: intermediate

4255: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4256: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4257: @*/
4258: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
4259: {

4265:   if (!dm->coordinateDM) {
4266:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
4267:     (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);
4268:   }
4269:   *cdm = dm->coordinateDM;
4270:   return(0);
4271: }

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

4276:   Logically Collective on DM

4278:   Input Parameters:
4279: + dm - the DM
4280: - cdm - coordinate DM

4282:   Level: intermediate

4284: .keywords: distributed array, get, corners, nodes, local indices, coordinates
4285: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
4286: @*/
4287: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
4288: {

4294:   PetscObjectReference((PetscObject)cdm);
4295:   DMDestroy(&dm->coordinateDM);
4296:   dm->coordinateDM = cdm;
4297:   return(0);
4298: }

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

4303:   Not Collective

4305:   Input Parameter:
4306: . dm - The DM object

4308:   Output Parameter:
4309: . dim - The embedding dimension

4311:   Level: intermediate

4313: .keywords: mesh, coordinates
4314: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4315: @*/
4316: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
4317: {
4321:   if (dm->dimEmbed == PETSC_DEFAULT) {
4322:     dm->dimEmbed = dm->dim;
4323:   }
4324:   *dim = dm->dimEmbed;
4325:   return(0);
4326: }

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

4331:   Not Collective

4333:   Input Parameters:
4334: + dm  - The DM object
4335: - dim - The embedding dimension

4337:   Level: intermediate

4339: .keywords: mesh, coordinates
4340: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4341: @*/
4342: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
4343: {
4346:   dm->dimEmbed = dim;
4347:   return(0);
4348: }

4350: /*@
4351:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

4353:   Not Collective

4355:   Input Parameter:
4356: . dm - The DM object

4358:   Output Parameter:
4359: . section - The PetscSection object

4361:   Level: intermediate

4363: .keywords: mesh, coordinates
4364: .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
4365: @*/
4366: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
4367: {
4368:   DM             cdm;

4374:   DMGetCoordinateDM(dm, &cdm);
4375:   DMGetDefaultSection(cdm, section);
4376:   return(0);
4377: }

4379: /*@
4380:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

4382:   Not Collective

4384:   Input Parameters:
4385: + dm      - The DM object
4386: . dim     - The embedding dimension, or PETSC_DETERMINE
4387: - section - The PetscSection object

4389:   Level: intermediate

4391: .keywords: mesh, coordinates
4392: .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
4393: @*/
4394: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
4395: {
4396:   DM             cdm;

4402:   DMGetCoordinateDM(dm, &cdm);
4403:   DMSetDefaultSection(cdm, section);
4404:   if (dim == PETSC_DETERMINE) {
4405:     PetscInt d = PETSC_DEFAULT;
4406:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

4408:     PetscSectionGetChart(section, &pStart, &pEnd);
4409:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
4410:     pStart = PetscMax(vStart, pStart);
4411:     pEnd   = PetscMin(vEnd, pEnd);
4412:     for (v = pStart; v < pEnd; ++v) {
4413:       PetscSectionGetDof(section, v, &dd);
4414:       if (dd) {d = dd; break;}
4415:     }
4416:     if (d < 0) d = PETSC_DEFAULT;
4417:     DMSetCoordinateDim(dm, d);
4418:   }
4419:   return(0);
4420: }

4422: /*@C
4423:   DMGetPeriodicity - Get the description of mesh periodicity

4425:   Input Parameters:
4426: . dm      - The DM object

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

4434:   Level: developer

4436: .seealso: DMGetPeriodicity()
4437: @*/
4438: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
4439: {
4442:   if (per)     *per     = dm->periodic;
4443:   if (L)       *L       = dm->L;
4444:   if (maxCell) *maxCell = dm->maxCell;
4445:   if (bd)      *bd      = dm->bdtype;
4446:   return(0);
4447: }

4449: /*@C
4450:   DMSetPeriodicity - Set the description of mesh periodicity

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

4459:   Level: developer

4461: .seealso: DMGetPeriodicity()
4462: @*/
4463: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
4464: {
4465:   PetscInt       dim, d;

4471:   if (maxCell) {
4475:   }
4476:   PetscFree3(dm->L,dm->maxCell,dm->bdtype);
4477:   DMGetDimension(dm, &dim);
4478:   if (maxCell) {
4479:     PetscMalloc3(dim,&dm->L,dim,&dm->maxCell,dim,&dm->bdtype);
4480:     for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d]; dm->bdtype[d] = bd[d];}
4481:     dm->periodic = PETSC_TRUE;
4482:   } else {
4483:     dm->periodic = per;
4484:   }
4485:   return(0);
4486: }

4488: /*@
4489:   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.

4491:   Input Parameters:
4492: + dm     - The DM
4493: . in     - The input coordinate point (dim numbers)
4494: - endpoint - Include the endpoint L_i

4496:   Output Parameter:
4497: . out - The localized coordinate point

4499:   Level: developer

4501: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4502: @*/
4503: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
4504: {
4505:   PetscInt       dim, d;

4509:   DMGetCoordinateDim(dm, &dim);
4510:   if (!dm->maxCell) {
4511:     for (d = 0; d < dim; ++d) out[d] = in[d];
4512:   } else {
4513:     if (endpoint) {
4514:       for (d = 0; d < dim; ++d) {
4515:         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)) {
4516:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
4517:         } else {
4518:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4519:         }
4520:       }
4521:     } else {
4522:       for (d = 0; d < dim; ++d) {
4523:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
4524:       }
4525:     }
4526:   }
4527:   return(0);
4528: }

4530: /*
4531:   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.

4533:   Input Parameters:
4534: + dm     - The DM
4535: . dim    - The spatial dimension
4536: . anchor - The anchor point, the input point can be no more than maxCell away from it
4537: - in     - The input coordinate point (dim numbers)

4539:   Output Parameter:
4540: . out - The localized coordinate point

4542:   Level: developer

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

4546: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
4547: */
4548: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4549: {
4550:   PetscInt d;

4553:   if (!dm->maxCell) {
4554:     for (d = 0; d < dim; ++d) out[d] = in[d];
4555:   } else {
4556:     for (d = 0; d < dim; ++d) {
4557:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4558:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4559:       } else {
4560:         out[d] = in[d];
4561:       }
4562:     }
4563:   }
4564:   return(0);
4565: }
4566: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
4567: {
4568:   PetscInt d;

4571:   if (!dm->maxCell) {
4572:     for (d = 0; d < dim; ++d) out[d] = in[d];
4573:   } else {
4574:     for (d = 0; d < dim; ++d) {
4575:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
4576:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
4577:       } else {
4578:         out[d] = in[d];
4579:       }
4580:     }
4581:   }
4582:   return(0);
4583: }

4585: /*
4586:   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.

4588:   Input Parameters:
4589: + dm     - The DM
4590: . dim    - The spatial dimension
4591: . anchor - The anchor point, the input point can be no more than maxCell away from it
4592: . in     - The input coordinate delta (dim numbers)
4593: - out    - The input coordinate point (dim numbers)

4595:   Output Parameter:
4596: . out    - The localized coordinate in + out

4598:   Level: developer

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

4602: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
4603: */
4604: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
4605: {
4606:   PetscInt d;

4609:   if (!dm->maxCell) {
4610:     for (d = 0; d < dim; ++d) out[d] += in[d];
4611:   } else {
4612:     for (d = 0; d < dim; ++d) {
4613:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
4614:         out[d] += PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
4615:       } else {
4616:         out[d] += in[d];
4617:       }
4618:     }
4619:   }
4620:   return(0);
4621: }

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

4626:   Input Parameter:
4627: . dm - The DM

4629:   Output Parameter:
4630:   areLocalized - True if localized

4632:   Level: developer

4634: .seealso: DMLocalizeCoordinates()
4635: @*/
4636: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
4637: {
4638:   DM             cdm;
4639:   PetscSection   coordSection;
4640:   PetscInt       cStart, cEnd, c, sStart, sEnd, dof;
4641:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;

4646:   if (!dm->periodic) {
4647:     *areLocalized = PETSC_FALSE;
4648:     return(0);
4649:   }
4650:   /* We need some generic way of refering to cells/vertices */
4651:   DMGetCoordinateDM(dm, &cdm);
4652:   {
4653:     PetscBool isplex;

4655:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
4656:     if (isplex) {
4657:       DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
4658:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4659:   }
4660:   DMGetCoordinateSection(dm, &coordSection);
4661:   PetscSectionGetChart(coordSection,&sStart,&sEnd);
4662:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_FALSE;
4663:   for (c = cStart; c < cEnd; ++c) {
4664:     if (c < sStart || c >= sEnd) {
4665:       alreadyLocalized = PETSC_FALSE;
4666:       break;
4667:     }
4668:     PetscSectionGetDof(coordSection, c, &dof);
4669:     if (dof) {
4670:       alreadyLocalized = PETSC_TRUE;
4671:       break;
4672:     }
4673:   }
4674:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
4675:   *areLocalized = alreadyLocalizedGlobal;
4676:   return(0);
4677: }


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

4683:   Input Parameter:
4684: . dm - The DM

4686:   Level: developer

4688: .seealso: DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
4689: @*/
4690: PetscErrorCode DMLocalizeCoordinates(DM dm)
4691: {
4692:   DM             cdm;
4693:   PetscSection   coordSection, cSection;
4694:   Vec            coordinates,  cVec;
4695:   PetscScalar   *coords, *coords2, *anchor, *localized;
4696:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
4697:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
4698:   PetscInt       maxHeight = 0, h;
4699:   PetscInt       *pStart = NULL, *pEnd = NULL;

4704:   if (!dm->periodic) return(0);
4705:   /* We need some generic way of refering to cells/vertices */
4706:   DMGetCoordinateDM(dm, &cdm);
4707:   {
4708:     PetscBool isplex;

4710:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
4711:     if (isplex) {
4712:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
4713:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
4714:       DMGetWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);
4715:       pEnd = &pStart[maxHeight + 1];
4716:       newStart = vStart;
4717:       newEnd   = vEnd;
4718:       for (h = 0; h <= maxHeight; h++) {
4719:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
4720:         newStart = PetscMin(newStart,pStart[h]);
4721:         newEnd   = PetscMax(newEnd,pEnd[h]);
4722:       }
4723:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
4724:   }
4725:   DMGetCoordinatesLocal(dm, &coordinates);
4726:   DMGetCoordinateSection(dm, &coordSection);
4727:   VecGetBlockSize(coordinates, &bs);
4728:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

4730:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
4731:   PetscSectionSetNumFields(cSection, 1);
4732:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
4733:   PetscSectionSetFieldComponents(cSection, 0, Nc);
4734:   PetscSectionSetChart(cSection, newStart, newEnd);

4736:   DMGetWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);
4737:   localized = &anchor[bs];
4738:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
4739:   for (h = 0; h <= maxHeight; h++) {
4740:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

4742:     for (c = cStart; c < cEnd; ++c) {
4743:       PetscScalar *cellCoords = NULL;
4744:       PetscInt     b;

4746:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
4747:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4748:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4749:       for (d = 0; d < dof/bs; ++d) {
4750:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
4751:         for (b = 0; b < bs; b++) {
4752:           if (cellCoords[d*bs + b] != localized[b]) break;
4753:         }
4754:         if (b < bs) break;
4755:       }
4756:       if (d < dof/bs) {
4757:         if (c >= sStart && c < sEnd) {
4758:           PetscInt cdof;

4760:           PetscSectionGetDof(coordSection, c, &cdof);
4761:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
4762:         }
4763:         PetscSectionSetDof(cSection, c, dof);
4764:         PetscSectionSetFieldDof(cSection, c, 0, dof);
4765:       }
4766:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4767:     }
4768:   }
4769:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
4770:   if (alreadyLocalizedGlobal) {
4771:     DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);
4772:     PetscSectionDestroy(&cSection);
4773:     DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);
4774:     return(0);
4775:   }
4776:   for (v = vStart; v < vEnd; ++v) {
4777:     PetscSectionGetDof(coordSection, v, &dof);
4778:     PetscSectionSetDof(cSection,     v,  dof);
4779:     PetscSectionSetFieldDof(cSection, v, 0, dof);
4780:   }
4781:   PetscSectionSetUp(cSection);
4782:   PetscSectionGetStorageSize(cSection, &coordSize);
4783:   VecCreate(PETSC_COMM_SELF, &cVec);
4784:   PetscObjectSetName((PetscObject)cVec,"coordinates");
4785:   VecSetBlockSize(cVec,         bs);
4786:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
4787:   VecSetType(cVec, VECSTANDARD);
4788:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
4789:   VecGetArray(cVec, &coords2);
4790:   for (v = vStart; v < vEnd; ++v) {
4791:     PetscSectionGetDof(coordSection, v, &dof);
4792:     PetscSectionGetOffset(coordSection, v, &off);
4793:     PetscSectionGetOffset(cSection,     v, &off2);
4794:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
4795:   }
4796:   for (h = 0; h <= maxHeight; h++) {
4797:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

4799:     for (c = cStart; c < cEnd; ++c) {
4800:       PetscScalar *cellCoords = NULL;
4801:       PetscInt     b, cdof;

4803:       PetscSectionGetDof(cSection,c,&cdof);
4804:       if (!cdof) continue;
4805:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4806:       PetscSectionGetOffset(cSection, c, &off2);
4807:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
4808:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
4809:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
4810:     }
4811:   }
4812:   DMRestoreWorkArray(dm, 2 * bs, PETSC_SCALAR, &anchor);
4813:   DMRestoreWorkArray(dm,2*(maxHeight + 1),PETSC_INT,&pStart);
4814:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
4815:   VecRestoreArray(cVec, &coords2);
4816:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
4817:   DMSetCoordinatesLocal(dm, cVec);
4818:   VecDestroy(&cVec);
4819:   PetscSectionDestroy(&cSection);
4820:   return(0);
4821: }

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

4826:   Collective on Vec v (see explanation below)

4828:   Input Parameters:
4829: + dm - The DM
4830: . v - The Vec of points
4831: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
4832: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

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


4839:   Level: developer

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

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

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

4850: $    const PetscSFNode *cells;
4851: $    PetscInt           nFound;
4852: $    const PetscSFNode *found;
4853: $
4854: $    PetscSFGetGraph(cells,NULL,&nFound,&found,&cells);

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

4859: .keywords: point location, mesh
4860: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
4861: @*/
4862: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
4863: {

4870:   if (*cellSF) {
4871:     PetscMPIInt result;

4874:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
4875:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
4876:   } else {
4877:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
4878:   }
4879:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
4880:   if (dm->ops->locatepoints) {
4881:     (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
4882:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
4883:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
4884:   return(0);
4885: }

4887: /*@
4888:   DMGetOutputDM - Retrieve the DM associated with the layout for output

4890:   Input Parameter:
4891: . dm - The original DM

4893:   Output Parameter:
4894: . odm - The DM which provides the layout for output

4896:   Level: intermediate

4898: .seealso: VecView(), DMGetDefaultGlobalSection()
4899: @*/
4900: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
4901: {
4902:   PetscSection   section;
4903:   PetscBool      hasConstraints, ghasConstraints;

4909:   DMGetDefaultSection(dm, &section);
4910:   PetscSectionHasConstraints(section, &hasConstraints);
4911:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
4912:   if (!ghasConstraints) {
4913:     *odm = dm;
4914:     return(0);
4915:   }
4916:   if (!dm->dmBC) {
4917:     PetscDS      ds;
4918:     PetscSection newSection, gsection;
4919:     PetscSF      sf;

4921:     DMClone(dm, &dm->dmBC);
4922:     DMGetDS(dm, &ds);
4923:     DMSetDS(dm->dmBC, ds);
4924:     PetscSectionClone(section, &newSection);
4925:     DMSetDefaultSection(dm->dmBC, newSection);
4926:     PetscSectionDestroy(&newSection);
4927:     DMGetPointSF(dm->dmBC, &sf);
4928:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
4929:     DMSetDefaultGlobalSection(dm->dmBC, gsection);
4930:     PetscSectionDestroy(&gsection);
4931:   }
4932:   *odm = dm->dmBC;
4933:   return(0);
4934: }

4936: /*@
4937:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

4939:   Input Parameter:
4940: . dm - The original DM

4942:   Output Parameters:
4943: + num - The output sequence number
4944: - val - The output sequence value

4946:   Level: intermediate

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

4951: .seealso: VecView()
4952: @*/
4953: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4954: {
4959:   return(0);
4960: }

4962: /*@
4963:   DMSetOutputSequenceNumber - Set the sequence number/value for output

4965:   Input Parameters:
4966: + dm - The original DM
4967: . num - The output sequence number
4968: - val - The output sequence value

4970:   Level: intermediate

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

4975: .seealso: VecView()
4976: @*/
4977: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4978: {
4981:   dm->outputSequenceNum = num;
4982:   dm->outputSequenceVal = val;
4983:   return(0);
4984: }

4986: /*@C
4987:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

4989:   Input Parameters:
4990: + dm   - The original DM
4991: . name - The sequence name
4992: - num  - The output sequence number

4994:   Output Parameter:
4995: . val  - The output sequence value

4997:   Level: intermediate

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

5002: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
5003: @*/
5004: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
5005: {
5006:   PetscBool      ishdf5;

5013:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
5014:   if (ishdf5) {
5015: #if defined(PETSC_HAVE_HDF5)
5016:     PetscScalar value;

5018:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
5019:     *val = PetscRealPart(value);
5020: #endif
5021:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
5022:   return(0);
5023: }

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

5028:   Not collective

5030:   Input Parameter:
5031: . dm - The DM

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

5036:   Level: beginner

5038: .seealso: DMSetUseNatural(), DMCreate()
5039: @*/
5040: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
5041: {
5045:   *useNatural = dm->useNatural;
5046:   return(0);
5047: }

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

5052:   Collective on dm

5054:   Input Parameters:
5055: + dm - The DM
5056: - useNatural - The flag to build the mapping to a natural order during distribution

5058:   Level: beginner

5060: .seealso: DMGetUseNatural(), DMCreate()
5061: @*/
5062: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
5063: {
5067:   dm->useNatural = useNatural;
5068:   return(0);
5069: }


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

5075:   Not Collective

5077:   Input Parameters:
5078: + dm   - The DM object
5079: - name - The label name

5081:   Level: intermediate

5083: .keywords: mesh
5084: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5085: @*/
5086: PetscErrorCode DMCreateLabel(DM dm, const char name[])
5087: {
5088:   DMLabelLink    next  = dm->labels->next;
5089:   PetscBool      flg   = PETSC_FALSE;

5095:   while (next) {
5096:     PetscStrcmp(name, next->label->name, &flg);
5097:     if (flg) break;
5098:     next = next->next;
5099:   }
5100:   if (!flg) {
5101:     DMLabelLink tmpLabel;

5103:     PetscCalloc1(1, &tmpLabel);
5104:     DMLabelCreate(name, &tmpLabel->label);
5105:     tmpLabel->output = PETSC_TRUE;
5106:     tmpLabel->next   = dm->labels->next;
5107:     dm->labels->next = tmpLabel;
5108:   }
5109:   return(0);
5110: }

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

5115:   Not Collective

5117:   Input Parameters:
5118: + dm   - The DM object
5119: . name - The label name
5120: - point - The mesh point

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

5125:   Level: beginner

5127: .keywords: mesh
5128: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
5129: @*/
5130: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
5131: {
5132:   DMLabel        label;

5138:   DMGetLabel(dm, name, &label);
5139:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
5140:   DMLabelGetValue(label, point, value);
5141:   return(0);
5142: }

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

5147:   Not Collective

5149:   Input Parameters:
5150: + dm   - The DM object
5151: . name - The label name
5152: . point - The mesh point
5153: - value - The label value for this point

5155:   Output Parameter:

5157:   Level: beginner

5159: .keywords: mesh
5160: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
5161: @*/
5162: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5163: {
5164:   DMLabel        label;

5170:   DMGetLabel(dm, name, &label);
5171:   if (!label) {
5172:     DMCreateLabel(dm, name);
5173:     DMGetLabel(dm, name, &label);
5174:   }
5175:   DMLabelSetValue(label, point, value);
5176:   return(0);
5177: }

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

5182:   Not Collective

5184:   Input Parameters:
5185: + dm   - The DM object
5186: . name - The label name
5187: . point - The mesh point
5188: - value - The label value for this point

5190:   Output Parameter:

5192:   Level: beginner

5194: .keywords: mesh
5195: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
5196: @*/
5197: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
5198: {
5199:   DMLabel        label;

5205:   DMGetLabel(dm, name, &label);
5206:   if (!label) return(0);
5207:   DMLabelClearValue(label, point, value);
5208:   return(0);
5209: }

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

5214:   Not Collective

5216:   Input Parameters:
5217: + dm   - The DM object
5218: - name - The label name

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

5223:   Level: beginner

5225: .keywords: mesh
5226: .seealso: DMLabeGetNumValues(), DMSetLabelValue()
5227: @*/
5228: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
5229: {
5230:   DMLabel        label;

5237:   DMGetLabel(dm, name, &label);
5238:   *size = 0;
5239:   if (!label) return(0);
5240:   DMLabelGetNumValues(label, size);
5241:   return(0);
5242: }

5244: /*@C
5245:   DMGetLabelIdIS - Get the integer ids in a label

5247:   Not Collective

5249:   Input Parameters:
5250: + mesh - The DM object
5251: - name - The label name

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

5256:   Level: beginner

5258: .keywords: mesh
5259: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
5260: @*/
5261: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
5262: {
5263:   DMLabel        label;

5270:   DMGetLabel(dm, name, &label);
5271:   *ids = NULL;
5272:   if (!label) return(0);
5273:   DMLabelGetValueIS(label, ids);
5274:   return(0);
5275: }

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

5280:   Not Collective

5282:   Input Parameters:
5283: + dm - The DM object
5284: . name - The label name
5285: - value - The stratum value

5287:   Output Parameter:
5288: . size - The stratum size

5290:   Level: beginner

5292: .keywords: mesh
5293: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
5294: @*/
5295: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
5296: {
5297:   DMLabel        label;

5304:   DMGetLabel(dm, name, &label);
5305:   *size = 0;
5306:   if (!label) return(0);
5307:   DMLabelGetStratumSize(label, value, size);
5308:   return(0);
5309: }

5311: /*@C
5312:   DMGetStratumIS - Get the points in a label stratum

5314:   Not Collective

5316:   Input Parameters:
5317: + dm - The DM object
5318: . name - The label name
5319: - value - The stratum value

5321:   Output Parameter:
5322: . points - The stratum points, or NULL if the label does not exist or does not have that value

5324:   Level: beginner

5326: .keywords: mesh
5327: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
5328: @*/
5329: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
5330: {
5331:   DMLabel        label;

5338:   DMGetLabel(dm, name, &label);
5339:   *points = NULL;
5340:   if (!label) return(0);
5341:   DMLabelGetStratumIS(label, value, points);
5342:   return(0);
5343: }

5345: /*@C
5346:   DMGetStratumIS - Set the points in a label stratum

5348:   Not Collective

5350:   Input Parameters:
5351: + dm - The DM object
5352: . name - The label name
5353: . value - The stratum value
5354: - points - The stratum points

5356:   Level: beginner

5358: .keywords: mesh
5359: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
5360: @*/
5361: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
5362: {
5363:   DMLabel        label;

5370:   DMGetLabel(dm, name, &label);
5371:   if (!label) return(0);
5372:   DMLabelSetStratumIS(label, value, points);
5373:   return(0);
5374: }

5376: /*@C
5377:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

5379:   Not Collective

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

5386:   Output Parameter:

5388:   Level: beginner

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

5401:   DMGetLabel(dm, name, &label);
5402:   if (!label) return(0);
5403:   DMLabelClearStratum(label, value);
5404:   return(0);
5405: }

5407: /*@
5408:   DMGetNumLabels - Return the number of labels defined by the mesh

5410:   Not Collective

5412:   Input Parameter:
5413: . dm   - The DM object

5415:   Output Parameter:
5416: . numLabels - the number of Labels

5418:   Level: intermediate

5420: .keywords: mesh
5421: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5422: @*/
5423: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
5424: {
5425:   DMLabelLink next = dm->labels->next;
5426:   PetscInt  n    = 0;

5431:   while (next) {++n; next = next->next;}
5432:   *numLabels = n;
5433:   return(0);
5434: }

5436: /*@C
5437:   DMGetLabelName - Return the name of nth label

5439:   Not Collective

5441:   Input Parameters:
5442: + dm - The DM object
5443: - n  - the label number

5445:   Output Parameter:
5446: . name - the label name

5448:   Level: intermediate

5450: .keywords: mesh
5451: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5452: @*/
5453: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
5454: {
5455:   DMLabelLink next = dm->labels->next;
5456:   PetscInt  l    = 0;

5461:   while (next) {
5462:     if (l == n) {
5463:       *name = next->label->name;
5464:       return(0);
5465:     }
5466:     ++l;
5467:     next = next->next;
5468:   }
5469:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5470: }

5472: /*@C
5473:   DMHasLabel - Determine whether the mesh has a label of a given name

5475:   Not Collective

5477:   Input Parameters:
5478: + dm   - The DM object
5479: - name - The label name

5481:   Output Parameter:
5482: . hasLabel - PETSC_TRUE if the label is present

5484:   Level: intermediate

5486: .keywords: mesh
5487: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5488: @*/
5489: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
5490: {
5491:   DMLabelLink    next = dm->labels->next;

5498:   *hasLabel = PETSC_FALSE;
5499:   while (next) {
5500:     PetscStrcmp(name, next->label->name, hasLabel);
5501:     if (*hasLabel) break;
5502:     next = next->next;
5503:   }
5504:   return(0);
5505: }

5507: /*@C
5508:   DMGetLabel - Return the label of a given name, or NULL

5510:   Not Collective

5512:   Input Parameters:
5513: + dm   - The DM object
5514: - name - The label name

5516:   Output Parameter:
5517: . label - The DMLabel, or NULL if the label is absent

5519:   Level: intermediate

5521: .keywords: mesh
5522: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5523: @*/
5524: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
5525: {
5526:   DMLabelLink    next = dm->labels->next;
5527:   PetscBool      hasLabel;

5534:   *label = NULL;
5535:   while (next) {
5536:     PetscStrcmp(name, next->label->name, &hasLabel);
5537:     if (hasLabel) {
5538:       *label = next->label;
5539:       break;
5540:     }
5541:     next = next->next;
5542:   }
5543:   return(0);
5544: }

5546: /*@C
5547:   DMGetLabelByNum - Return the nth label

5549:   Not Collective

5551:   Input Parameters:
5552: + dm - The DM object
5553: - n  - the label number

5555:   Output Parameter:
5556: . label - the label

5558:   Level: intermediate

5560: .keywords: mesh
5561: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5562: @*/
5563: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
5564: {
5565:   DMLabelLink next = dm->labels->next;
5566:   PetscInt    l    = 0;

5571:   while (next) {
5572:     if (l == n) {
5573:       *label = next->label;
5574:       return(0);
5575:     }
5576:     ++l;
5577:     next = next->next;
5578:   }
5579:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
5580: }

5582: /*@C
5583:   DMAddLabel - Add the label to this mesh

5585:   Not Collective

5587:   Input Parameters:
5588: + dm   - The DM object
5589: - label - The DMLabel

5591:   Level: developer

5593: .keywords: mesh
5594: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5595: @*/
5596: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
5597: {
5598:   DMLabelLink    tmpLabel;
5599:   PetscBool      hasLabel;

5604:   DMHasLabel(dm, label->name, &hasLabel);
5605:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", label->name);
5606:   PetscCalloc1(1, &tmpLabel);
5607:   tmpLabel->label  = label;
5608:   tmpLabel->output = PETSC_TRUE;
5609:   tmpLabel->next   = dm->labels->next;
5610:   dm->labels->next = tmpLabel;
5611:   return(0);
5612: }

5614: /*@C
5615:   DMRemoveLabel - Remove the label from this mesh

5617:   Not Collective

5619:   Input Parameters:
5620: + dm   - The DM object
5621: - name - The label name

5623:   Output Parameter:
5624: . label - The DMLabel, or NULL if the label is absent

5626:   Level: developer

5628: .keywords: mesh
5629: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5630: @*/
5631: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
5632: {
5633:   DMLabelLink    next = dm->labels->next;
5634:   DMLabelLink    last = NULL;
5635:   PetscBool      hasLabel;

5640:   DMHasLabel(dm, name, &hasLabel);
5641:   *label = NULL;
5642:   if (!hasLabel) return(0);
5643:   while (next) {
5644:     PetscStrcmp(name, next->label->name, &hasLabel);
5645:     if (hasLabel) {
5646:       if (last) last->next       = next->next;
5647:       else      dm->labels->next = next->next;
5648:       next->next = NULL;
5649:       *label     = next->label;
5650:       PetscStrcmp(name, "depth", &hasLabel);
5651:       if (hasLabel) {
5652:         dm->depthLabel = NULL;
5653:       }
5654:       PetscFree(next);
5655:       break;
5656:     }
5657:     last = next;
5658:     next = next->next;
5659:   }
5660:   return(0);
5661: }

5663: /*@C
5664:   DMGetLabelOutput - Get the output flag for a given label

5666:   Not Collective

5668:   Input Parameters:
5669: + dm   - The DM object
5670: - name - The label name

5672:   Output Parameter:
5673: . output - The flag for output

5675:   Level: developer

5677: .keywords: mesh
5678: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5679: @*/
5680: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
5681: {
5682:   DMLabelLink    next = dm->labels->next;

5689:   while (next) {
5690:     PetscBool flg;

5692:     PetscStrcmp(name, next->label->name, &flg);
5693:     if (flg) {*output = next->output; return(0);}
5694:     next = next->next;
5695:   }
5696:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5697: }

5699: /*@C
5700:   DMSetLabelOutput - Set the output flag for a given label

5702:   Not Collective

5704:   Input Parameters:
5705: + dm     - The DM object
5706: . name   - The label name
5707: - output - The flag for output

5709:   Level: developer

5711: .keywords: mesh
5712: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
5713: @*/
5714: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
5715: {
5716:   DMLabelLink    next = dm->labels->next;

5722:   while (next) {
5723:     PetscBool flg;

5725:     PetscStrcmp(name, next->label->name, &flg);
5726:     if (flg) {next->output = output; return(0);}
5727:     next = next->next;
5728:   }
5729:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
5730: }


5733: /*@
5734:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

5736:   Collective on DM

5738:   Input Parameter:
5739: . dmA - The DM object with initial labels

5741:   Output Parameter:
5742: . dmB - The DM object with copied labels

5744:   Level: intermediate

5746:   Note: This is typically used when interpolating or otherwise adding to a mesh

5748: .keywords: mesh
5749: .seealso: DMCopyCoordinates(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection()
5750: @*/
5751: PetscErrorCode DMCopyLabels(DM dmA, DM dmB)
5752: {
5753:   PetscInt       numLabels, l;

5757:   if (dmA == dmB) return(0);
5758:   DMGetNumLabels(dmA, &numLabels);
5759:   for (l = 0; l < numLabels; ++l) {
5760:     DMLabel     label, labelNew;
5761:     const char *name;
5762:     PetscBool   flg;

5764:     DMGetLabelName(dmA, l, &name);
5765:     PetscStrcmp(name, "depth", &flg);
5766:     if (flg) continue;
5767:     DMGetLabel(dmA, name, &label);
5768:     DMLabelDuplicate(label, &labelNew);
5769:     DMAddLabel(dmB, labelNew);
5770:   }
5771:   return(0);
5772: }

5774: /*@
5775:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

5777:   Input Parameter:
5778: . dm - The DM object

5780:   Output Parameter:
5781: . cdm - The coarse DM

5783:   Level: intermediate

5785: .seealso: DMSetCoarseDM()
5786: @*/
5787: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
5788: {
5792:   *cdm = dm->coarseMesh;
5793:   return(0);
5794: }

5796: /*@
5797:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

5799:   Input Parameters:
5800: + dm - The DM object
5801: - cdm - The coarse DM

5803:   Level: intermediate

5805: .seealso: DMGetCoarseDM()
5806: @*/
5807: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
5808: {

5814:   PetscObjectReference((PetscObject)cdm);
5815:   DMDestroy(&dm->coarseMesh);
5816:   dm->coarseMesh = cdm;
5817:   return(0);
5818: }

5820: /*@
5821:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

5823:   Input Parameter:
5824: . dm - The DM object

5826:   Output Parameter:
5827: . fdm - The fine DM

5829:   Level: intermediate

5831: .seealso: DMSetFineDM()
5832: @*/
5833: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
5834: {
5838:   *fdm = dm->fineMesh;
5839:   return(0);
5840: }

5842: /*@
5843:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

5845:   Input Parameters:
5846: + dm - The DM object
5847: - fdm - The fine DM

5849:   Level: intermediate

5851: .seealso: DMGetFineDM()
5852: @*/
5853: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
5854: {

5860:   PetscObjectReference((PetscObject)fdm);
5861:   DMDestroy(&dm->fineMesh);
5862:   dm->fineMesh = fdm;
5863:   return(0);
5864: }

5866: /*=== DMBoundary code ===*/

5868: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
5869: {

5873:   PetscDSCopyBoundary(dm->prob,dmNew->prob);
5874:   return(0);
5875: }

5877: /*@C
5878:   DMAddBoundary - Add a boundary condition to the model

5880:   Input Parameters:
5881: + dm          - The DM, with a PetscDS that matches the problem being constrained
5882: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5883: . name        - The BC name
5884: . labelname   - The label defining constrained points
5885: . field       - The field to constrain
5886: . numcomps    - The number of constrained field components
5887: . comps       - An array of constrained component numbers
5888: . bcFunc      - A pointwise function giving boundary values
5889: . numids      - The number of DMLabel ids for constrained points
5890: . ids         - An array of ids for constrained points
5891: - ctx         - An optional user context for bcFunc

5893:   Options Database Keys:
5894: + -bc_<boundary name> <num> - Overrides the boundary ids
5895: - -bc_<boundary name>_comp <num> - Overrides the boundary components

5897:   Level: developer

5899: .seealso: DMGetBoundary()
5900: @*/
5901: 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)
5902: {

5907:   PetscDSAddBoundary(dm->prob,type,name,labelname,field,numcomps,comps,bcFunc,numids,ids,ctx);
5908:   return(0);
5909: }

5911: /*@
5912:   DMGetNumBoundary - Get the number of registered BC

5914:   Input Parameters:
5915: . dm - The mesh object

5917:   Output Parameters:
5918: . numBd - The number of BC

5920:   Level: intermediate

5922: .seealso: DMAddBoundary(), DMGetBoundary()
5923: @*/
5924: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
5925: {

5930:   PetscDSGetNumBoundary(dm->prob,numBd);
5931:   return(0);
5932: }

5934: /*@C
5935:   DMGetBoundary - Get a model boundary condition

5937:   Input Parameters:
5938: + dm          - The mesh object
5939: - bd          - The BC number

5941:   Output Parameters:
5942: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
5943: . name        - The BC name
5944: . labelname   - The label defining constrained points
5945: . field       - The field to constrain
5946: . numcomps    - The number of constrained field components
5947: . comps       - An array of constrained component numbers
5948: . bcFunc      - A pointwise function giving boundary values
5949: . numids      - The number of DMLabel ids for constrained points
5950: . ids         - An array of ids for constrained points
5951: - ctx         - An optional user context for bcFunc

5953:   Options Database Keys:
5954: + -bc_<boundary name> <num> - Overrides the boundary ids
5955: - -bc_<boundary name>_comp <num> - Overrides the boundary components

5957:   Level: developer

5959: .seealso: DMAddBoundary()
5960: @*/
5961: 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)
5962: {

5967:   PetscDSGetBoundary(dm->prob,bd,type,name,labelname,field,numcomps,comps,func,numids,ids,ctx);
5968:   return(0);
5969: }

5971: static PetscErrorCode DMPopulateBoundary(DM dm)
5972: {
5973:   DMBoundary *lastnext;
5974:   DSBoundary dsbound;

5978:   dsbound = dm->prob->boundary;
5979:   if (dm->boundary) {
5980:     DMBoundary next = dm->boundary;

5982:     /* quick check to see if the PetscDS has changed */
5983:     if (next->dsboundary == dsbound) return(0);
5984:     /* the PetscDS has changed: tear down and rebuild */
5985:     while (next) {
5986:       DMBoundary b = next;

5988:       next = b->next;
5989:       PetscFree(b);
5990:     }
5991:     dm->boundary = NULL;
5992:   }

5994:   lastnext = &(dm->boundary);
5995:   while (dsbound) {
5996:     DMBoundary dmbound;

5998:     PetscNew(&dmbound);
5999:     dmbound->dsboundary = dsbound;
6000:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
6001:     if (!dmbound->label) PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);
6002:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
6003:     *lastnext = dmbound;
6004:     lastnext = &(dmbound->next);
6005:     dsbound = dsbound->next;
6006:   }
6007:   return(0);
6008: }

6010: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
6011: {
6012:   DMBoundary     b;

6018:   *isBd = PETSC_FALSE;
6019:   DMPopulateBoundary(dm);
6020:   b = dm->boundary;
6021:   while (b && !(*isBd)) {
6022:     DMLabel    label = b->label;
6023:     DSBoundary dsb = b->dsboundary;

6025:     if (label) {
6026:       PetscInt i;

6028:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
6029:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
6030:       }
6031:     }
6032:     b = b->next;
6033:   }
6034:   return(0);
6035: }

6037: /*@C
6038:   DMProjectFunction - This projects the given function into the function space provided.

6040:   Input Parameters:
6041: + dm      - The DM
6042: . time    - The time
6043: . funcs   - The coordinate functions to evaluate, one per field
6044: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
6045: - mode    - The insertion mode for values

6047:   Output Parameter:
6048: . X - vector

6050:    Calling sequence of func:
6051: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

6053: +  dim - The spatial dimension
6054: .  x   - The coordinates
6055: .  Nf  - The number of fields
6056: .  u   - The output field values
6057: -  ctx - optional user-defined function context

6059:   Level: developer

6061: .seealso: DMComputeL2Diff()
6062: @*/
6063: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
6064: {
6065:   Vec            localX;

6070:   DMGetLocalVector(dm, &localX);
6071:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
6072:   DMLocalToGlobalBegin(dm, localX, mode, X);
6073:   DMLocalToGlobalEnd(dm, localX, mode, X);
6074:   DMRestoreLocalVector(dm, &localX);
6075:   return(0);
6076: }

6078: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
6079: {

6085:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLocal",((PetscObject)dm)->type_name);
6086:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
6087:   return(0);
6088: }

6090: 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)
6091: {

6097:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
6098:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
6099:   return(0);
6100: }

6102: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
6103:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
6104:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6105:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6106:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6107:                                    InsertMode mode, Vec localX)
6108: {

6115:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
6116:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
6117:   return(0);
6118: }

6120: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
6121:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
6122:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6123:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
6124:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
6125:                                         InsertMode mode, Vec localX)
6126: {

6133:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMProjectFieldLocal",((PetscObject)dm)->type_name);
6134:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
6135:   return(0);
6136: }

6138: /*@C
6139:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

6141:   Input Parameters:
6142: + dm    - The DM
6143: . time  - The time
6144: . funcs - The functions to evaluate for each field component
6145: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6146: - X     - The coefficient vector u_h

6148:   Output Parameter:
6149: . diff - The diff ||u - u_h||_2

6151:   Level: developer

6153: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6154: @*/
6155: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
6156: {

6162:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2Diff",((PetscObject)dm)->type_name);
6163:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
6164:   return(0);
6165: }

6167: /*@C
6168:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

6170:   Input Parameters:
6171: + dm    - The DM
6172: , time  - The time
6173: . funcs - The gradient functions to evaluate for each field component
6174: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6175: . X     - The coefficient vector u_h
6176: - n     - The vector to project along

6178:   Output Parameter:
6179: . diff - The diff ||(grad u - grad u_h) . n||_2

6181:   Level: developer

6183: .seealso: DMProjectFunction(), DMComputeL2Diff()
6184: @*/
6185: 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)
6186: {

6192:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
6193:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
6194:   return(0);
6195: }

6197: /*@C
6198:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

6200:   Input Parameters:
6201: + dm    - The DM
6202: . time  - The time
6203: . funcs - The functions to evaluate for each field component
6204: . ctxs  - Optional array of contexts to pass to each function, or NULL.
6205: - X     - The coefficient vector u_h

6207:   Output Parameter:
6208: . diff - The array of differences, ||u^f - u^f_h||_2

6210:   Level: developer

6212: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
6213: @*/
6214: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
6215: {

6221:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
6222:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
6223:   return(0);
6224: }

6226: /*@C
6227:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
6228:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

6230:   Collective on dm

6232:   Input parameters:
6233: + dm - the pre-adaptation DM object
6234: - label - label with the flags

6236:   Output parameters:
6237: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

6239:   Level: intermediate

6241: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
6242: @*/
6243: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
6244: {

6251:   *dmAdapt = NULL;
6252:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
6253:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
6254:   return(0);
6255: }

6257: /*@C
6258:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

6260:   Input Parameters:
6261: + dm - The DM object
6262: . metric - The metric to which the mesh is adapted, defined vertex-wise.
6263: - 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_".

6265:   Output Parameter:
6266: . dmAdapt  - Pointer to the DM object containing the adapted mesh

6268:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

6270:   Level: advanced

6272: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
6273: @*/
6274: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
6275: {

6283:   *dmAdapt = NULL;
6284:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
6285:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
6286:   return(0);
6287: }

6289: /*@C
6290:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

6292:  Not Collective

6294:  Input Parameter:
6295:  . dm    - The DM

6297:  Output Parameter:
6298:  . nranks - the number of neighbours
6299:  . ranks - the neighbors ranks

6301:  Notes:
6302:  Do not free the array, it is freed when the DM is destroyed.

6304:  Level: beginner

6306:  .seealso: DMDAGetNeighbors(), PetscSFGetRanks()
6307: @*/
6308: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
6309: {

6314:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implemnt DMGetNeighbors",((PetscObject)dm)->type_name);
6315:   (dm->ops->getneighbors)(dm,nranks,ranks);
6316:   return(0);
6317: }

6319: #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */

6321: /*
6322:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
6323:     This has be a different function because it requires DM which is not defined in the Mat library
6324: */
6325: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
6326: {

6330:   if (coloring->ctype == IS_COLORING_LOCAL) {
6331:     Vec x1local;
6332:     DM  dm;
6333:     MatGetDM(J,&dm);
6334:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
6335:     DMGetLocalVector(dm,&x1local);
6336:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
6337:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
6338:     x1   = x1local;
6339:   }
6340:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
6341:   if (coloring->ctype == IS_COLORING_LOCAL) {
6342:     DM  dm;
6343:     MatGetDM(J,&dm);
6344:     DMRestoreLocalVector(dm,&x1);
6345:   }
6346:   return(0);
6347: }

6349: /*@
6350:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

6352:     Input Parameter:
6353: .    coloring - the MatFDColoring object

6355:     Developer Notes: this routine exists because the PETSc Mat library does not know about the DM objects

6357:     Level: advanced

6359: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
6360: @*/
6361: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
6362: {
6364:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
6365:   return(0);
6366: }