Actual source code: dm.c

petsc-3.14.6 2021-03-30
Report Typos and Errors
  1: #include <petscvec.h>
  2: #include <petsc/private/dmimpl.h>
  3: #include <petsc/private/dmlabelimpl.h>
  4: #include <petsc/private/petscdsimpl.h>
  5: #include <petscdmplex.h>
  6: #include <petscdmfield.h>
  7: #include <petscsf.h>
  8: #include <petscds.h>

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

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

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

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

 27:   Collective

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

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

 35:   Level: beginner

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

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

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

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

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

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

 97:   Collective

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

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

105:   Level: beginner

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

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

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

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

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

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

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

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

186:    Logically Collective on da

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

192:    Options Database:
193: .   -dm_vec_type ctype

195:    Level: intermediate

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

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

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

213:    Logically Collective on da

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

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

221:    Level: intermediate

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

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

236:   Not collective

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

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

244:   Level: intermediate

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

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

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

262:   Not collective

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

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

270:   Level: intermediate

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

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

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

288:    Logically Collective on dm

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

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

297:    Level: intermediate

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

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

313:    Logically Collective on dm

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

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

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

324:    Level: intermediate

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

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

340:    Logically Collective on dm

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

346:    Options Database:
347: .   -dm_mat_type ctype

349:    Level: intermediate

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

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

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

367:    Logically Collective on dm

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

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

375:    Options Database:
376: .   -dm_mat_type ctype

378:    Level: intermediate

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

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

393:   Not collective

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

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

401:   Level: intermediate

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

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

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

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

422:   Not collective

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

428:   Level: intermediate

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


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

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

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

451:    Logically Collective on dm

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

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

461:    Level: advanced

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

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

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

485:    Logically Collective on dm

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

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

495:    Level: advanced

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

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

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

513:    Not Collective

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

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

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

525:    Level: advanced

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

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

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

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

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

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

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

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

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

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

591:     Collective on dm

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

596:     Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

769:     Collective on dm

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

774:     Level: developer

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

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

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

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

796:     Collective on dm

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

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

807:     DMPLEX Specific Checks
808: +   -dm_plex_check_symmetry        - Check that the adjacency information in the mesh is symmetric - DMPlexCheckSymmetry()
809: .   -dm_plex_check_skeleton        - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - DMPlexCheckSkeleton()
810: .   -dm_plex_check_faces           - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - DMPlexCheckFaces()
811: .   -dm_plex_check_geometry        - Check that cells have positive volume - DMPlexCheckGeometry()
812: .   -dm_plex_check_pointsf         - Check some necessary conditions for PointSF - DMPlexCheckPointSF()
813: .   -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - DMPlexCheckInterfaceCones()
814: -   -dm_plex_check_all             - Perform all the checks above

816:     Level: intermediate

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

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

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

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

856:    Collective on DM

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

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

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

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

879:     Collective on dm

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

885:     Level: beginner

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

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

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

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

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

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

935:     Collective on dm

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

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

943:     Level: beginner

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

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

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

960:     VecGetDM(*vec,&vdm);
961:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
962:   }
963:   return(0);
964: }

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

969:     Not Collective

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

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

977:     Level: beginner

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

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

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

994:     VecGetDM(*vec,&vdm);
995:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
996:   }
997:   return(0);
998: }

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

1003:    Collective on dm

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

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

1011:    Level: intermediate

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

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

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

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

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

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

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

1084:    Not Collective

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

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

1092:    Level: intermediate

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

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

1109:     Collective on dmc

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

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

1119:     Level: developer

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

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


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

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

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

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

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

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

1158:   Level: developer

1160: .seealso: DMCreateInterpolation()

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

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

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

1182:     Collective on dmc

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

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


1192:     Level: developer

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


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

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

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

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

1220:     Collective on dac

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

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

1229:     Level: developer

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

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

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

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

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

1256:   Collective on dac

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

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

1265:   Level: developer

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

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

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

1285:     Collective on dm

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

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

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

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

1300:     Level: developer

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

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

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

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

1320:     Collective on dm

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

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

1328:     Level: beginner

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

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

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

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

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

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

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

1360:     MatGetDM(*mat,&mdm);
1361:     if (!mdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the matrix\n",((PetscObject)dm)->type_name);
1362:   }
1363:   /* Handle nullspace and near nullspace */
1364:   if (dm->Nf) {
1365:     MatNullSpace nullSpace;
1366:     PetscInt     Nf;

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

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

1390:   Logically Collective on dm

1392:   Input Parameter:
1393: + dm - the DM
1394: - only - PETSC_TRUE if only want preallocation

1396:   Level: developer
1397: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1398: @*/
1399: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1400: {
1403:   dm->prealloc_only = only;
1404:   return(0);
1405: }

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

1411:   Logically Collective on dm

1413:   Input Parameter:
1414: + dm - the DM
1415: - only - PETSC_TRUE if only want matrix stucture

1417:   Level: developer
1418: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1419: @*/
1420: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1421: {
1424:   dm->structure_only = only;
1425:   return(0);
1426: }

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

1431:   Not Collective

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

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

1441:   Level: developer

1443: .seealso DMDestroy(), DMCreate()
1444: @*/
1445: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1446: {
1448:   DMWorkLink     link;
1449:   PetscMPIInt    dsize;

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

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

1479:   Not Collective

1481:   Input Parameters:
1482: + dm - the DM object
1483: . count - The minium size
1484: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1486:   Output Parameter:
1487: . array - the work array

1489:   Level: developer

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

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

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

1517:   Logically collective on DM

1519:   Input Parameters:
1520: + dm     - The DM
1521: . field  - The field number for the nullspace
1522: - nullsp - A callback to create the nullspace

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

1532:   This function is currently not available from Fortran.

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

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

1548:   Not collective

1550:   Input Parameters:
1551: + dm     - The DM
1552: - field  - The field number for the nullspace

1554:   Output Parameter:
1555: . nullsp - A callback to create the nullspace

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

1565:   This function is currently not available from Fortran.

1567: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1568: */
1569: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1570: {
1574:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1575:   *nullsp = dm->nullspaceConstructors[field];
1576:   return(0);
1577: }

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

1582:   Logically collective on DM

1584:   Input Parameters:
1585: + dm     - The DM
1586: . field  - The field number for the nullspace
1587: - nullsp - A callback to create the near-nullspace

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

1597:   This function is currently not available from Fortran.

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

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

1613:   Not collective

1615:   Input Parameters:
1616: + dm     - The DM
1617: - field  - The field number for the nullspace

1619:   Output Parameter:
1620: . nullsp - A callback to create the near-nullspace

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

1630:   This function is currently not available from Fortran.

1632: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1633: */
1634: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1635: {
1639:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1640:   *nullsp = dm->nearnullspaceConstructors[field];
1641:   return(0);
1642: }

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

1647:   Not collective

1649:   Input Parameter:
1650: . dm - the DM object

1652:   Output Parameters:
1653: + numFields  - The number of fields (or NULL if not requested)
1654: . fieldNames - The name for each field (or NULL if not requested)
1655: - fields     - The global indices for each field (or NULL if not requested)

1657:   Level: intermediate

1659:   Notes:
1660:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1661:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1662:   PetscFree().

1664: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1665: @*/
1666: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1667: {
1668:   PetscSection   section, sectionGlobal;

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

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

1701:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1702:       if (gdof > 0) {
1703:         for (f = 0; f < nF; ++f) {
1704:           PetscInt fdof, fcdof, fpdof;

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

1724:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1725:       if (gdof > 0) {
1726:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1727:         for (f = 0; f < nF; ++f) {
1728:           PetscInt fdof, fcdof, fc;

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

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

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


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

1775:   Not collective

1777:   Input Parameter:
1778: . dm - the DM object

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

1786:   Level: intermediate

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

1793: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1794: @*/
1795: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1796: {

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

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

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

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

1858:   Not collective

1860:   Input Parameters:
1861: + dm        - The DM object
1862: . numFields - The number of fields in this subproblem
1863: - fields    - The field numbers of the selected fields

1865:   Output Parameters:
1866: + is - The global indices for the subproblem
1867: - subdm - The DM for the subproblem

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

1871:   Level: intermediate

1873: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1874: @*/
1875: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1876: {

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

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

1892:   Not collective

1894:   Input Parameter:
1895: + dms - The DM objects
1896: - len - The number of DMs

1898:   Output Parameters:
1899: + is - The global indices for the subproblem, or NULL
1900: - superdm - The DM for the superproblem

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

1904:   Level: intermediate

1906: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1907: @*/
1908: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1909: {
1910:   PetscInt       i;

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


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

1935:   Not collective

1937:   Input Parameter:
1938: . dm - the DM object

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

1947:   Level: intermediate

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

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

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


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

1995:   Not collective

1997:   Input Parameters:
1998: + dm - the DM object
1999: . n  - the number of subdomain scatters
2000: - subdms - the local subdomains

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

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

2014:   Level: developer

2016: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2017: @*/
2018: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2019: {

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

2030: /*@
2031:   DMRefine - Refines a DM object

2033:   Collective on dm

2035:   Input Parameter:
2036: + dm   - the DM object
2037: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2039:   Output Parameter:
2040: . dmf - the refined DM, or NULL

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

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

2047:   Level: developer

2049: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2050: @*/
2051: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2052: {
2053:   PetscErrorCode   ierr;
2054:   DMRefineHookLink link;

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

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

2066:     (*dmf)->ctx       = dm->ctx;
2067:     (*dmf)->leveldown = dm->leveldown;
2068:     (*dmf)->levelup   = dm->levelup + 1;

2070:     DMSetMatType(*dmf,dm->mattype);
2071:     for (link=dm->refinehook; link; link=link->next) {
2072:       if (link->refinehook) {
2073:         (*link->refinehook)(dm,*dmf,link->ctx);
2074:       }
2075:     }
2076:   }
2077:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2078:   return(0);
2079: }

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

2084:    Logically Collective

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

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

2095: +  coarse - coarse level DM
2096: .  fine - fine level DM to interpolate problem to
2097: -  ctx - optional user-defined function context

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

2102: +  coarse - coarse level DM
2103: .  interp - matrix interpolating a coarse-level solution to the finer grid
2104: .  fine - fine level DM to update
2105: -  ctx - optional user-defined function context

2107:    Level: advanced

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

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

2114:    This function is currently not available from Fortran.

2116: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2117: @*/
2118: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2119: {
2120:   PetscErrorCode   ierr;
2121:   DMRefineHookLink link,*p;

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

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

2140:    Logically Collective

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

2148:    Level: advanced

2150:    Notes:
2151:    This function does nothing if the hook is not in the list.

2153:    This function is currently not available from Fortran.

2155: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2156: @*/
2157: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2158: {
2159:   PetscErrorCode   ierr;
2160:   DMRefineHookLink link,*p;

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

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

2178:    Collective if any hooks are

2180:    Input Arguments:
2181: +  coarse - coarser DM to use as a base
2182: .  interp - interpolation matrix, apply using MatInterpolate()
2183: -  fine - finer DM to update

2185:    Level: developer

2187: .seealso: DMRefineHookAdd(), MatInterpolate()
2188: @*/
2189: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2190: {
2191:   PetscErrorCode   ierr;
2192:   DMRefineHookLink link;

2195:   for (link=fine->refinehook; link; link=link->next) {
2196:     if (link->interphook) {
2197:       (*link->interphook)(coarse,interp,fine,link->ctx);
2198:     }
2199:   }
2200:   return(0);
2201: }

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

2206:     Not Collective

2208:     Input Parameter:
2209: .   dm - the DM object

2211:     Output Parameter:
2212: .   level - number of refinements

2214:     Level: developer

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

2218: @*/
2219: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2220: {
2223:   *level = dm->levelup;
2224:   return(0);
2225: }

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

2230:     Not Collective

2232:     Input Parameter:
2233: +   dm - the DM object
2234: -   level - number of refinements

2236:     Level: advanced

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

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

2243: @*/
2244: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2245: {
2248:   dm->levelup = level;
2249:   return(0);
2250: }

2252: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2253: {
2257:   *tdm = dm->transformDM;
2258:   return(0);
2259: }

2261: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2262: {
2266:   *tv = dm->transform;
2267:   return(0);
2268: }

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

2273:   Input Parameter:
2274: . dm - The DM

2276:   Output Parameter:
2277: . flg - PETSC_TRUE if a basis transformation should be done

2279:   Level: developer

2281: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2282: @*/
2283: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2284: {
2285:   Vec            tv;

2291:   DMGetBasisTransformVec_Internal(dm, &tv);
2292:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2293:   return(0);
2294: }

2296: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2297: {
2298:   PetscSection   s, ts;
2299:   PetscScalar   *ta;
2300:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

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

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

2345: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2346: {

2352:   newdm->transformCtx       = dm->transformCtx;
2353:   newdm->transformSetUp     = dm->transformSetUp;
2354:   newdm->transformDestroy   = NULL;
2355:   newdm->transformGetMatrix = dm->transformGetMatrix;
2356:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
2357:   return(0);
2358: }

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

2363:    Logically Collective

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

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

2374: +  dm - global DM
2375: .  g - global vector
2376: .  mode - mode
2377: .  l - local vector
2378: -  ctx - optional user-defined function context


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

2384: +  global - global DM
2385: -  ctx - optional user-defined function context

2387:    Level: advanced

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

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

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

2418:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2419:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2420:     PetscInt nRows;

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

2441: /*@
2442:     DMGlobalToLocal - update local vectors from global vector

2444:     Neighbor-wise Collective on dm

2446:     Input Parameters:
2447: +   dm - the DM object
2448: .   g - the global vector
2449: .   mode - INSERT_VALUES or ADD_VALUES
2450: -   l - the local vector

2452:     Notes:
2453:     The communication involved in this update can be overlapped with computation by using
2454:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2456:     Level: beginner

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

2460: @*/
2461: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2462: {

2466:   DMGlobalToLocalBegin(dm,g,mode,l);
2467:   DMGlobalToLocalEnd(dm,g,mode,l);
2468:   return(0);
2469: }

2471: /*@
2472:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2474:     Neighbor-wise Collective on dm

2476:     Input Parameters:
2477: +   dm - the DM object
2478: .   g - the global vector
2479: .   mode - INSERT_VALUES or ADD_VALUES
2480: -   l - the local vector

2482:     Level: intermediate

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

2486: @*/
2487: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2488: {
2489:   PetscSF                 sf;
2490:   PetscErrorCode          ierr;
2491:   DMGlobalToLocalHookLink link;


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

2507:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2508:     VecGetArrayInPlace_Internal(l, &lArray, &lmtype);
2509:     VecGetArrayReadInPlace_Internal(g, &gArray, &gmtype);
2510:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray);
2511:     VecRestoreArrayInPlace(l, &lArray);
2512:     VecRestoreArrayReadInPlace(g, &gArray);
2513:   } else {
2514:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
2515:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2516:   }
2517:   return(0);
2518: }

2520: /*@
2521:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2523:     Neighbor-wise Collective on dm

2525:     Input Parameters:
2526: +   dm - the DM object
2527: .   g - the global vector
2528: .   mode - INSERT_VALUES or ADD_VALUES
2529: -   l - the local vector

2531:     Level: intermediate

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

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

2548:   DMGetSectionSF(dm, &sf);
2549:   DMHasBasisTransform(dm, &transform);
2550:   if (sf) {
2551:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

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

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

2573:    Logically Collective

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

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

2584: +  dm - global DM
2585: .  l - local vector
2586: .  mode - mode
2587: .  g - global vector
2588: -  ctx - optional user-defined function context


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

2594: +  global - global DM
2595: .  l - local vector
2596: .  mode - mode
2597: .  g - global vector
2598: -  ctx - optional user-defined function context

2600:    Level: advanced

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

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

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

2631:   DMGetDefaultConstraints(dm,&cSec,&cMat);
2632:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2633:     PetscInt nRows;

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

2662:     Neighbor-wise Collective on dm

2664:     Input Parameters:
2665: +   dm - the DM object
2666: .   l - the local vector
2667: .   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.
2668: -   g - the global vector

2670:     Notes:
2671:     The communication involved in this update can be overlapped with computation by using
2672:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2677:     Level: beginner

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

2681: @*/
2682: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2683: {

2687:   DMLocalToGlobalBegin(dm,l,mode,g);
2688:   DMLocalToGlobalEnd(dm,l,mode,g);
2689:   return(0);
2690: }

2692: /*@
2693:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2695:     Neighbor-wise Collective on dm

2697:     Input Parameters:
2698: +   dm - the DM object
2699: .   l - the local vector
2700: .   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.
2701: -   g - the global vector

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

2707:     Level: intermediate

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

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

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

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

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

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

2821: /*@
2822:     DMLocalToGlobalEnd - updates global vectors from local vectors

2824:     Neighbor-wise Collective on dm

2826:     Input Parameters:
2827: +   dm - the DM object
2828: .   l - the local vector
2829: .   mode - INSERT_VALUES or ADD_VALUES
2830: -   g - the global vector

2832:     Level: intermediate

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

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

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

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

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

2896:    Neighbor-wise Collective on dm

2898:    Input Parameters:
2899: +  dm - the DM object
2900: .  g - the original local vector
2901: -  mode - one of INSERT_VALUES or ADD_VALUES

2903:    Output Parameter:
2904: .  l  - the local vector with correct ghost values

2906:    Level: intermediate

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

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

2916: @*/
2917: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2918: {
2919:   PetscErrorCode          ierr;

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

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

2933:    Neighbor-wise Collective on dm

2935:    Input Parameters:
2936: +  da - the DM object
2937: .  g - the original local vector
2938: -  mode - one of INSERT_VALUES or ADD_VALUES

2940:    Output Parameter:
2941: .  l  - the local vector with correct ghost values

2943:    Level: intermediate

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

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

2953: @*/
2954: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2955: {
2956:   PetscErrorCode          ierr;

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


2966: /*@
2967:     DMCoarsen - Coarsens a DM object

2969:     Collective on dm

2971:     Input Parameter:
2972: +   dm - the DM object
2973: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2975:     Output Parameter:
2976: .   dmc - the coarsened DM

2978:     Level: developer

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

2982: @*/
2983: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
2984: {
2985:   PetscErrorCode    ierr;
2986:   DMCoarsenHookLink link;

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

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

3013:    Logically Collective

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

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

3024: +  fine - fine level DM
3025: .  coarse - coarse level DM to restrict problem to
3026: -  ctx - optional user-defined function context

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

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

3038:    Level: advanced

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

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

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

3048:    This function is currently not available from Fortran.

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

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

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

3074:    Logically Collective

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

3082:    Level: advanced

3084:    Notes:
3085:    This function does nothing if the hook is not in the list.

3087:    This function is currently not available from Fortran.

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

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


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

3113:    Collective if any hooks are

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

3122:    Level: developer

3124: .seealso: DMCoarsenHookAdd(), MatRestrict()
3125: @*/
3126: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3127: {
3128:   PetscErrorCode    ierr;
3129:   DMCoarsenHookLink link;

3132:   for (link=fine->coarsenhook; link; link=link->next) {
3133:     if (link->restricthook) {
3134:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3135:     }
3136:   }
3137:   return(0);
3138: }

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

3143:    Logically Collective on global

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


3152:    Calling sequence for ddhook:
3153: $    ddhook(DM global,DM block,void *ctx)

3155: +  global - global DM
3156: .  block  - block DM
3157: -  ctx - optional user-defined function context

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

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

3168:    Level: advanced

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

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

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

3178:    This function is currently not available from Fortran.

3180: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3181: @*/
3182: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3183: {
3184:   PetscErrorCode      ierr;
3185:   DMSubDomainHookLink link,*p;

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

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

3204:    Logically Collective

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

3212:    Level: advanced

3214:    Notes:

3216:    This function is currently not available from Fortran.

3218: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3219: @*/
3220: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3221: {
3222:   PetscErrorCode      ierr;
3223:   DMSubDomainHookLink link,*p;

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

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

3241:    Collective if any hooks are

3243:    Input Arguments:
3244: +  fine - finer DM to use as a base
3245: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3246: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3247: -  coarse - coarer DM to update

3249:    Level: developer

3251: .seealso: DMCoarsenHookAdd(), MatRestrict()
3252: @*/
3253: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3254: {
3255:   PetscErrorCode      ierr;
3256:   DMSubDomainHookLink link;

3259:   for (link=global->subdomainhook; link; link=link->next) {
3260:     if (link->restricthook) {
3261:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3262:     }
3263:   }
3264:   return(0);
3265: }

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

3270:     Not Collective

3272:     Input Parameter:
3273: .   dm - the DM object

3275:     Output Parameter:
3276: .   level - number of coarsenings

3278:     Level: developer

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

3282: @*/
3283: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3284: {
3288:   *level = dm->leveldown;
3289:   return(0);
3290: }

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

3295:     Not Collective

3297:     Input Parameters:
3298: +   dm - the DM object
3299: -   level - number of coarsenings

3301:     Level: developer

3303: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3304: @*/
3305: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3306: {
3309:   dm->leveldown = level;
3310:   return(0);
3311: }



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

3318:     Collective on dm

3320:     Input Parameter:
3321: +   dm - the DM object
3322: -   nlevels - the number of levels of refinement

3324:     Output Parameter:
3325: .   dmf - the refined DM hierarchy

3327:     Level: developer

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

3331: @*/
3332: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3333: {

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

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

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

3357:     Collective on dm

3359:     Input Parameter:
3360: +   dm - the DM object
3361: -   nlevels - the number of levels of coarsening

3363:     Output Parameter:
3364: .   dmc - the coarsened DM hierarchy

3366:     Level: developer

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

3370: @*/
3371: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3372: {

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

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

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

3396:     Not Collective

3398:     Input Parameters:
3399: +   dm - the DM object
3400: -   destroy - the destroy function

3402:     Level: intermediate

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

3406: @*/
3407: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3408: {
3411:   dm->ctxdestroy = destroy;
3412:   return(0);
3413: }

3415: /*@
3416:     DMSetApplicationContext - Set a user context into a DM object

3418:     Not Collective

3420:     Input Parameters:
3421: +   dm - the DM object
3422: -   ctx - the user context

3424:     Level: intermediate

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

3428: @*/
3429: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3430: {
3433:   dm->ctx = ctx;
3434:   return(0);
3435: }

3437: /*@
3438:     DMGetApplicationContext - Gets a user context from a DM object

3440:     Not Collective

3442:     Input Parameter:
3443: .   dm - the DM object

3445:     Output Parameter:
3446: .   ctx - the user context

3448:     Level: intermediate

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

3452: @*/
3453: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3454: {
3457:   *(void**)ctx = dm->ctx;
3458:   return(0);
3459: }

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

3464:     Logically Collective on dm

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

3470:     Level: intermediate

3472: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
3473:          DMSetJacobian()

3475: @*/
3476: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3477: {
3480:   dm->ops->computevariablebounds = f;
3481:   return(0);
3482: }

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

3487:     Not Collective

3489:     Input Parameter:
3490: .   dm - the DM object to destroy

3492:     Output Parameter:
3493: .   flg - PETSC_TRUE if the variable bounds function exists

3495:     Level: developer

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

3499: @*/
3500: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3501: {
3505:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3506:   return(0);
3507: }

3509: /*@C
3510:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3512:     Logically Collective on dm

3514:     Input Parameters:
3515: .   dm - the DM object

3517:     Output parameters:
3518: +   xl - lower bound
3519: -   xu - upper bound

3521:     Level: advanced

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

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

3528: @*/
3529: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3530: {

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

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

3545:     Not Collective

3547:     Input Parameter:
3548: .   dm - the DM object

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

3553:     Level: developer

3555: .seealso DMCreateColoring()

3557: @*/
3558: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3559: {
3563:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3564:   return(0);
3565: }

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

3570:     Not Collective

3572:     Input Parameter:
3573: .   dm - the DM object

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

3578:     Level: developer

3580: .seealso DMCreateRestriction()

3582: @*/
3583: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3584: {
3588:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3589:   return(0);
3590: }


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

3596:     Not Collective

3598:     Input Parameter:
3599: .   dm - the DM object

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

3604:     Level: developer

3606: .seealso DMCreateInjection()

3608: @*/
3609: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3610: {

3616:   if (dm->ops->hascreateinjection) {
3617:     (*dm->ops->hascreateinjection)(dm,flg);
3618:   } else {
3619:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3620:   }
3621:   return(0);
3622: }

3624: PetscFunctionList DMList              = NULL;
3625: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3627: /*@C
3628:   DMSetType - Builds a DM, for a particular DM implementation.

3630:   Collective on dm

3632:   Input Parameters:
3633: + dm     - The DM object
3634: - method - The name of the DM type

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

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

3642:   Level: intermediate

3644: .seealso: DMGetType(), DMCreate()
3645: @*/
3646: PetscErrorCode  DMSetType(DM dm, DMType method)
3647: {
3648:   PetscErrorCode (*r)(DM);
3649:   PetscBool      match;

3654:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3655:   if (match) return(0);

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

3661:   if (dm->ops->destroy) {
3662:     (*dm->ops->destroy)(dm);
3663:   }
3664:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3665:   PetscObjectChangeTypeName((PetscObject)dm,method);
3666:   (*r)(dm);
3667:   return(0);
3668: }

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

3673:   Not Collective

3675:   Input Parameter:
3676: . dm  - The DM

3678:   Output Parameter:
3679: . type - The DM type name

3681:   Level: intermediate

3683: .seealso: DMSetType(), DMCreate()
3684: @*/
3685: PetscErrorCode  DMGetType(DM dm, DMType *type)
3686: {

3692:   DMRegisterAll();
3693:   *type = ((PetscObject)dm)->type_name;
3694:   return(0);
3695: }

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

3700:   Collective on dm

3702:   Input Parameters:
3703: + dm - the DM
3704: - newtype - new DM type (use "same" for the same type)

3706:   Output Parameter:
3707: . M - pointer to new DM

3709:   Notes:
3710:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3711:   the MPI communicator of the generated DM is always the same as the communicator
3712:   of the input DM.

3714:   Level: intermediate

3716: .seealso: DMCreate()
3717: @*/
3718: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3719: {
3720:   DM             B;
3721:   char           convname[256];
3722:   PetscBool      sametype/*, issame */;

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

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

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

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

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

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

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

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

3803: /*--------------------------------------------------------------------------------------------------------------------*/

3805: /*@C
3806:   DMRegister -  Adds a new DM component implementation

3808:   Not Collective

3810:   Input Parameters:
3811: + name        - The name of a new user-defined creation routine
3812: - create_func - The creation routine itself

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


3818:   Sample usage:
3819: .vb
3820:     DMRegister("my_da", MyDMCreate);
3821: .ve

3823:   Then, your DM type can be chosen with the procedural interface via
3824: .vb
3825:     DMCreate(MPI_Comm, DM *);
3826:     DMSetType(DM,"my_da");
3827: .ve
3828:    or at runtime via the option
3829: .vb
3830:     -da_type my_da
3831: .ve

3833:   Level: advanced

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

3837: @*/
3838: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3839: {

3843:   DMInitializePackage();
3844:   PetscFunctionListAdd(&DMList,sname,function);
3845:   return(0);
3846: }

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

3851:   Collective on viewer

3853:   Input Parameters:
3854: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3855:            some related function before a call to DMLoad().
3856: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3857:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3859:    Level: intermediate

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

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

3873: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3874: @*/
3875: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3876: {
3877:   PetscBool      isbinary, ishdf5;

3883:   PetscViewerCheckReadable(viewer);
3884:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3885:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3886:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3887:   if (isbinary) {
3888:     PetscInt classid;
3889:     char     type[256];

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

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

3906:   Not collective

3908:   Input Parameter:
3909: . dm - the DM

3911:   Output Parameters:
3912: + lmin - local minimum coordinates (length coord dim, optional)
3913: - lmax - local maximim coordinates (length coord dim, optional)

3915:   Level: beginner

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


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

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

3950:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3951:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
3952:   }
3953:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
3954:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
3955:   return(0);
3956: }

3958: /*@
3959:   DMGetBoundingBox - Returns the global bounding box for the DM.

3961:   Collective

3963:   Input Parameter:
3964: . dm - the DM

3966:   Output Parameters:
3967: + gmin - global minimum coordinates (length coord dim, optional)
3968: - gmax - global maximim coordinates (length coord dim, optional)

3970:   Level: beginner

3972: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
3973: @*/
3974: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
3975: {
3976:   PetscReal      lmin[3], lmax[3];
3977:   PetscInt       cdim;
3978:   PetscMPIInt    count;

3983:   DMGetCoordinateDim(dm, &cdim);
3984:   PetscMPIIntCast(cdim, &count);
3985:   DMGetLocalBoundingBox(dm, lmin, lmax);
3986:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
3987:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
3988:   return(0);
3989: }

3991: /******************************** FEM Support **********************************/

3993: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
3994: {
3995:   PetscInt       f;

3999:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4000:   for (f = 0; f < len; ++f) {
4001:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
4002:   }
4003:   return(0);
4004: }

4006: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4007: {
4008:   PetscInt       f, g;

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

4023: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4024: {
4025:   PetscInt          localSize, bs;
4026:   PetscMPIInt       size;
4027:   Vec               x, xglob;
4028:   const PetscScalar *xarray;
4029:   PetscErrorCode    ierr;

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

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

4057:   Input Parameter:
4058: . dm - The DM

4060:   Output Parameter:
4061: . section - The PetscSection

4063:   Options Database Keys:
4064: . -dm_petscsection_view - View the Section created by the DM

4066:   Level: advanced

4068:   Notes:
4069:   Use DMGetLocalSection() in new code.

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

4073: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4074: @*/
4075: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4076: {

4080:   DMGetLocalSection(dm,section);
4081:   return(0);
4082: }

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

4087:   Input Parameter:
4088: . dm - The DM

4090:   Output Parameter:
4091: . section - The PetscSection

4093:   Options Database Keys:
4094: . -dm_petscsection_view - View the Section created by the DM

4096:   Level: intermediate

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

4100: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4101: @*/
4102: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4103: {

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

4112:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
4113:     (*dm->ops->createlocalsection)(dm);
4114:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
4115:   }
4116:   *section = dm->localSection;
4117:   return(0);
4118: }

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

4123:   Input Parameters:
4124: + dm - The DM
4125: - section - The PetscSection

4127:   Level: advanced

4129:   Notes:
4130:   Use DMSetLocalSection() in new code.

4132:   Any existing Section will be destroyed

4134: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4135: @*/
4136: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4137: {

4141:   DMSetLocalSection(dm,section);
4142:   return(0);
4143: }

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

4148:   Input Parameters:
4149: + dm - The DM
4150: - section - The PetscSection

4152:   Level: intermediate

4154:   Note: Any existing Section will be destroyed

4156: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4157: @*/
4158: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4159: {
4160:   PetscInt       numFields = 0;
4161:   PetscInt       f;

4167:   PetscObjectReference((PetscObject)section);
4168:   PetscSectionDestroy(&dm->localSection);
4169:   dm->localSection = section;
4170:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
4171:   if (numFields) {
4172:     DMSetNumFields(dm, numFields);
4173:     for (f = 0; f < numFields; ++f) {
4174:       PetscObject disc;
4175:       const char *name;

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

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

4190:   not collective

4192:   Input Parameter:
4193: . dm - The DM

4195:   Output Parameter:
4196: + 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.
4197: - 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.

4199:   Level: advanced

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

4203: .seealso: DMSetDefaultConstraints()
4204: @*/
4205: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
4206: {

4211:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
4212:   if (section) {*section = dm->defaultConstraintSection;}
4213:   if (mat) {*mat = dm->defaultConstraintMat;}
4214:   return(0);
4215: }

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

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

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

4224:   collective on dm

4226:   Input Parameters:
4227: + dm - The DM
4228: + 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).
4229: - 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).

4231:   Level: advanced

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

4235: .seealso: DMGetDefaultConstraints()
4236: @*/
4237: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
4238: {
4239:   PetscMPIInt result;

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

4263: #if defined(PETSC_USE_DEBUG)
4264: /*
4265:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4267:   Input Parameters:
4268: + dm - The DM
4269: . localSection - PetscSection describing the local data layout
4270: - globalSection - PetscSection describing the global data layout

4272:   Level: intermediate

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

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

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

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

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

4335:   Collective on dm

4337:   Input Parameter:
4338: . dm - The DM

4340:   Output Parameter:
4341: . section - The PetscSection

4343:   Level: intermediate

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

4347: .seealso: DMSetLocalSection(), DMGetLocalSection()
4348: @*/
4349: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4350: {

4356:   if (!dm->globalSection) {
4357:     PetscSection s;

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

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

4374:   Input Parameters:
4375: + dm - The DM
4376: - section - The PetscSection, or NULL

4378:   Level: intermediate

4380:   Note: Any existing Section will be destroyed

4382: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4383: @*/
4384: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4385: {

4391:   PetscObjectReference((PetscObject)section);
4392:   PetscSectionDestroy(&dm->globalSection);
4393:   dm->globalSection = section;
4394: #if defined(PETSC_USE_DEBUG)
4395:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
4396: #endif
4397:   return(0);
4398: }

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

4404:   Input Parameter:
4405: . dm - The DM

4407:   Output Parameter:
4408: . sf - The PetscSF

4410:   Level: intermediate

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

4414: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4415: @*/
4416: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4417: {
4418:   PetscInt       nroots;

4424:   if (!dm->sectionSF) {
4425:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4426:   }
4427:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4428:   if (nroots < 0) {
4429:     PetscSection section, gSection;

4431:     DMGetLocalSection(dm, &section);
4432:     if (section) {
4433:       DMGetGlobalSection(dm, &gSection);
4434:       DMCreateSectionSF(dm, section, gSection);
4435:     } else {
4436:       *sf = NULL;
4437:       return(0);
4438:     }
4439:   }
4440:   *sf = dm->sectionSF;
4441:   return(0);
4442: }

4444: /*@
4445:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4447:   Input Parameters:
4448: + dm - The DM
4449: - sf - The PetscSF

4451:   Level: intermediate

4453:   Note: Any previous SF is destroyed

4455: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4456: @*/
4457: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4458: {

4464:   PetscObjectReference((PetscObject) sf);
4465:   PetscSFDestroy(&dm->sectionSF);
4466:   dm->sectionSF = sf;
4467:   return(0);
4468: }

4470: /*@C
4471:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4472:   describing the data layout.

4474:   Input Parameters:
4475: + dm - The DM
4476: . localSection - PetscSection describing the local data layout
4477: - globalSection - PetscSection describing the global data layout

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

4481:   Level: developer

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

4487: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4488: @*/
4489: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4490: {
4491:   MPI_Comm       comm;
4492:   PetscLayout    layout;
4493:   const PetscInt *ranges;
4494:   PetscInt       *local;
4495:   PetscSFNode    *remote;
4496:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
4497:   PetscMPIInt    size, rank;

4502:   PetscObjectGetComm((PetscObject)dm,&comm);
4503:   MPI_Comm_size(comm, &size);
4504:   MPI_Comm_rank(comm, &rank);
4505:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4506:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4507:   PetscLayoutCreate(comm, &layout);
4508:   PetscLayoutSetBlockSize(layout, 1);
4509:   PetscLayoutSetLocalSize(layout, nroots);
4510:   PetscLayoutSetUp(layout);
4511:   PetscLayoutGetRanges(layout, &ranges);
4512:   for (p = pStart; p < pEnd; ++p) {
4513:     PetscInt gdof, gcdof;

4515:     PetscSectionGetDof(globalSection, p, &gdof);
4516:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4517:     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));
4518:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4519:   }
4520:   PetscMalloc1(nleaves, &local);
4521:   PetscMalloc1(nleaves, &remote);
4522:   for (p = pStart, l = 0; p < pEnd; ++p) {
4523:     const PetscInt *cind;
4524:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

4526:     PetscSectionGetDof(localSection, p, &dof);
4527:     PetscSectionGetOffset(localSection, p, &off);
4528:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4529:     PetscSectionGetConstraintIndices(localSection, p, &cind);
4530:     PetscSectionGetDof(globalSection, p, &gdof);
4531:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4532:     PetscSectionGetOffset(globalSection, p, &goff);
4533:     if (!gdof) continue; /* Censored point */
4534:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4535:     if (gsize != dof-cdof) {
4536:       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);
4537:       cdof = 0; /* Ignore constraints */
4538:     }
4539:     for (d = 0, c = 0; d < dof; ++d) {
4540:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
4541:       local[l+d-c] = off+d;
4542:     }
4543:     if (gdof < 0) {
4544:       for (d = 0; d < gsize; ++d, ++l) {
4545:         PetscInt offset = -(goff+1) + d, r;

4547:         PetscFindInt(offset,size+1,ranges,&r);
4548:         if (r < 0) r = -(r+2);
4549:         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);
4550:         remote[l].rank  = r;
4551:         remote[l].index = offset - ranges[r];
4552:       }
4553:     } else {
4554:       for (d = 0; d < gsize; ++d, ++l) {
4555:         remote[l].rank  = rank;
4556:         remote[l].index = goff+d - ranges[rank];
4557:       }
4558:     }
4559:   }
4560:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
4561:   PetscLayoutDestroy(&layout);
4562:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
4563:   return(0);
4564: }

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

4569:   Input Parameter:
4570: . dm - The DM

4572:   Output Parameter:
4573: . sf - The PetscSF

4575:   Level: intermediate

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

4579: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4580: @*/
4581: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4582: {
4586:   *sf = dm->sf;
4587:   return(0);
4588: }

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

4593:   Input Parameters:
4594: + dm - The DM
4595: - sf - The PetscSF

4597:   Level: intermediate

4599: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4600: @*/
4601: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4602: {

4608:   PetscObjectReference((PetscObject) sf);
4609:   PetscSFDestroy(&dm->sf);
4610:   dm->sf = sf;
4611:   return(0);
4612: }

4614: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4615: {
4616:   PetscClassId   id;

4620:   PetscObjectGetClassId(disc, &id);
4621:   if (id == PETSCFE_CLASSID) {
4622:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4623:   } else if (id == PETSCFV_CLASSID) {
4624:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4625:   } else {
4626:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4627:   }
4628:   return(0);
4629: }

4631: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4632: {
4633:   RegionField   *tmpr;
4634:   PetscInt       Nf = dm->Nf, f;

4638:   if (Nf >= NfNew) return(0);
4639:   PetscMalloc1(NfNew, &tmpr);
4640:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4641:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
4642:   PetscFree(dm->fields);
4643:   dm->Nf     = NfNew;
4644:   dm->fields = tmpr;
4645:   return(0);
4646: }

4648: /*@
4649:   DMClearFields - Remove all fields from the DM

4651:   Logically collective on dm

4653:   Input Parameter:
4654: . dm - The DM

4656:   Level: intermediate

4658: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4659: @*/
4660: PetscErrorCode DMClearFields(DM dm)
4661: {
4662:   PetscInt       f;

4667:   for (f = 0; f < dm->Nf; ++f) {
4668:     PetscObjectDestroy(&dm->fields[f].disc);
4669:     DMLabelDestroy(&dm->fields[f].label);
4670:   }
4671:   PetscFree(dm->fields);
4672:   dm->fields = NULL;
4673:   dm->Nf     = 0;
4674:   return(0);
4675: }

4677: /*@
4678:   DMGetNumFields - Get the number of fields in the DM

4680:   Not collective

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

4685:   Output Parameter:
4686: . Nf - The number of fields

4688:   Level: intermediate

4690: .seealso: DMSetNumFields(), DMSetField()
4691: @*/
4692: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4693: {
4697:   *numFields = dm->Nf;
4698:   return(0);
4699: }

4701: /*@
4702:   DMSetNumFields - Set the number of fields in the DM

4704:   Logically collective on dm

4706:   Input Parameters:
4707: + dm - The DM
4708: - Nf - The number of fields

4710:   Level: intermediate

4712: .seealso: DMGetNumFields(), DMSetField()
4713: @*/
4714: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4715: {
4716:   PetscInt       Nf, f;

4721:   DMGetNumFields(dm, &Nf);
4722:   for (f = Nf; f < numFields; ++f) {
4723:     PetscContainer obj;

4725:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4726:     DMAddField(dm, NULL, (PetscObject) obj);
4727:     PetscContainerDestroy(&obj);
4728:   }
4729:   return(0);
4730: }

4732: /*@
4733:   DMGetField - Return the discretization object for a given DM field

4735:   Not collective

4737:   Input Parameters:
4738: + dm - The DM
4739: - f  - The field number

4741:   Output Parameters:
4742: + label - The label indicating the support of the field, or NULL for the entire mesh
4743: - field - The discretization object

4745:   Level: intermediate

4747: .seealso: DMAddField(), DMSetField()
4748: @*/
4749: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4750: {
4754:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, dm->Nf);
4755:   if (label) *label = dm->fields[f].label;
4756:   if (field) *field = dm->fields[f].disc;
4757:   return(0);
4758: }

4760: /* Does not clear the DS */
4761: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4762: {

4766:   DMFieldEnlarge_Static(dm, f+1);
4767:   DMLabelDestroy(&dm->fields[f].label);
4768:   PetscObjectDestroy(&dm->fields[f].disc);
4769:   dm->fields[f].label = label;
4770:   dm->fields[f].disc  = field;
4771:   PetscObjectReference((PetscObject) label);
4772:   PetscObjectReference((PetscObject) field);
4773:   return(0);
4774: }

4776: /*@
4777:   DMSetField - Set the discretization object for a given DM field

4779:   Logically collective on dm

4781:   Input Parameters:
4782: + dm    - The DM
4783: . f     - The field number
4784: . label - The label indicating the support of the field, or NULL for the entire mesh
4785: - field - The discretization object

4787:   Level: intermediate

4789: .seealso: DMAddField(), DMGetField()
4790: @*/
4791: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4792: {

4799:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4800:   DMSetField_Internal(dm, f, label, field);
4801:   DMSetDefaultAdjacency_Private(dm, f, field);
4802:   DMClearDS(dm);
4803:   return(0);
4804: }

4806: /*@
4807:   DMAddField - Add the discretization object for the given DM field

4809:   Logically collective on dm

4811:   Input Parameters:
4812: + dm    - The DM
4813: . label - The label indicating the support of the field, or NULL for the entire mesh
4814: - field - The discretization object

4816:   Level: intermediate

4818: .seealso: DMSetField(), DMGetField()
4819: @*/
4820: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4821: {
4822:   PetscInt       Nf = dm->Nf;

4829:   DMFieldEnlarge_Static(dm, Nf+1);
4830:   dm->fields[Nf].label = label;
4831:   dm->fields[Nf].disc  = field;
4832:   PetscObjectReference((PetscObject) label);
4833:   PetscObjectReference((PetscObject) field);
4834:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4835:   DMClearDS(dm);
4836:   return(0);
4837: }

4839: /*@
4840:   DMCopyFields - Copy the discretizations for the DM into another DM

4842:   Collective on dm

4844:   Input Parameter:
4845: . dm - The DM

4847:   Output Parameter:
4848: . newdm - The DM

4850:   Level: advanced

4852: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4853: @*/
4854: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4855: {
4856:   PetscInt       Nf, f;

4860:   if (dm == newdm) return(0);
4861:   DMGetNumFields(dm, &Nf);
4862:   DMClearFields(newdm);
4863:   for (f = 0; f < Nf; ++f) {
4864:     DMLabel     label;
4865:     PetscObject field;
4866:     PetscBool   useCone, useClosure;

4868:     DMGetField(dm, f, &label, &field);
4869:     DMSetField(newdm, f, label, field);
4870:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4871:     DMSetAdjacency(newdm, f, useCone, useClosure);
4872:   }
4873:   return(0);
4874: }

4876: /*@
4877:   DMGetAdjacency - Returns the flags for determining variable influence

4879:   Not collective

4881:   Input Parameters:
4882: + dm - The DM object
4883: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4885:   Output Parameter:
4886: + useCone    - Flag for variable influence starting with the cone operation
4887: - useClosure - Flag for variable influence using transitive closure

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

4895:   Level: developer

4897: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4898: @*/
4899: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4900: {
4905:   if (f < 0) {
4906:     if (useCone)    *useCone    = dm->adjacency[0];
4907:     if (useClosure) *useClosure = dm->adjacency[1];
4908:   } else {
4909:     PetscInt       Nf;

4912:     DMGetNumFields(dm, &Nf);
4913:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4914:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4915:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4916:   }
4917:   return(0);
4918: }

4920: /*@
4921:   DMSetAdjacency - Set the flags for determining variable influence

4923:   Not collective

4925:   Input Parameters:
4926: + dm         - The DM object
4927: . f          - The field number
4928: . useCone    - Flag for variable influence starting with the cone operation
4929: - useClosure - Flag for variable influence using transitive closure

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

4937:   Level: developer

4939: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4940: @*/
4941: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4942: {
4945:   if (f < 0) {
4946:     dm->adjacency[0] = useCone;
4947:     dm->adjacency[1] = useClosure;
4948:   } else {
4949:     PetscInt       Nf;

4952:     DMGetNumFields(dm, &Nf);
4953:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4954:     dm->fields[f].adjacency[0] = useCone;
4955:     dm->fields[f].adjacency[1] = useClosure;
4956:   }
4957:   return(0);
4958: }

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

4963:   Not collective

4965:   Input Parameters:
4966: . dm - The DM object

4968:   Output Parameter:
4969: + useCone    - Flag for variable influence starting with the cone operation
4970: - useClosure - Flag for variable influence using transitive closure

4972:   Notes:
4973: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4974: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4975: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4977:   Level: developer

4979: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4980: @*/
4981: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4982: {
4983:   PetscInt       Nf;

4990:   DMGetNumFields(dm, &Nf);
4991:   if (!Nf) {
4992:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
4993:   } else {
4994:     DMGetAdjacency(dm, 0, useCone, useClosure);
4995:   }
4996:   return(0);
4997: }

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

5002:   Not collective

5004:   Input Parameters:
5005: + dm         - The DM object
5006: . useCone    - Flag for variable influence starting with the cone operation
5007: - useClosure - Flag for variable influence using transitive closure

5009:   Notes:
5010: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5011: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5012: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5014:   Level: developer

5016: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5017: @*/
5018: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5019: {
5020:   PetscInt       Nf;

5025:   DMGetNumFields(dm, &Nf);
5026:   if (!Nf) {
5027:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5028:   } else {
5029:     DMSetAdjacency(dm, 0, useCone, useClosure);
5030:   }
5031:   return(0);
5032: }

5034: /* Complete labels that are being used for FEM BC */
5035: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5036: {
5037:   DMLabel        label;
5038:   PetscObject    obj;
5039:   PetscClassId   id;
5040:   PetscInt       Nbd, bd;
5041:   PetscBool      isFE      = PETSC_FALSE;
5042:   PetscBool      duplicate = PETSC_FALSE;

5046:   DMGetField(dm, field, NULL, &obj);
5047:   PetscObjectGetClassId(obj, &id);
5048:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5049:   DMGetLabel(dm, labelname, &label);
5050:   if (isFE && label) {
5051:     /* Only want to modify label once */
5052:     PetscDSGetNumBoundary(ds, &Nbd);
5053:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5054:       const char *lname;

5056:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5057:       PetscStrcmp(lname, labelname, &duplicate);
5058:       if (duplicate) break;
5059:     }
5060:     if (!duplicate) {
5061:       DM plex;

5063:       DMConvert(dm, DMPLEX, &plex);
5064:       if (plex) {DMPlexLabelComplete(plex, label);}
5065:       DMDestroy(&plex);
5066:     }
5067:   }
5068:   return(0);
5069: }

5071: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5072: {
5073:   DMSpace       *tmpd;
5074:   PetscInt       Nds = dm->Nds, s;

5078:   if (Nds >= NdsNew) return(0);
5079:   PetscMalloc1(NdsNew, &tmpd);
5080:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5081:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5082:   PetscFree(dm->probs);
5083:   dm->Nds   = NdsNew;
5084:   dm->probs = tmpd;
5085:   return(0);
5086: }

5088: /*@
5089:   DMGetNumDS - Get the number of discrete systems in the DM

5091:   Not collective

5093:   Input Parameter:
5094: . dm - The DM

5096:   Output Parameter:
5097: . Nds - The number of PetscDS objects

5099:   Level: intermediate

5101: .seealso: DMGetDS(), DMGetCellDS()
5102: @*/
5103: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5104: {
5108:   *Nds = dm->Nds;
5109:   return(0);
5110: }

5112: /*@
5113:   DMClearDS - Remove all discrete systems from the DM

5115:   Logically collective on dm

5117:   Input Parameter:
5118: . dm - The DM

5120:   Level: intermediate

5122: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5123: @*/
5124: PetscErrorCode DMClearDS(DM dm)
5125: {
5126:   PetscInt       s;

5131:   for (s = 0; s < dm->Nds; ++s) {
5132:     PetscDSDestroy(&dm->probs[s].ds);
5133:     DMLabelDestroy(&dm->probs[s].label);
5134:     ISDestroy(&dm->probs[s].fields);
5135:   }
5136:   PetscFree(dm->probs);
5137:   dm->probs = NULL;
5138:   dm->Nds   = 0;
5139:   return(0);
5140: }

5142: /*@
5143:   DMGetDS - Get the default PetscDS

5145:   Not collective

5147:   Input Parameter:
5148: . dm    - The DM

5150:   Output Parameter:
5151: . prob - The default PetscDS

5153:   Level: intermediate

5155: .seealso: DMGetCellDS(), DMGetRegionDS()
5156: @*/
5157: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5158: {

5164:   if (dm->Nds <= 0) {
5165:     PetscDS ds;

5167:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
5168:     DMSetRegionDS(dm, NULL, NULL, ds);
5169:     PetscDSDestroy(&ds);
5170:   }
5171:   *prob = dm->probs[0].ds;
5172:   return(0);
5173: }

5175: /*@
5176:   DMGetCellDS - Get the PetscDS defined on a given cell

5178:   Not collective

5180:   Input Parameters:
5181: + dm    - The DM
5182: - point - Cell for the DS

5184:   Output Parameter:
5185: . prob - The PetscDS defined on the given cell

5187:   Level: developer

5189: .seealso: DMGetDS(), DMSetRegionDS()
5190: @*/
5191: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5192: {
5193:   PetscDS        probDef = NULL;
5194:   PetscInt       s;

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

5205:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5206:     else {
5207:       DMLabelGetValue(dm->probs[s].label, point, &val);
5208:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5209:     }
5210:   }
5211:   if (!*prob) *prob = probDef;
5212:   return(0);
5213: }

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

5218:   Not collective

5220:   Input Parameters:
5221: + dm    - The DM
5222: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5230:   Level: advanced

5232: .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5233: @*/
5234: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5235: {
5236:   PetscInt Nds = dm->Nds, s;

5243:   for (s = 0; s < Nds; ++s) {
5244:     if (dm->probs[s].label == label) {
5245:       if (fields) *fields = dm->probs[s].fields;
5246:       if (ds)     *ds     = dm->probs[s].ds;
5247:       return(0);
5248:     }
5249:   }
5250:   return(0);
5251: }

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

5256:   Collective on dm

5258:   Input Parameters:
5259: + dm     - The DM
5260: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5261: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5262: - prob   - The PetscDS defined on the given cell

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

5267:   Level: advanced

5269: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5270: @*/
5271: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5272: {
5273:   PetscInt       Nds = dm->Nds, s;

5280:   for (s = 0; s < Nds; ++s) {
5281:     if (dm->probs[s].label == label) {
5282:       PetscDSDestroy(&dm->probs[s].ds);
5283:       dm->probs[s].ds = ds;
5284:       return(0);
5285:     }
5286:   }
5287:   DMDSEnlarge_Static(dm, Nds+1);
5288:   PetscObjectReference((PetscObject) label);
5289:   PetscObjectReference((PetscObject) fields);
5290:   PetscObjectReference((PetscObject) ds);
5291:   if (!label) {
5292:     /* Put the NULL label at the front, so it is returned as the default */
5293:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5294:     Nds = 0;
5295:   }
5296:   dm->probs[Nds].label  = label;
5297:   dm->probs[Nds].fields = fields;
5298:   dm->probs[Nds].ds     = ds;
5299:   return(0);
5300: }

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

5305:   Not collective

5307:   Input Parameters:
5308: + dm  - The DM
5309: - num - The region number, in [0, Nds)

5311:   Output Parameters:
5312: + label  - The region label, or NULL
5313: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5314: - ds     - The PetscDS defined on the given region, or NULL

5316:   Level: advanced

5318: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5319: @*/
5320: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5321: {
5322:   PetscInt       Nds;

5327:   DMGetNumDS(dm, &Nds);
5328:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5329:   if (label) {
5331:     *label = dm->probs[num].label;
5332:   }
5333:   if (fields) {
5335:     *fields = dm->probs[num].fields;
5336:   }
5337:   if (ds) {
5339:     *ds = dm->probs[num].ds;
5340:   }
5341:   return(0);
5342: }

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

5347:   Not collective

5349:   Input Parameters:
5350: + dm     - The DM
5351: . num    - The region number, in [0, Nds)
5352: . label  - The region label, or NULL
5353: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5354: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5356:   Level: advanced

5358: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5359: @*/
5360: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5361: {
5362:   PetscInt       Nds;

5368:   DMGetNumDS(dm, &Nds);
5369:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5370:   PetscObjectReference((PetscObject) label);
5371:   DMLabelDestroy(&dm->probs[num].label);
5372:   dm->probs[num].label = label;
5373:   if (fields) {
5375:     PetscObjectReference((PetscObject) fields);
5376:     ISDestroy(&dm->probs[num].fields);
5377:     dm->probs[num].fields = fields;
5378:   }
5379:   if (ds) {
5381:     PetscObjectReference((PetscObject) ds);
5382:     PetscDSDestroy(&dm->probs[num].ds);
5383:     dm->probs[num].ds = ds;
5384:   }
5385:   return(0);
5386: }

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

5391:   Not collective

5393:   Input Parameters:
5394: + dm  - The DM
5395: - ds  - The PetscDS defined on the given region

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

5400:   Level: advanced

5402: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5403: @*/
5404: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5405: {
5406:   PetscInt       Nds, n;

5413:   DMGetNumDS(dm, &Nds);
5414:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5415:   if (n >= Nds) *num = -1;
5416:   else          *num = n;
5417:   return(0);
5418: }

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

5423:   Collective on dm

5425:   Input Parameter:
5426: . dm - The DM

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

5430:   Level: intermediate

5432: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5433: @*/
5434: PetscErrorCode DMCreateDS(DM dm)
5435: {
5436:   MPI_Comm       comm;
5437:   PetscDS        dsDef;
5438:   DMLabel       *labelSet;
5439:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5440:   PetscBool      doSetup = PETSC_TRUE;

5445:   if (!dm->fields) return(0);
5446:   PetscObjectGetComm((PetscObject) dm, &comm);
5447:   DMGetCoordinateDim(dm, &dE);
5448:   /* Determine how many regions we have */
5449:   PetscMalloc1(Nf, &labelSet);
5450:   Nl   = 0;
5451:   Ndef = 0;
5452:   for (f = 0; f < Nf; ++f) {
5453:     DMLabel  label = dm->fields[f].label;
5454:     PetscInt l;

5456:     if (!label) {++Ndef; continue;}
5457:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5458:     if (l < Nl) continue;
5459:     labelSet[Nl++] = label;
5460:   }
5461:   /* Create default DS if there are no labels to intersect with */
5462:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5463:   if (!dsDef && Ndef && !Nl) {
5464:     IS        fields;
5465:     PetscInt *fld, nf;

5467:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5468:     if (nf) {
5469:       PetscMalloc1(nf, &fld);
5470:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5471:       ISCreate(PETSC_COMM_SELF, &fields);
5472:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5473:       ISSetType(fields, ISGENERAL);
5474:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5476:       PetscDSCreate(comm, &dsDef);
5477:       DMSetRegionDS(dm, NULL, fields, dsDef);
5478:       PetscDSDestroy(&dsDef);
5479:       ISDestroy(&fields);
5480:     }
5481:   }
5482:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5483:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
5484:   /* Intersect labels with default fields */
5485:   if (Ndef && Nl) {
5486:     DM              plex;
5487:     DMLabel         cellLabel;
5488:     IS              fieldIS, allcellIS, defcellIS = NULL;
5489:     PetscInt       *fields;
5490:     const PetscInt *cells;
5491:     PetscInt        depth, nf = 0, n, c;

5493:     DMConvert(dm, DMPLEX, &plex);
5494:     DMPlexGetDepth(plex, &depth);
5495:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5496:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
5497:     for (l = 0; l < Nl; ++l) {
5498:       DMLabel label = labelSet[l];
5499:       IS      pointIS;

5501:       ISDestroy(&defcellIS);
5502:       DMLabelGetStratumIS(label, 1, &pointIS);
5503:       ISDifference(allcellIS, pointIS, &defcellIS);
5504:       ISDestroy(&pointIS);
5505:     }
5506:     ISDestroy(&allcellIS);

5508:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5509:     ISGetLocalSize(defcellIS, &n);
5510:     ISGetIndices(defcellIS, &cells);
5511:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
5512:     ISRestoreIndices(defcellIS, &cells);
5513:     ISDestroy(&defcellIS);
5514:     DMPlexLabelComplete(plex, cellLabel);

5516:     PetscMalloc1(Ndef, &fields);
5517:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5518:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5519:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5520:     ISSetType(fieldIS, ISGENERAL);
5521:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5523:     PetscDSCreate(comm, &dsDef);
5524:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5525:     DMLabelDestroy(&cellLabel);
5526:     PetscDSSetCoordinateDimension(dsDef, dE);
5527:     PetscDSDestroy(&dsDef);
5528:     ISDestroy(&fieldIS);
5529:     DMDestroy(&plex);
5530:   }
5531:   /* Create label DSes
5532:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5533:   */
5534:   /* TODO Should check that labels are disjoint */
5535:   for (l = 0; l < Nl; ++l) {
5536:     DMLabel   label = labelSet[l];
5537:     PetscDS   ds;
5538:     IS        fields;
5539:     PetscInt *fld, nf;

5541:     PetscDSCreate(comm, &ds);
5542:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5543:     PetscMalloc1(nf, &fld);
5544:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5545:     ISCreate(PETSC_COMM_SELF, &fields);
5546:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5547:     ISSetType(fields, ISGENERAL);
5548:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5549:     DMSetRegionDS(dm, label, fields, ds);
5550:     ISDestroy(&fields);
5551:     PetscDSSetCoordinateDimension(ds, dE);
5552:     {
5553:       DMPolytopeType ct;
5554:       PetscInt       lStart, lEnd;
5555:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

5557:       DMLabelGetBounds(label, &lStart, &lEnd);
5558:       if (lStart >= 0) {
5559:         DMPlexGetCellType(dm, lStart, &ct);
5560:         switch (ct) {
5561:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5562:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5563:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5564:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5565:             isHybridLocal = PETSC_TRUE;break;
5566:           default: break;
5567:         }
5568:       }
5569:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
5570:       PetscDSSetHybrid(ds, isHybrid);
5571:     }
5572:     PetscDSDestroy(&ds);
5573:   }
5574:   PetscFree(labelSet);
5575:   /* Set fields in DSes */
5576:   for (s = 0; s < dm->Nds; ++s) {
5577:     PetscDS         ds     = dm->probs[s].ds;
5578:     IS              fields = dm->probs[s].fields;
5579:     const PetscInt *fld;
5580:     PetscInt        nf;

5582:     ISGetLocalSize(fields, &nf);
5583:     ISGetIndices(fields, &fld);
5584:     for (f = 0; f < nf; ++f) {
5585:       PetscObject  disc  = dm->fields[fld[f]].disc;
5586:       PetscBool    isHybrid;
5587:       PetscClassId id;

5589:       PetscDSGetHybrid(ds, &isHybrid);
5590:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5591:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
5592:       PetscDSSetDiscretization(ds, f, disc);
5593:       /* We allow people to have placeholder fields and construct the Section by hand */
5594:       PetscObjectGetClassId(disc, &id);
5595:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5596:     }
5597:     ISRestoreIndices(fields, &fld);
5598:   }
5599:   /* Setup DSes */
5600:   if (doSetup) {
5601:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
5602:   }
5603:   return(0);
5604: }

5606: /*@
5607:   DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.

5609:   Collective on DM

5611:   Input Parameters:
5612: + dm   - The DM
5613: - time - The time

5615:   Output Parameters:
5616: + u    - The vector will be filled with exact solution values, or NULL
5617: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5619:   Note: The user must call PetscDSSetExactSolution() beforehand

5621:   Level: developer

5623: .seealso: PetscDSSetExactSolution()
5624: @*/
5625: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5626: {
5627:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5628:   void            **ectxs;
5629:   PetscInt          Nf, Nds, s;
5630:   PetscErrorCode    ierr;

5636:   DMGetNumFields(dm, &Nf);
5637:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5638:   DMGetNumDS(dm, &Nds);
5639:   for (s = 0; s < Nds; ++s) {
5640:     PetscDS         ds;
5641:     DMLabel         label;
5642:     IS              fieldIS;
5643:     const PetscInt *fields, id = 1;
5644:     PetscInt        dsNf, f;

5646:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5647:     PetscDSGetNumFields(ds, &dsNf);
5648:     ISGetIndices(fieldIS, &fields);
5649:     PetscArrayzero(exacts, Nf);
5650:     PetscArrayzero(ectxs, Nf);
5651:     if (u) {
5652:       for (f = 0; f < dsNf; ++f) {
5653:         const PetscInt field = fields[f];
5654:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5655:       }
5656:       ISRestoreIndices(fieldIS, &fields);
5657:       if (label) {
5658:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5659:       } else {
5660:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5661:       }
5662:     }
5663:     if (u_t) {
5664:       PetscArrayzero(exacts, Nf);
5665:       PetscArrayzero(ectxs, Nf);
5666:       for (f = 0; f < dsNf; ++f) {
5667:         const PetscInt field = fields[f];
5668:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5669:       }
5670:       ISRestoreIndices(fieldIS, &fields);
5671:       if (label) {
5672:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5673:       } else {
5674:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5675:       }
5676:     }
5677:   }
5678:   if (u) {
5679:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5680:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5681:   }
5682:   if (u_t) {
5683:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5684:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5685:   }
5686:   PetscFree2(exacts, ectxs);
5687:   return(0);
5688: }

5690: /*@
5691:   DMCopyDS - Copy the discrete systems for the DM into another DM

5693:   Collective on dm

5695:   Input Parameter:
5696: . dm - The DM

5698:   Output Parameter:
5699: . newdm - The DM

5701:   Level: advanced

5703: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5704: @*/
5705: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5706: {
5707:   PetscInt       Nds, s;

5711:   if (dm == newdm) return(0);
5712:   DMGetNumDS(dm, &Nds);
5713:   DMClearDS(newdm);
5714:   for (s = 0; s < Nds; ++s) {
5715:     DMLabel  label;
5716:     IS       fields;
5717:     PetscDS  ds;
5718:     PetscInt Nbd, bd;

5720:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5721:     DMSetRegionDS(newdm, label, fields, ds);
5722:     PetscDSGetNumBoundary(ds, &Nbd);
5723:     for (bd = 0; bd < Nbd; ++bd) {
5724:       const char *labelname, *name;
5725:       PetscInt    field;

5727:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5728:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5729:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
5730:     }
5731:   }
5732:   return(0);
5733: }

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

5738:   Collective on dm

5740:   Input Parameter:
5741: . dm - The DM

5743:   Output Parameter:
5744: . newdm - The DM

5746:   Level: advanced

5748: .seealso: DMCopyFields(), DMCopyDS()
5749: @*/
5750: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5751: {

5755:   DMCopyFields(dm, newdm);
5756:   DMCopyDS(dm, newdm);
5757:   return(0);
5758: }

5760: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5761: {
5762:   DM dm_coord,dmc_coord;
5764:   Vec coords,ccoords;
5765:   Mat inject;
5767:   DMGetCoordinateDM(dm,&dm_coord);
5768:   DMGetCoordinateDM(dmc,&dmc_coord);
5769:   DMGetCoordinates(dm,&coords);
5770:   DMGetCoordinates(dmc,&ccoords);
5771:   if (coords && !ccoords) {
5772:     DMCreateGlobalVector(dmc_coord,&ccoords);
5773:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5774:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5775:     MatRestrict(inject,coords,ccoords);
5776:     MatDestroy(&inject);
5777:     DMSetCoordinates(dmc,ccoords);
5778:     VecDestroy(&ccoords);
5779:   }
5780:   return(0);
5781: }

5783: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5784: {
5785:   DM dm_coord,subdm_coord;
5787:   Vec coords,ccoords,clcoords;
5788:   VecScatter *scat_i,*scat_g;
5790:   DMGetCoordinateDM(dm,&dm_coord);
5791:   DMGetCoordinateDM(subdm,&subdm_coord);
5792:   DMGetCoordinates(dm,&coords);
5793:   DMGetCoordinates(subdm,&ccoords);
5794:   if (coords && !ccoords) {
5795:     DMCreateGlobalVector(subdm_coord,&ccoords);
5796:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5797:     DMCreateLocalVector(subdm_coord,&clcoords);
5798:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5799:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5800:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5801:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5802:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5803:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5804:     DMSetCoordinates(subdm,ccoords);
5805:     DMSetCoordinatesLocal(subdm,clcoords);
5806:     VecScatterDestroy(&scat_i[0]);
5807:     VecScatterDestroy(&scat_g[0]);
5808:     VecDestroy(&ccoords);
5809:     VecDestroy(&clcoords);
5810:     PetscFree(scat_i);
5811:     PetscFree(scat_g);
5812:   }
5813:   return(0);
5814: }

5816: /*@
5817:   DMGetDimension - Return the topological dimension of the DM

5819:   Not collective

5821:   Input Parameter:
5822: . dm - The DM

5824:   Output Parameter:
5825: . dim - The topological dimension

5827:   Level: beginner

5829: .seealso: DMSetDimension(), DMCreate()
5830: @*/
5831: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5832: {
5836:   *dim = dm->dim;
5837:   return(0);
5838: }

5840: /*@
5841:   DMSetDimension - Set the topological dimension of the DM

5843:   Collective on dm

5845:   Input Parameters:
5846: + dm - The DM
5847: - dim - The topological dimension

5849:   Level: beginner

5851: .seealso: DMGetDimension(), DMCreate()
5852: @*/
5853: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5854: {
5855:   PetscDS        ds;

5861:   dm->dim = dim;
5862:   DMGetDS(dm, &ds);
5863:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
5864:   return(0);
5865: }

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

5870:   Collective on dm

5872:   Input Parameters:
5873: + dm - the DM
5874: - dim - the dimension

5876:   Output Parameters:
5877: + pStart - The first point of the given dimension
5878: - pEnd - The first point following points of the given dimension

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

5885:   Level: intermediate

5887: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5888: @*/
5889: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5890: {
5891:   PetscInt       d;

5896:   DMGetDimension(dm, &d);
5897:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5898:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5899:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5900:   return(0);
5901: }

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

5906:   Collective on dm

5908:   Input Parameters:
5909: + dm - the DM
5910: - c - coordinate vector

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

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

5917:   Level: intermediate

5919: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5920: @*/
5921: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5922: {

5928:   PetscObjectReference((PetscObject) c);
5929:   VecDestroy(&dm->coordinates);
5930:   dm->coordinates = c;
5931:   VecDestroy(&dm->coordinatesLocal);
5932:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
5933:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
5934:   return(0);
5935: }

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

5940:   Not collective

5942:    Input Parameters:
5943: +  dm - the DM
5944: -  c - coordinate vector

5946:   Notes:
5947:   The coordinates of ghost points can be set using DMSetCoordinates()
5948:   followed by DMGetCoordinatesLocal(). This is intended to enable the
5949:   setting of ghost coordinates outside of the domain.

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

5953:   Level: intermediate

5955: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5956: @*/
5957: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5958: {

5964:   PetscObjectReference((PetscObject) c);
5965:   VecDestroy(&dm->coordinatesLocal);

5967:   dm->coordinatesLocal = c;

5969:   VecDestroy(&dm->coordinates);
5970:   return(0);
5971: }

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

5976:   Collective on dm

5978:   Input Parameter:
5979: . dm - the DM

5981:   Output Parameter:
5982: . c - global coordinate vector

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

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

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

5992:   Level: intermediate

5994: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5995: @*/
5996: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5997: {

6003:   if (!dm->coordinates && dm->coordinatesLocal) {
6004:     DM        cdm = NULL;
6005:     PetscBool localized;

6007:     DMGetCoordinateDM(dm, &cdm);
6008:     DMCreateGlobalVector(cdm, &dm->coordinates);
6009:     DMGetCoordinatesLocalized(dm, &localized);
6010:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6011:     if (localized) {
6012:       PetscInt cdim;

6014:       DMGetCoordinateDim(dm, &cdim);
6015:       VecSetBlockSize(dm->coordinates, cdim);
6016:     }
6017:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6018:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6019:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6020:   }
6021:   *c = dm->coordinates;
6022:   return(0);
6023: }

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

6028:   Collective on dm

6030:   Input Parameter:
6031: . dm - the DM

6033:   Level: advanced

6035: .seealso: DMGetCoordinatesLocalNoncollective()
6036: @*/
6037: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6038: {

6043:   if (!dm->coordinatesLocal && dm->coordinates) {
6044:     DM        cdm = NULL;
6045:     PetscBool localized;

6047:     DMGetCoordinateDM(dm, &cdm);
6048:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6049:     DMGetCoordinatesLocalized(dm, &localized);
6050:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6051:     if (localized) {
6052:       PetscInt cdim;

6054:       DMGetCoordinateDim(dm, &cdim);
6055:       VecSetBlockSize(dm->coordinates, cdim);
6056:     }
6057:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6058:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6059:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6060:   }
6061:   return(0);
6062: }

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

6067:   Collective on dm

6069:   Input Parameter:
6070: . dm - the DM

6072:   Output Parameter:
6073: . c - coordinate vector

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

6078:   Each process has the local and ghost coordinates

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

6083:   Level: intermediate

6085: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6086: @*/
6087: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6088: {

6094:   DMGetCoordinatesLocalSetUp(dm);
6095:   *c = dm->coordinatesLocal;
6096:   return(0);
6097: }

6099: /*@
6100:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6102:   Not collective

6104:   Input Parameter:
6105: . dm - the DM

6107:   Output Parameter:
6108: . c - coordinate vector

6110:   Level: advanced

6112: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6113: @*/
6114: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6115: {
6119:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6120:   *c = dm->coordinatesLocal;
6121:   return(0);
6122: }

6124: /*@
6125:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6127:   Not collective

6129:   Input Parameter:
6130: + dm - the DM
6131: - p - the IS of points whose coordinates will be returned

6133:   Output Parameter:
6134: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6135: - pCoord - the Vec with coordinates of points in p

6137:   Note:
6138:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6140:   This creates a new vector, so the user SHOULD destroy this vector

6142:   Each process has the local and ghost coordinates

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

6147:   Level: advanced

6149: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6150: @*/
6151: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6152: {
6153:   PetscSection        cs, newcs;
6154:   Vec                 coords;
6155:   const PetscScalar   *arr;
6156:   PetscScalar         *newarr=NULL;
6157:   PetscInt            n;
6158:   PetscErrorCode      ierr;

6165:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6166:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6167:   cs = dm->coordinateDM->localSection;
6168:   coords = dm->coordinatesLocal;
6169:   VecGetArrayRead(coords, &arr);
6170:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6171:   VecRestoreArrayRead(coords, &arr);
6172:   if (pCoord) {
6173:     PetscSectionGetStorageSize(newcs, &n);
6174:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6175:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6176:     VecReplaceArray(*pCoord, newarr);
6177:   } else {
6178:     PetscFree(newarr);
6179:   }
6180:   if (pCoordSection) {*pCoordSection = newcs;}
6181:   else               {PetscSectionDestroy(&newcs);}
6182:   return(0);
6183: }

6185: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6186: {

6192:   if (!dm->coordinateField) {
6193:     if (dm->ops->createcoordinatefield) {
6194:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6195:     }
6196:   }
6197:   *field = dm->coordinateField;
6198:   return(0);
6199: }

6201: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6202: {

6208:   PetscObjectReference((PetscObject)field);
6209:   DMFieldDestroy(&dm->coordinateField);
6210:   dm->coordinateField = field;
6211:   return(0);
6212: }

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

6217:   Collective on dm

6219:   Input Parameter:
6220: . dm - the DM

6222:   Output Parameter:
6223: . cdm - coordinate DM

6225:   Level: intermediate

6227: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6228: @*/
6229: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6230: {

6236:   if (!dm->coordinateDM) {
6237:     DM cdm;

6239:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6240:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6241:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6242:      * until the call to CreateCoordinateDM) */
6243:     DMDestroy(&dm->coordinateDM);
6244:     dm->coordinateDM = cdm;
6245:   }
6246:   *cdm = dm->coordinateDM;
6247:   return(0);
6248: }

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

6253:   Logically Collective on dm

6255:   Input Parameters:
6256: + dm - the DM
6257: - cdm - coordinate DM

6259:   Level: intermediate

6261: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6262: @*/
6263: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6264: {

6270:   PetscObjectReference((PetscObject)cdm);
6271:   DMDestroy(&dm->coordinateDM);
6272:   dm->coordinateDM = cdm;
6273:   return(0);
6274: }

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

6279:   Not Collective

6281:   Input Parameter:
6282: . dm - The DM object

6284:   Output Parameter:
6285: . dim - The embedding dimension

6287:   Level: intermediate

6289: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6290: @*/
6291: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6292: {
6296:   if (dm->dimEmbed == PETSC_DEFAULT) {
6297:     dm->dimEmbed = dm->dim;
6298:   }
6299:   *dim = dm->dimEmbed;
6300:   return(0);
6301: }

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

6306:   Not Collective

6308:   Input Parameters:
6309: + dm  - The DM object
6310: - dim - The embedding dimension

6312:   Level: intermediate

6314: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6315: @*/
6316: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6317: {
6318:   PetscDS        ds;

6323:   dm->dimEmbed = dim;
6324:   DMGetDS(dm, &ds);
6325:   PetscDSSetCoordinateDimension(ds, dim);
6326:   return(0);
6327: }

6329: /*@
6330:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6332:   Collective on dm

6334:   Input Parameter:
6335: . dm - The DM object

6337:   Output Parameter:
6338: . section - The PetscSection object

6340:   Level: intermediate

6342: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6343: @*/
6344: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6345: {
6346:   DM             cdm;

6352:   DMGetCoordinateDM(dm, &cdm);
6353:   DMGetLocalSection(cdm, section);
6354:   return(0);
6355: }

6357: /*@
6358:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6360:   Not Collective

6362:   Input Parameters:
6363: + dm      - The DM object
6364: . dim     - The embedding dimension, or PETSC_DETERMINE
6365: - section - The PetscSection object

6367:   Level: intermediate

6369: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6370: @*/
6371: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6372: {
6373:   DM             cdm;

6379:   DMGetCoordinateDM(dm, &cdm);
6380:   DMSetLocalSection(cdm, section);
6381:   if (dim == PETSC_DETERMINE) {
6382:     PetscInt d = PETSC_DEFAULT;
6383:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6385:     PetscSectionGetChart(section, &pStart, &pEnd);
6386:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6387:     pStart = PetscMax(vStart, pStart);
6388:     pEnd   = PetscMin(vEnd, pEnd);
6389:     for (v = pStart; v < pEnd; ++v) {
6390:       PetscSectionGetDof(section, v, &dd);
6391:       if (dd) {d = dd; break;}
6392:     }
6393:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
6394:   }
6395:   return(0);
6396: }

6398: /*@
6399:   DMProjectCoordinates - Project coordinates to a different space

6401:   Input Parameters:
6402: + dm      - The DM object
6403: - disc    - The new coordinate discretization

6405:   Level: intermediate

6407: .seealso: DMGetCoordinateField()
6408: @*/
6409: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6410: {
6411:   PetscObject    discOld;
6412:   PetscClassId   classid;
6413:   DM             cdmOld,cdmNew;
6414:   Vec            coordsOld,coordsNew;
6415:   Mat            matInterp;


6422:   DMGetCoordinateDM(dm, &cdmOld);
6423:   /* Check current discretization is compatible */
6424:   DMGetField(cdmOld, 0, NULL, &discOld);
6425:   PetscObjectGetClassId(discOld, &classid);
6426:   if (classid != PETSCFE_CLASSID) SETERRQ(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type not supported");
6427:   /* Make a fresh clone of the coordinate DM */
6428:   DMClone(cdmOld, &cdmNew);
6429:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6430:   DMCreateDS(cdmNew);
6431:   /* Project the coordinate vector from old to new space  */
6432:   DMGetCoordinates(dm, &coordsOld);
6433:   DMCreateGlobalVector(cdmNew, &coordsNew);
6434:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6435:   MatInterpolate(matInterp, coordsOld, coordsNew);
6436:   MatDestroy(&matInterp);
6437:   /* Set new coordinate structures */
6438:   DMSetCoordinateField(dm, NULL);
6439:   DMSetCoordinateDM(dm, cdmNew);
6440:   DMSetCoordinates(dm, coordsNew);
6441:   VecDestroy(&coordsNew);
6442:   DMDestroy(&cdmNew);
6443:   return(0);
6444: }

6446: /*@C
6447:   DMGetPeriodicity - Get the description of mesh periodicity

6449:   Input Parameters:
6450: . dm      - The DM object

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

6458:   Level: developer

6460: .seealso: DMGetPeriodicity()
6461: @*/
6462: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6463: {
6466:   if (per)     *per     = dm->periodic;
6467:   if (L)       *L       = dm->L;
6468:   if (maxCell) *maxCell = dm->maxCell;
6469:   if (bd)      *bd      = dm->bdtype;
6470:   return(0);
6471: }

6473: /*@C
6474:   DMSetPeriodicity - Set the description of mesh periodicity

6476:   Input Parameters:
6477: + dm      - The DM object
6478: . per     - Whether the DM is periodic or not.
6479: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
6480: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6481: - bd      - This describes the type of periodicity in each topological dimension

6483:   Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.

6485:   Level: developer

6487: .seealso: DMGetPeriodicity()
6488: @*/
6489: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6490: {
6491:   PetscInt       dim, d;

6500:   DMGetDimension(dm, &dim);
6501:   if (maxCell) {
6502:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
6503:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6504:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6505:     PetscFree(dm->maxCell);
6506:   }

6508:   if (L) {
6509:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
6510:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6511:   }
6512:   if (bd) {
6513:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
6514:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6515:   }
6516:   dm->periodic = per;
6517:   return(0);
6518: }

6520: /*@
6521:   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.

6523:   Input Parameters:
6524: + dm     - The DM
6525: . in     - The input coordinate point (dim numbers)
6526: - endpoint - Include the endpoint L_i

6528:   Output Parameter:
6529: . out - The localized coordinate point

6531:   Level: developer

6533: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6534: @*/
6535: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6536: {
6537:   PetscInt       dim, d;

6541:   DMGetCoordinateDim(dm, &dim);
6542:   if (!dm->maxCell) {
6543:     for (d = 0; d < dim; ++d) out[d] = in[d];
6544:   } else {
6545:     if (endpoint) {
6546:       for (d = 0; d < dim; ++d) {
6547:         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)) {
6548:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6549:         } else {
6550:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6551:         }
6552:       }
6553:     } else {
6554:       for (d = 0; d < dim; ++d) {
6555:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6556:       }
6557:     }
6558:   }
6559:   return(0);
6560: }

6562: /*
6563:   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.

6565:   Input Parameters:
6566: + dm     - The DM
6567: . dim    - The spatial dimension
6568: . anchor - The anchor point, the input point can be no more than maxCell away from it
6569: - in     - The input coordinate point (dim numbers)

6571:   Output Parameter:
6572: . out - The localized coordinate point

6574:   Level: developer

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

6578: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6579: */
6580: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6581: {
6582:   PetscInt d;

6585:   if (!dm->maxCell) {
6586:     for (d = 0; d < dim; ++d) out[d] = in[d];
6587:   } else {
6588:     for (d = 0; d < dim; ++d) {
6589:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6590:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6591:       } else {
6592:         out[d] = in[d];
6593:       }
6594:     }
6595:   }
6596:   return(0);
6597: }

6599: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6600: {
6601:   PetscInt d;

6604:   if (!dm->maxCell) {
6605:     for (d = 0; d < dim; ++d) out[d] = in[d];
6606:   } else {
6607:     for (d = 0; d < dim; ++d) {
6608:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6609:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6610:       } else {
6611:         out[d] = in[d];
6612:       }
6613:     }
6614:   }
6615:   return(0);
6616: }

6618: /*
6619:   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.

6621:   Input Parameters:
6622: + dm     - The DM
6623: . dim    - The spatial dimension
6624: . anchor - The anchor point, the input point can be no more than maxCell away from it
6625: . in     - The input coordinate delta (dim numbers)
6626: - out    - The input coordinate point (dim numbers)

6628:   Output Parameter:
6629: . out    - The localized coordinate in + out

6631:   Level: developer

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

6635: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6636: */
6637: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6638: {
6639:   PetscInt d;

6642:   if (!dm->maxCell) {
6643:     for (d = 0; d < dim; ++d) out[d] += in[d];
6644:   } else {
6645:     for (d = 0; d < dim; ++d) {
6646:       const PetscReal maxC = dm->maxCell[d];

6648:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6649:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6651:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6652:           SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
6653:         out[d] += newCoord;
6654:       } else {
6655:         out[d] += in[d];
6656:       }
6657:     }
6658:   }
6659:   return(0);
6660: }

6662: /*@
6663:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6665:   Not collective

6667:   Input Parameter:
6668: . dm - The DM

6670:   Output Parameter:
6671:   areLocalized - True if localized

6673:   Level: developer

6675: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6676: @*/
6677: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6678: {
6679:   DM             cdm;
6680:   PetscSection   coordSection;
6681:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6682:   PetscBool      isPlex, alreadyLocalized;

6688:   *areLocalized = PETSC_FALSE;

6690:   /* We need some generic way of refering to cells/vertices */
6691:   DMGetCoordinateDM(dm, &cdm);
6692:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6693:   if (!isPlex) return(0);

6695:   DMGetCoordinateSection(dm, &coordSection);
6696:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6697:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6698:   alreadyLocalized = PETSC_FALSE;
6699:   for (c = cStart; c < cEnd; ++c) {
6700:     if (c < sStart || c >= sEnd) continue;
6701:     PetscSectionGetDof(coordSection, c, &dof);
6702:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6703:   }
6704:   *areLocalized = alreadyLocalized;
6705:   return(0);
6706: }

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

6711:   Collective on dm

6713:   Input Parameter:
6714: . dm - The DM

6716:   Output Parameter:
6717:   areLocalized - True if localized

6719:   Level: developer

6721: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6722: @*/
6723: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6724: {
6725:   PetscBool      localized;

6731:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6732:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6733:   return(0);
6734: }

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

6739:   Collective on dm

6741:   Input Parameter:
6742: . dm - The DM

6744:   Level: developer

6746: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6747: @*/
6748: PetscErrorCode DMLocalizeCoordinates(DM dm)
6749: {
6750:   DM             cdm;
6751:   PetscSection   coordSection, cSection;
6752:   Vec            coordinates,  cVec;
6753:   PetscScalar   *coords, *coords2, *anchor, *localized;
6754:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6755:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6756:   PetscInt       maxHeight = 0, h;
6757:   PetscInt       *pStart = NULL, *pEnd = NULL;

6762:   if (!dm->periodic) return(0);
6763:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6764:   if (alreadyLocalized) return(0);

6766:   /* We need some generic way of refering to cells/vertices */
6767:   DMGetCoordinateDM(dm, &cdm);
6768:   {
6769:     PetscBool isplex;

6771:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6772:     if (isplex) {
6773:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6774:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6775:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6776:       pEnd = &pStart[maxHeight + 1];
6777:       newStart = vStart;
6778:       newEnd   = vEnd;
6779:       for (h = 0; h <= maxHeight; h++) {
6780:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6781:         newStart = PetscMin(newStart,pStart[h]);
6782:         newEnd   = PetscMax(newEnd,pEnd[h]);
6783:       }
6784:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6785:   }
6786:   DMGetCoordinatesLocal(dm, &coordinates);
6787:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6788:   DMGetCoordinateSection(dm, &coordSection);
6789:   VecGetBlockSize(coordinates, &bs);
6790:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6792:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6793:   PetscSectionSetNumFields(cSection, 1);
6794:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6795:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6796:   PetscSectionSetChart(cSection, newStart, newEnd);

6798:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6799:   localized = &anchor[bs];
6800:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6801:   for (h = 0; h <= maxHeight; h++) {
6802:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6804:     for (c = cStart; c < cEnd; ++c) {
6805:       PetscScalar *cellCoords = NULL;
6806:       PetscInt     b;

6808:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6809:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6810:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6811:       for (d = 0; d < dof/bs; ++d) {
6812:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6813:         for (b = 0; b < bs; b++) {
6814:           if (cellCoords[d*bs + b] != localized[b]) break;
6815:         }
6816:         if (b < bs) break;
6817:       }
6818:       if (d < dof/bs) {
6819:         if (c >= sStart && c < sEnd) {
6820:           PetscInt cdof;

6822:           PetscSectionGetDof(coordSection, c, &cdof);
6823:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6824:         }
6825:         PetscSectionSetDof(cSection, c, dof);
6826:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6827:       }
6828:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6829:     }
6830:   }
6831:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6832:   if (alreadyLocalizedGlobal) {
6833:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6834:     PetscSectionDestroy(&cSection);
6835:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6836:     return(0);
6837:   }
6838:   for (v = vStart; v < vEnd; ++v) {
6839:     PetscSectionGetDof(coordSection, v, &dof);
6840:     PetscSectionSetDof(cSection, v, dof);
6841:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6842:   }
6843:   PetscSectionSetUp(cSection);
6844:   PetscSectionGetStorageSize(cSection, &coordSize);
6845:   VecCreate(PETSC_COMM_SELF, &cVec);
6846:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6847:   VecSetBlockSize(cVec, bs);
6848:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6849:   VecSetType(cVec, VECSTANDARD);
6850:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6851:   VecGetArray(cVec, &coords2);
6852:   for (v = vStart; v < vEnd; ++v) {
6853:     PetscSectionGetDof(coordSection, v, &dof);
6854:     PetscSectionGetOffset(coordSection, v, &off);
6855:     PetscSectionGetOffset(cSection,     v, &off2);
6856:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6857:   }
6858:   for (h = 0; h <= maxHeight; h++) {
6859:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6861:     for (c = cStart; c < cEnd; ++c) {
6862:       PetscScalar *cellCoords = NULL;
6863:       PetscInt     b, cdof;

6865:       PetscSectionGetDof(cSection,c,&cdof);
6866:       if (!cdof) continue;
6867:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6868:       PetscSectionGetOffset(cSection, c, &off2);
6869:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6870:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
6871:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6872:     }
6873:   }
6874:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6875:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6876:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6877:   VecRestoreArray(cVec, &coords2);
6878:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6879:   DMSetCoordinatesLocal(dm, cVec);
6880:   VecDestroy(&cVec);
6881:   PetscSectionDestroy(&cSection);
6882:   return(0);
6883: }

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

6888:   Collective on v (see explanation below)

6890:   Input Parameters:
6891: + dm - The DM
6892: . v - The Vec of points
6893: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6894: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

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


6901:   Level: developer

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

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

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

6912: $    const PetscSFNode *cells;
6913: $    PetscInt           nFound;
6914: $    const PetscInt    *found;
6915: $
6916: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

6921: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6922: @*/
6923: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6924: {

6931:   if (*cellSF) {
6932:     PetscMPIInt result;

6935:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
6936:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6937:   } else {
6938:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
6939:   }
6940:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6941:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
6942:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
6943:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
6944:   return(0);
6945: }

6947: /*@
6948:   DMGetOutputDM - Retrieve the DM associated with the layout for output

6950:   Collective on dm

6952:   Input Parameter:
6953: . dm - The original DM

6955:   Output Parameter:
6956: . odm - The DM which provides the layout for output

6958:   Level: intermediate

6960: .seealso: VecView(), DMGetGlobalSection()
6961: @*/
6962: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6963: {
6964:   PetscSection   section;
6965:   PetscBool      hasConstraints, ghasConstraints;

6971:   DMGetLocalSection(dm, &section);
6972:   PetscSectionHasConstraints(section, &hasConstraints);
6973:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
6974:   if (!ghasConstraints) {
6975:     *odm = dm;
6976:     return(0);
6977:   }
6978:   if (!dm->dmBC) {
6979:     PetscSection newSection, gsection;
6980:     PetscSF      sf;

6982:     DMClone(dm, &dm->dmBC);
6983:     DMCopyDisc(dm, dm->dmBC);
6984:     PetscSectionClone(section, &newSection);
6985:     DMSetLocalSection(dm->dmBC, newSection);
6986:     PetscSectionDestroy(&newSection);
6987:     DMGetPointSF(dm->dmBC, &sf);
6988:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6989:     DMSetGlobalSection(dm->dmBC, gsection);
6990:     PetscSectionDestroy(&gsection);
6991:   }
6992:   *odm = dm->dmBC;
6993:   return(0);
6994: }

6996: /*@
6997:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6999:   Input Parameter:
7000: . dm - The original DM

7002:   Output Parameters:
7003: + num - The output sequence number
7004: - val - The output sequence value

7006:   Level: intermediate

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

7011: .seealso: VecView()
7012: @*/
7013: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7014: {
7019:   return(0);
7020: }

7022: /*@
7023:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7025:   Input Parameters:
7026: + dm - The original DM
7027: . num - The output sequence number
7028: - val - The output sequence value

7030:   Level: intermediate

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

7035: .seealso: VecView()
7036: @*/
7037: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7038: {
7041:   dm->outputSequenceNum = num;
7042:   dm->outputSequenceVal = val;
7043:   return(0);
7044: }

7046: /*@C
7047:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7049:   Input Parameters:
7050: + dm   - The original DM
7051: . name - The sequence name
7052: - num  - The output sequence number

7054:   Output Parameter:
7055: . val  - The output sequence value

7057:   Level: intermediate

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

7062: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7063: @*/
7064: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7065: {
7066:   PetscBool      ishdf5;

7073:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7074:   if (ishdf5) {
7075: #if defined(PETSC_HAVE_HDF5)
7076:     PetscScalar value;

7078:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7079:     *val = PetscRealPart(value);
7080: #endif
7081:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7082:   return(0);
7083: }

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

7088:   Not collective

7090:   Input Parameter:
7091: . dm - The DM

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

7096:   Level: beginner

7098: .seealso: DMSetUseNatural(), DMCreate()
7099: @*/
7100: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7101: {
7105:   *useNatural = dm->useNatural;
7106:   return(0);
7107: }

7109: /*@
7110:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7112:   Collective on dm

7114:   Input Parameters:
7115: + dm - The DM
7116: - useNatural - The flag to build the mapping to a natural order during distribution

7118:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7120:   Level: beginner

7122: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7123: @*/
7124: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7125: {
7129:   dm->useNatural = useNatural;
7130:   return(0);
7131: }


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

7137:   Not Collective

7139:   Input Parameters:
7140: + dm   - The DM object
7141: - name - The label name

7143:   Level: intermediate

7145: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7146: @*/
7147: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7148: {
7149:   PetscBool      flg;
7150:   DMLabel        label;

7156:   DMHasLabel(dm, name, &flg);
7157:   if (!flg) {
7158:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7159:     DMAddLabel(dm, label);
7160:     DMLabelDestroy(&label);
7161:   }
7162:   return(0);
7163: }

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

7168:   Not Collective

7170:   Input Parameters:
7171: + dm   - The DM object
7172: . name - The label name
7173: - point - The mesh point

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

7178:   Level: beginner

7180: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7181: @*/
7182: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7183: {
7184:   DMLabel        label;

7190:   DMGetLabel(dm, name, &label);
7191:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7192:   DMLabelGetValue(label, point, value);
7193:   return(0);
7194: }

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

7199:   Not Collective

7201:   Input Parameters:
7202: + dm   - The DM object
7203: . name - The label name
7204: . point - The mesh point
7205: - value - The label value for this point

7207:   Output Parameter:

7209:   Level: beginner

7211: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7212: @*/
7213: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7214: {
7215:   DMLabel        label;

7221:   DMGetLabel(dm, name, &label);
7222:   if (!label) {
7223:     DMCreateLabel(dm, name);
7224:     DMGetLabel(dm, name, &label);
7225:   }
7226:   DMLabelSetValue(label, point, value);
7227:   return(0);
7228: }

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

7233:   Not Collective

7235:   Input Parameters:
7236: + dm   - The DM object
7237: . name - The label name
7238: . point - The mesh point
7239: - value - The label value for this point

7241:   Output Parameter:

7243:   Level: beginner

7245: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7246: @*/
7247: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7248: {
7249:   DMLabel        label;

7255:   DMGetLabel(dm, name, &label);
7256:   if (!label) return(0);
7257:   DMLabelClearValue(label, point, value);
7258:   return(0);
7259: }

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

7264:   Not Collective

7266:   Input Parameters:
7267: + dm   - The DM object
7268: - name - The label name

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

7273:   Level: beginner

7275: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7276: @*/
7277: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7278: {
7279:   DMLabel        label;

7286:   DMGetLabel(dm, name, &label);
7287:   *size = 0;
7288:   if (!label) return(0);
7289:   DMLabelGetNumValues(label, size);
7290:   return(0);
7291: }

7293: /*@C
7294:   DMGetLabelIdIS - Get the integer ids in a label

7296:   Not Collective

7298:   Input Parameters:
7299: + mesh - The DM object
7300: - name - The label name

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

7305:   Level: beginner

7307: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7308: @*/
7309: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7310: {
7311:   DMLabel        label;

7318:   DMGetLabel(dm, name, &label);
7319:   *ids = NULL;
7320:  if (label) {
7321:     DMLabelGetValueIS(label, ids);
7322:   } else {
7323:     /* returning an empty IS */
7324:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7325:   }
7326:   return(0);
7327: }

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

7332:   Not Collective

7334:   Input Parameters:
7335: + dm - The DM object
7336: . name - The label name
7337: - value - The stratum value

7339:   Output Parameter:
7340: . size - The stratum size

7342:   Level: beginner

7344: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7345: @*/
7346: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7347: {
7348:   DMLabel        label;

7355:   DMGetLabel(dm, name, &label);
7356:   *size = 0;
7357:   if (!label) return(0);
7358:   DMLabelGetStratumSize(label, value, size);
7359:   return(0);
7360: }

7362: /*@C
7363:   DMGetStratumIS - Get the points in a label stratum

7365:   Not Collective

7367:   Input Parameters:
7368: + dm - The DM object
7369: . name - The label name
7370: - value - The stratum value

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

7375:   Level: beginner

7377: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7378: @*/
7379: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7380: {
7381:   DMLabel        label;

7388:   DMGetLabel(dm, name, &label);
7389:   *points = NULL;
7390:   if (!label) return(0);
7391:   DMLabelGetStratumIS(label, value, points);
7392:   return(0);
7393: }

7395: /*@C
7396:   DMSetStratumIS - Set the points in a label stratum

7398:   Not Collective

7400:   Input Parameters:
7401: + dm - The DM object
7402: . name - The label name
7403: . value - The stratum value
7404: - points - The stratum points

7406:   Level: beginner

7408: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7409: @*/
7410: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7411: {
7412:   DMLabel        label;

7419:   DMGetLabel(dm, name, &label);
7420:   if (!label) return(0);
7421:   DMLabelSetStratumIS(label, value, points);
7422:   return(0);
7423: }

7425: /*@C
7426:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

7428:   Not Collective

7430:   Input Parameters:
7431: + dm   - The DM object
7432: . name - The label name
7433: - value - The label value for this point

7435:   Output Parameter:

7437:   Level: beginner

7439: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7440: @*/
7441: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7442: {
7443:   DMLabel        label;

7449:   DMGetLabel(dm, name, &label);
7450:   if (!label) return(0);
7451:   DMLabelClearStratum(label, value);
7452:   return(0);
7453: }

7455: /*@
7456:   DMGetNumLabels - Return the number of labels defined by the mesh

7458:   Not Collective

7460:   Input Parameter:
7461: . dm   - The DM object

7463:   Output Parameter:
7464: . numLabels - the number of Labels

7466:   Level: intermediate

7468: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7469: @*/
7470: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7471: {
7472:   DMLabelLink next = dm->labels;
7473:   PetscInt  n    = 0;

7478:   while (next) {++n; next = next->next;}
7479:   *numLabels = n;
7480:   return(0);
7481: }

7483: /*@C
7484:   DMGetLabelName - Return the name of nth label

7486:   Not Collective

7488:   Input Parameters:
7489: + dm - The DM object
7490: - n  - the label number

7492:   Output Parameter:
7493: . name - the label name

7495:   Level: intermediate

7497: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7498: @*/
7499: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7500: {
7501:   DMLabelLink    next = dm->labels;
7502:   PetscInt       l    = 0;

7508:   while (next) {
7509:     if (l == n) {
7510:       PetscObjectGetName((PetscObject) next->label, name);
7511:       return(0);
7512:     }
7513:     ++l;
7514:     next = next->next;
7515:   }
7516:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7517: }

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

7522:   Not Collective

7524:   Input Parameters:
7525: + dm   - The DM object
7526: - name - The label name

7528:   Output Parameter:
7529: . hasLabel - PETSC_TRUE if the label is present

7531:   Level: intermediate

7533: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7534: @*/
7535: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7536: {
7537:   DMLabelLink    next = dm->labels;
7538:   const char    *lname;

7545:   *hasLabel = PETSC_FALSE;
7546:   while (next) {
7547:     PetscObjectGetName((PetscObject) next->label, &lname);
7548:     PetscStrcmp(name, lname, hasLabel);
7549:     if (*hasLabel) break;
7550:     next = next->next;
7551:   }
7552:   return(0);
7553: }

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

7558:   Not Collective

7560:   Input Parameters:
7561: + dm   - The DM object
7562: - name - The label name

7564:   Output Parameter:
7565: . label - The DMLabel, or NULL if the label is absent

7567:   Level: intermediate

7569: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7570: @*/
7571: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7572: {
7573:   DMLabelLink    next = dm->labels;
7574:   PetscBool      hasLabel;
7575:   const char    *lname;

7582:   *label = NULL;
7583:   while (next) {
7584:     PetscObjectGetName((PetscObject) next->label, &lname);
7585:     PetscStrcmp(name, lname, &hasLabel);
7586:     if (hasLabel) {
7587:       *label = next->label;
7588:       break;
7589:     }
7590:     next = next->next;
7591:   }
7592:   return(0);
7593: }

7595: /*@C
7596:   DMGetLabelByNum - Return the nth label

7598:   Not Collective

7600:   Input Parameters:
7601: + dm - The DM object
7602: - n  - the label number

7604:   Output Parameter:
7605: . label - the label

7607:   Level: intermediate

7609: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7610: @*/
7611: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7612: {
7613:   DMLabelLink next = dm->labels;
7614:   PetscInt    l    = 0;

7619:   while (next) {
7620:     if (l == n) {
7621:       *label = next->label;
7622:       return(0);
7623:     }
7624:     ++l;
7625:     next = next->next;
7626:   }
7627:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7628: }

7630: /*@C
7631:   DMAddLabel - Add the label to this mesh

7633:   Not Collective

7635:   Input Parameters:
7636: + dm   - The DM object
7637: - label - The DMLabel

7639:   Level: developer

7641: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7642: @*/
7643: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7644: {
7645:   DMLabelLink    l, *p, tmpLabel;
7646:   PetscBool      hasLabel;
7647:   const char    *lname;
7648:   PetscBool      flg;

7653:   PetscObjectGetName((PetscObject) label, &lname);
7654:   DMHasLabel(dm, lname, &hasLabel);
7655:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7656:   PetscCalloc1(1, &tmpLabel);
7657:   tmpLabel->label  = label;
7658:   tmpLabel->output = PETSC_TRUE;
7659:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7660:   *p = tmpLabel;
7661:   PetscObjectReference((PetscObject)label);
7662:   PetscStrcmp(lname, "depth", &flg);
7663:   if (flg) dm->depthLabel = label;
7664:   PetscStrcmp(lname, "celltype", &flg);
7665:   if (flg) dm->celltypeLabel = label;
7666:   return(0);
7667: }

7669: /*@C
7670:   DMRemoveLabel - Remove the label given by name from this mesh

7672:   Not Collective

7674:   Input Parameters:
7675: + dm   - The DM object
7676: - name - The label name

7678:   Output Parameter:
7679: . label - The DMLabel, or NULL if the label is absent

7681:   Level: developer

7683:   Notes:
7684:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7685:   DMLabelDestroy() on the label.

7687:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7688:   call DMLabelDestroy(). Instead, the label is returned and the user is
7689:   responsible of calling DMLabelDestroy() at some point.

7691: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7692: @*/
7693: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7694: {
7695:   DMLabelLink    link, *pnext;
7696:   PetscBool      hasLabel;
7697:   const char    *lname;

7703:   if (label) {
7705:     *label = NULL;
7706:   }
7707:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7708:     PetscObjectGetName((PetscObject) link->label, &lname);
7709:     PetscStrcmp(name, lname, &hasLabel);
7710:     if (hasLabel) {
7711:       *pnext = link->next; /* Remove from list */
7712:       PetscStrcmp(name, "depth", &hasLabel);
7713:       if (hasLabel) dm->depthLabel = NULL;
7714:       PetscStrcmp(name, "celltype", &hasLabel);
7715:       if (hasLabel) dm->celltypeLabel = NULL;
7716:       if (label) *label = link->label;
7717:       else       {DMLabelDestroy(&link->label);}
7718:       PetscFree(link);
7719:       break;
7720:     }
7721:   }
7722:   return(0);
7723: }

7725: /*@
7726:   DMRemoveLabelBySelf - Remove the label from this mesh

7728:   Not Collective

7730:   Input Parameters:
7731: + dm   - The DM object
7732: . label - (Optional) The DMLabel to be removed from the DM
7733: - failNotFound - Should it fail if the label is not found in the DM?

7735:   Level: developer

7737:   Notes:
7738:   Only exactly the same instance is removed if found, name match is ignored.
7739:   If the DM has an exclusive reference to the label, it gets destroyed and
7740:   *label nullified.

7742: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7743: @*/
7744: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7745: {
7746:   DMLabelLink    link, *pnext;
7747:   PetscBool      hasLabel = PETSC_FALSE;

7753:   if (!*label && !failNotFound) return(0);
7756:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7757:     if (*label == link->label) {
7758:       hasLabel = PETSC_TRUE;
7759:       *pnext = link->next; /* Remove from list */
7760:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7761:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7762:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7763:       DMLabelDestroy(&link->label);
7764:       PetscFree(link);
7765:       break;
7766:     }
7767:   }
7768:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7769:   return(0);
7770: }

7772: /*@C
7773:   DMGetLabelOutput - Get the output flag for a given label

7775:   Not Collective

7777:   Input Parameters:
7778: + dm   - The DM object
7779: - name - The label name

7781:   Output Parameter:
7782: . output - The flag for output

7784:   Level: developer

7786: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7787: @*/
7788: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7789: {
7790:   DMLabelLink    next = dm->labels;
7791:   const char    *lname;

7798:   while (next) {
7799:     PetscBool flg;

7801:     PetscObjectGetName((PetscObject) next->label, &lname);
7802:     PetscStrcmp(name, lname, &flg);
7803:     if (flg) {*output = next->output; return(0);}
7804:     next = next->next;
7805:   }
7806:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7807: }

7809: /*@C
7810:   DMSetLabelOutput - Set the output flag for a given label

7812:   Not Collective

7814:   Input Parameters:
7815: + dm     - The DM object
7816: . name   - The label name
7817: - output - The flag for output

7819:   Level: developer

7821: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7822: @*/
7823: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7824: {
7825:   DMLabelLink    next = dm->labels;
7826:   const char    *lname;

7832:   while (next) {
7833:     PetscBool flg;

7835:     PetscObjectGetName((PetscObject) next->label, &lname);
7836:     PetscStrcmp(name, lname, &flg);
7837:     if (flg) {next->output = output; return(0);}
7838:     next = next->next;
7839:   }
7840:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7841: }

7843: /*@
7844:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

7846:   Collective on dmA

7848:   Input Parameter:
7849: + dmA - The DM object with initial labels
7850: . dmB - The DM object with copied labels
7851: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7852: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

7854:   Level: intermediate

7856:   Note: This is typically used when interpolating or otherwise adding to a mesh

7858: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7859: @*/
7860: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7861: {
7862:   DMLabel        label, labelNew;
7863:   const char    *name;
7864:   PetscBool      flg;
7865:   DMLabelLink    link;

7873:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7874:   if (dmA == dmB) return(0);
7875:   for (link=dmA->labels; link; link=link->next) {
7876:     label=link->label;
7877:     PetscObjectGetName((PetscObject)label, &name);
7878:     if (!all) {
7879:       PetscStrcmp(name, "depth", &flg);
7880:       if (flg) continue;
7881:       PetscStrcmp(name, "dim", &flg);
7882:       if (flg) continue;
7883:       PetscStrcmp(name, "celltype", &flg);
7884:       if (flg) continue;
7885:     }
7886:     if (mode==PETSC_COPY_VALUES) {
7887:       DMLabelDuplicate(label, &labelNew);
7888:     } else {
7889:       labelNew = label;
7890:     }
7891:     DMAddLabel(dmB, labelNew);
7892:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
7893:   }
7894:   return(0);
7895: }

7897: /*@
7898:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

7900:   Input Parameter:
7901: . dm - The DM object

7903:   Output Parameter:
7904: . cdm - The coarse DM

7906:   Level: intermediate

7908: .seealso: DMSetCoarseDM()
7909: @*/
7910: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7911: {
7915:   *cdm = dm->coarseMesh;
7916:   return(0);
7917: }

7919: /*@
7920:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

7922:   Input Parameters:
7923: + dm - The DM object
7924: - cdm - The coarse DM

7926:   Level: intermediate

7928: .seealso: DMGetCoarseDM()
7929: @*/
7930: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7931: {

7937:   PetscObjectReference((PetscObject)cdm);
7938:   DMDestroy(&dm->coarseMesh);
7939:   dm->coarseMesh = cdm;
7940:   return(0);
7941: }

7943: /*@
7944:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

7946:   Input Parameter:
7947: . dm - The DM object

7949:   Output Parameter:
7950: . fdm - The fine DM

7952:   Level: intermediate

7954: .seealso: DMSetFineDM()
7955: @*/
7956: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7957: {
7961:   *fdm = dm->fineMesh;
7962:   return(0);
7963: }

7965: /*@
7966:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

7968:   Input Parameters:
7969: + dm - The DM object
7970: - fdm - The fine DM

7972:   Level: intermediate

7974: .seealso: DMGetFineDM()
7975: @*/
7976: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7977: {

7983:   PetscObjectReference((PetscObject)fdm);
7984:   DMDestroy(&dm->fineMesh);
7985:   dm->fineMesh = fdm;
7986:   return(0);
7987: }

7989: /*=== DMBoundary code ===*/

7991: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
7992: {
7993:   PetscInt       d;

7997:   for (d = 0; d < dm->Nds; ++d) {
7998:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
7999:   }
8000:   return(0);
8001: }

8003: /*@C
8004:   DMAddBoundary - Add a boundary condition to the model

8006:   Collective on dm

8008:   Input Parameters:
8009: + dm          - The DM, with a PetscDS that matches the problem being constrained
8010: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8011: . name        - The BC name
8012: . labelname   - The label defining constrained points
8013: . field       - The field to constrain
8014: . numcomps    - The number of constrained field components (0 will constrain all fields)
8015: . comps       - An array of constrained component numbers
8016: . bcFunc      - A pointwise function giving boundary values
8017: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8018: . numids      - The number of DMLabel ids for constrained points
8019: . ids         - An array of ids for constrained points
8020: - ctx         - An optional user context for bcFunc

8022:   Options Database Keys:
8023: + -bc_<boundary name> <num> - Overrides the boundary ids
8024: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8026:   Note:
8027:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8029: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8031:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8033: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8034: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8035: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8036: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8038: + dim - the spatial dimension
8039: . Nf - the number of fields
8040: . uOff - the offset into u[] and u_t[] for each field
8041: . uOff_x - the offset into u_x[] for each field
8042: . u - each field evaluated at the current point
8043: . u_t - the time derivative of each field evaluated at the current point
8044: . u_x - the gradient of each field evaluated at the current point
8045: . aOff - the offset into a[] and a_t[] for each auxiliary field
8046: . aOff_x - the offset into a_x[] for each auxiliary field
8047: . a - each auxiliary field evaluated at the current point
8048: . a_t - the time derivative of each auxiliary field evaluated at the current point
8049: . a_x - the gradient of auxiliary each field evaluated at the current point
8050: . t - current time
8051: . x - coordinates of the current point
8052: . numConstants - number of constant parameters
8053: . constants - constant parameters
8054: - bcval - output values at the current point

8056:   Level: developer

8058: .seealso: DMGetBoundary(), PetscDSAddBoundary()
8059: @*/
8060: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
8061: {
8062:   PetscDS        ds;

8071:   DMGetDS(dm, &ds);
8072:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
8073:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
8074:   return(0);
8075: }

8077: /*@
8078:   DMGetNumBoundary - Get the number of registered BC

8080:   Input Parameters:
8081: . dm - The mesh object

8083:   Output Parameters:
8084: . numBd - The number of BC

8086:   Level: intermediate

8088: .seealso: DMAddBoundary(), DMGetBoundary()
8089: @*/
8090: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8091: {
8092:   PetscDS        ds;

8097:   DMGetDS(dm, &ds);
8098:   PetscDSGetNumBoundary(ds, numBd);
8099:   return(0);
8100: }

8102: /*@C
8103:   DMGetBoundary - Get a model boundary condition

8105:   Input Parameters:
8106: + dm          - The mesh object
8107: - bd          - The BC number

8109:   Output Parameters:
8110: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8111: . name        - The BC name
8112: . labelname   - The label defining constrained points
8113: . field       - The field to constrain
8114: . numcomps    - The number of constrained field components
8115: . comps       - An array of constrained component numbers
8116: . bcFunc      - A pointwise function giving boundary values
8117: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8118: . numids      - The number of DMLabel ids for constrained points
8119: . ids         - An array of ids for constrained points
8120: - ctx         - An optional user context for bcFunc

8122:   Options Database Keys:
8123: + -bc_<boundary name> <num> - Overrides the boundary ids
8124: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8126:   Level: developer

8128: .seealso: DMAddBoundary()
8129: @*/
8130: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
8131: {
8132:   PetscDS        ds;

8137:   DMGetDS(dm, &ds);
8138:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
8139:   return(0);
8140: }

8142: static PetscErrorCode DMPopulateBoundary(DM dm)
8143: {
8144:   PetscDS        ds;
8145:   DMBoundary    *lastnext;
8146:   DSBoundary     dsbound;

8150:   DMGetDS(dm, &ds);
8151:   dsbound = ds->boundary;
8152:   if (dm->boundary) {
8153:     DMBoundary next = dm->boundary;

8155:     /* quick check to see if the PetscDS has changed */
8156:     if (next->dsboundary == dsbound) return(0);
8157:     /* the PetscDS has changed: tear down and rebuild */
8158:     while (next) {
8159:       DMBoundary b = next;

8161:       next = b->next;
8162:       PetscFree(b);
8163:     }
8164:     dm->boundary = NULL;
8165:   }

8167:   lastnext = &(dm->boundary);
8168:   while (dsbound) {
8169:     DMBoundary dmbound;

8171:     PetscNew(&dmbound);
8172:     dmbound->dsboundary = dsbound;
8173:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
8174:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
8175:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8176:     *lastnext = dmbound;
8177:     lastnext = &(dmbound->next);
8178:     dsbound = dsbound->next;
8179:   }
8180:   return(0);
8181: }

8183: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8184: {
8185:   DMBoundary     b;

8191:   *isBd = PETSC_FALSE;
8192:   DMPopulateBoundary(dm);
8193:   b = dm->boundary;
8194:   while (b && !(*isBd)) {
8195:     DMLabel    label = b->label;
8196:     DSBoundary dsb = b->dsboundary;

8198:     if (label) {
8199:       PetscInt i;

8201:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8202:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
8203:       }
8204:     }
8205:     b = b->next;
8206:   }
8207:   return(0);
8208: }

8210: /*@C
8211:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8213:   Collective on DM

8215:   Input Parameters:
8216: + dm      - The DM
8217: . time    - The time
8218: . funcs   - The coordinate functions to evaluate, one per field
8219: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8220: - mode    - The insertion mode for values

8222:   Output Parameter:
8223: . X - vector

8225:    Calling sequence of func:
8226: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8228: +  dim - The spatial dimension
8229: .  time - The time at which to sample
8230: .  x   - The coordinates
8231: .  Nf  - The number of fields
8232: .  u   - The output field values
8233: -  ctx - optional user-defined function context

8235:   Level: developer

8237: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8238: @*/
8239: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8240: {
8241:   Vec            localX;

8246:   DMGetLocalVector(dm, &localX);
8247:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8248:   DMLocalToGlobalBegin(dm, localX, mode, X);
8249:   DMLocalToGlobalEnd(dm, localX, mode, X);
8250:   DMRestoreLocalVector(dm, &localX);
8251:   return(0);
8252: }

8254: /*@C
8255:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8257:   Not collective

8259:   Input Parameters:
8260: + dm      - The DM
8261: . time    - The time
8262: . funcs   - The coordinate functions to evaluate, one per field
8263: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8264: - mode    - The insertion mode for values

8266:   Output Parameter:
8267: . localX - vector

8269:    Calling sequence of func:
8270: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8272: +  dim - The spatial dimension
8273: .  x   - The coordinates
8274: .  Nf  - The number of fields
8275: .  u   - The output field values
8276: -  ctx - optional user-defined function context

8278:   Level: developer

8280: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8281: @*/
8282: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8283: {

8289:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8290:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8291:   return(0);
8292: }

8294: /*@C
8295:   DMProjectFunctionLabel - This projects the given function into the function space provided, putting the coefficients in a global vector, setting values only for points in the given label.

8297:   Collective on DM

8299:   Input Parameters:
8300: + dm      - The DM
8301: . time    - The time
8302: . label   - The DMLabel selecting the portion of the mesh for projection
8303: . funcs   - The coordinate functions to evaluate, one per field
8304: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8305: - mode    - The insertion mode for values

8307:   Output Parameter:
8308: . X - vector

8310:    Calling sequence of func:
8311: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8313: +  dim - The spatial dimension
8314: .  x   - The coordinates
8315: .  Nf  - The number of fields
8316: .  u   - The output field values
8317: -  ctx - optional user-defined function context

8319:   Level: developer

8321: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8322: @*/
8323: PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8324: {
8325:   Vec            localX;

8330:   DMGetLocalVector(dm, &localX);
8331:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8332:   DMLocalToGlobalBegin(dm, localX, mode, X);
8333:   DMLocalToGlobalEnd(dm, localX, mode, X);
8334:   DMRestoreLocalVector(dm, &localX);
8335:   return(0);
8336: }

8338: /*@C
8339:   DMProjectFunctionLabelLocal - This projects the given function into the function space provided, putting the coefficients in a local vector, setting values only for points in the given label.

8341:   Not collective

8343:   Input Parameters:
8344: + dm      - The DM
8345: . time    - The time
8346: . label   - The DMLabel selecting the portion of the mesh for projection
8347: . funcs   - The coordinate functions to evaluate, one per field
8348: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8349: - mode    - The insertion mode for values

8351:   Output Parameter:
8352: . localX - vector

8354:    Calling sequence of func:
8355: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

8357: +  dim - The spatial dimension
8358: .  x   - The coordinates
8359: .  Nf  - The number of fields
8360: .  u   - The output field values
8361: -  ctx - optional user-defined function context

8363:   Level: developer

8365: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8366: @*/
8367: 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)
8368: {

8374:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8375:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8376:   return(0);
8377: }

8379: /*@C
8380:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8382:   Not collective

8384:   Input Parameters:
8385: + dm      - The DM
8386: . time    - The time
8387: . localU  - The input field vector
8388: . funcs   - The functions to evaluate, one per field
8389: - mode    - The insertion mode for values

8391:   Output Parameter:
8392: . localX  - The output vector

8394:    Calling sequence of func:
8395: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8396: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8397: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8398: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8400: +  dim          - The spatial dimension
8401: .  Nf           - The number of input fields
8402: .  NfAux        - The number of input auxiliary fields
8403: .  uOff         - The offset of each field in u[]
8404: .  uOff_x       - The offset of each field in u_x[]
8405: .  u            - The field values at this point in space
8406: .  u_t          - The field time derivative at this point in space (or NULL)
8407: .  u_x          - The field derivatives at this point in space
8408: .  aOff         - The offset of each auxiliary field in u[]
8409: .  aOff_x       - The offset of each auxiliary field in u_x[]
8410: .  a            - The auxiliary field values at this point in space
8411: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8412: .  a_x          - The auxiliary field derivatives at this point in space
8413: .  t            - The current time
8414: .  x            - The coordinates of this point
8415: .  numConstants - The number of constants
8416: .  constants    - The value of each constant
8417: -  f            - The value of the function at this point in space

8419:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8420:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8421:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8422:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8424:   Level: intermediate

8426: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8427: @*/
8428: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8429:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8430:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8431:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8432:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8433:                                    InsertMode mode, Vec localX)
8434: {

8441:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8442:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8443:   return(0);
8444: }

8446: /*@C
8447:   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.

8449:   Not collective

8451:   Input Parameters:
8452: + dm      - The DM
8453: . time    - The time
8454: . label   - The DMLabel marking the portion of the domain to output
8455: . numIds  - The number of label ids to use
8456: . ids     - The label ids to use for marking
8457: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8458: . comps   - The components to set in the output, or NULL for all components
8459: . localU  - The input field vector
8460: . funcs   - The functions to evaluate, one per field
8461: - mode    - The insertion mode for values

8463:   Output Parameter:
8464: . localX  - The output vector

8466:    Calling sequence of func:
8467: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8468: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8469: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8470: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8472: +  dim          - The spatial dimension
8473: .  Nf           - The number of input fields
8474: .  NfAux        - The number of input auxiliary fields
8475: .  uOff         - The offset of each field in u[]
8476: .  uOff_x       - The offset of each field in u_x[]
8477: .  u            - The field values at this point in space
8478: .  u_t          - The field time derivative at this point in space (or NULL)
8479: .  u_x          - The field derivatives at this point in space
8480: .  aOff         - The offset of each auxiliary field in u[]
8481: .  aOff_x       - The offset of each auxiliary field in u_x[]
8482: .  a            - The auxiliary field values at this point in space
8483: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8484: .  a_x          - The auxiliary field derivatives at this point in space
8485: .  t            - The current time
8486: .  x            - The coordinates of this point
8487: .  numConstants - The number of constants
8488: .  constants    - The value of each constant
8489: -  f            - The value of the function at this point in space

8491:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8492:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8493:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8494:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8496:   Level: intermediate

8498: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8499: @*/
8500: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8501:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8502:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8503:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8504:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8505:                                         InsertMode mode, Vec localX)
8506: {

8513:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8514:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8515:   return(0);
8516: }

8518: /*@C
8519:   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.

8521:   Not collective

8523:   Input Parameters:
8524: + dm      - The DM
8525: . time    - The time
8526: . label   - The DMLabel marking the portion of the domain boundary to output
8527: . numIds  - The number of label ids to use
8528: . ids     - The label ids to use for marking
8529: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8530: . comps   - The components to set in the output, or NULL for all components
8531: . localU  - The input field vector
8532: . funcs   - The functions to evaluate, one per field
8533: - mode    - The insertion mode for values

8535:   Output Parameter:
8536: . localX  - The output vector

8538:    Calling sequence of func:
8539: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8540: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8541: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8542: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8544: +  dim          - The spatial dimension
8545: .  Nf           - The number of input fields
8546: .  NfAux        - The number of input auxiliary fields
8547: .  uOff         - The offset of each field in u[]
8548: .  uOff_x       - The offset of each field in u_x[]
8549: .  u            - The field values at this point in space
8550: .  u_t          - The field time derivative at this point in space (or NULL)
8551: .  u_x          - The field derivatives at this point in space
8552: .  aOff         - The offset of each auxiliary field in u[]
8553: .  aOff_x       - The offset of each auxiliary field in u_x[]
8554: .  a            - The auxiliary field values at this point in space
8555: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8556: .  a_x          - The auxiliary field derivatives at this point in space
8557: .  t            - The current time
8558: .  x            - The coordinates of this point
8559: .  n            - The face normal
8560: .  numConstants - The number of constants
8561: .  constants    - The value of each constant
8562: -  f            - The value of the function at this point in space

8564:   Note:
8565:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8566:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8567:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8568:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8570:   Level: intermediate

8572: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8573: @*/
8574: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8575:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8576:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8577:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8578:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8579:                                           InsertMode mode, Vec localX)
8580: {

8587:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8588:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8589:   return(0);
8590: }

8592: /*@C
8593:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8595:   Input Parameters:
8596: + dm    - The DM
8597: . time  - The time
8598: . funcs - The functions to evaluate for each field component
8599: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8600: - X     - The coefficient vector u_h, a global vector

8602:   Output Parameter:
8603: . diff - The diff ||u - u_h||_2

8605:   Level: developer

8607: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8608: @*/
8609: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8610: {

8616:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8617:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8618:   return(0);
8619: }

8621: /*@C
8622:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8624:   Collective on dm

8626:   Input Parameters:
8627: + dm    - The DM
8628: , time  - The time
8629: . funcs - The gradient functions to evaluate for each field component
8630: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8631: . X     - The coefficient vector u_h, a global vector
8632: - n     - The vector to project along

8634:   Output Parameter:
8635: . diff - The diff ||(grad u - grad u_h) . n||_2

8637:   Level: developer

8639: .seealso: DMProjectFunction(), DMComputeL2Diff()
8640: @*/
8641: 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)
8642: {

8648:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8649:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8650:   return(0);
8651: }

8653: /*@C
8654:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8656:   Collective on dm

8658:   Input Parameters:
8659: + dm    - The DM
8660: . time  - The time
8661: . funcs - The functions to evaluate for each field component
8662: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8663: - X     - The coefficient vector u_h, a global vector

8665:   Output Parameter:
8666: . diff - The array of differences, ||u^f - u^f_h||_2

8668:   Level: developer

8670: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8671: @*/
8672: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8673: {

8679:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8680:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
8681:   return(0);
8682: }

8684: /*@C
8685:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8686:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

8688:   Collective on dm

8690:   Input parameters:
8691: + dm - the pre-adaptation DM object
8692: - label - label with the flags

8694:   Output parameters:
8695: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

8697:   Level: intermediate

8699: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8700: @*/
8701: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8702: {

8709:   *dmAdapt = NULL;
8710:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8711:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
8712:   return(0);
8713: }

8715: /*@C
8716:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

8718:   Input Parameters:
8719: + dm - The DM object
8720: . metric - The metric to which the mesh is adapted, defined vertex-wise.
8721: - 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_".

8723:   Output Parameter:
8724: . dmAdapt  - Pointer to the DM object containing the adapted mesh

8726:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

8728:   Level: advanced

8730: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8731: @*/
8732: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8733: {

8741:   *dmAdapt = NULL;
8742:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8743:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
8744:   return(0);
8745: }

8747: /*@C
8748:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

8750:  Not Collective

8752:  Input Parameter:
8753: .  dm    - The DM

8755:  Output Parameters:
8756: +  nranks - the number of neighbours
8757: -  ranks - the neighbors ranks

8759:  Notes:
8760:  Do not free the array, it is freed when the DM is destroyed.

8762:  Level: beginner

8764:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
8765: @*/
8766: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
8767: {

8772:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
8773:   (dm->ops->getneighbors)(dm,nranks,ranks);
8774:   return(0);
8775: }

8777: #include <petsc/private/matimpl.h>

8779: /*
8780:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8781:     This has be a different function because it requires DM which is not defined in the Mat library
8782: */
8783: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
8784: {

8788:   if (coloring->ctype == IS_COLORING_LOCAL) {
8789:     Vec x1local;
8790:     DM  dm;
8791:     MatGetDM(J,&dm);
8792:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
8793:     DMGetLocalVector(dm,&x1local);
8794:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
8795:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
8796:     x1   = x1local;
8797:   }
8798:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
8799:   if (coloring->ctype == IS_COLORING_LOCAL) {
8800:     DM  dm;
8801:     MatGetDM(J,&dm);
8802:     DMRestoreLocalVector(dm,&x1);
8803:   }
8804:   return(0);
8805: }

8807: /*@
8808:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

8810:     Input Parameter:
8811: .    coloring - the MatFDColoring object

8813:     Developer Notes:
8814:     this routine exists because the PETSc Mat library does not know about the DM objects

8816:     Level: advanced

8818: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
8819: @*/
8820: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
8821: {
8823:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8824:   return(0);
8825: }

8827: /*@
8828:     DMGetCompatibility - determine if two DMs are compatible

8830:     Collective

8832:     Input Parameters:
8833: +    dm1 - the first DM
8834: -    dm2 - the second DM

8836:     Output Parameters:
8837: +    compatible - whether or not the two DMs are compatible
8838: -    set - whether or not the compatible value was set

8840:     Notes:
8841:     Two DMs are deemed compatible if they represent the same parallel decomposition
8842:     of the same topology. This implies that the section (field data) on one
8843:     "makes sense" with respect to the topology and parallel decomposition of the other.
8844:     Loosely speaking, compatible DMs represent the same domain and parallel
8845:     decomposition, but hold different data.

8847:     Typically, one would confirm compatibility if intending to simultaneously iterate
8848:     over a pair of vectors obtained from different DMs.

8850:     For example, two DMDA objects are compatible if they have the same local
8851:     and global sizes and the same stencil width. They can have different numbers
8852:     of degrees of freedom per node. Thus, one could use the node numbering from
8853:     either DM in bounds for a loop over vectors derived from either DM.

8855:     Consider the operation of summing data living on a 2-dof DMDA to data living
8856:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
8857: .vb
8858:   ...
8859:   DMGetCompatibility(da1,da2,&compatible,&set);
8860:   if (set && compatible)  {
8861:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8862:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8863:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8864:     for (j=y; j<y+n; ++j) {
8865:       for (i=x; i<x+m, ++i) {
8866:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8867:       }
8868:     }
8869:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8870:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8871:   } else {
8872:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8873:   }
8874:   ...
8875: .ve

8877:     Checking compatibility might be expensive for a given implementation of DM,
8878:     or might be impossible to unambiguously confirm or deny. For this reason,
8879:     this function may decline to determine compatibility, and hence users should
8880:     always check the "set" output parameter.

8882:     A DM is always compatible with itself.

8884:     In the current implementation, DMs which live on "unequal" communicators
8885:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8886:     incompatible.

8888:     This function is labeled "Collective," as information about all subdomains
8889:     is required on each rank. However, in DM implementations which store all this
8890:     information locally, this function may be merely "Logically Collective".

8892:     Developer Notes:
8893:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
8894:     iff B is compatible with A. Thus, this function checks the implementations
8895:     of both dm and dmc (if they are of different types), attempting to determine
8896:     compatibility. It is left to DM implementers to ensure that symmetry is
8897:     preserved. The simplest way to do this is, when implementing type-specific
8898:     logic for this function, is to check for existing logic in the implementation
8899:     of other DM types and let *set = PETSC_FALSE if found.

8901:     Level: advanced

8903: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
8904: @*/

8906: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
8907: {
8909:   PetscMPIInt    compareResult;
8910:   DMType         type,type2;
8911:   PetscBool      sameType;


8917:   /* Declare a DM compatible with itself */
8918:   if (dm1 == dm2) {
8919:     *set = PETSC_TRUE;
8920:     *compatible = PETSC_TRUE;
8921:     return(0);
8922:   }

8924:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8925:      communicator. Note that this does not preclude compatibility with
8926:      DMs living on "congruent" or "similar" communicators, but this must be
8927:      determined by the implementation-specific logic */
8928:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
8929:   if (compareResult == MPI_UNEQUAL) {
8930:     *set = PETSC_TRUE;
8931:     *compatible = PETSC_FALSE;
8932:     return(0);
8933:   }

8935:   /* Pass to the implementation-specific routine, if one exists. */
8936:   if (dm1->ops->getcompatibility) {
8937:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
8938:     if (*set) return(0);
8939:   }

8941:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8942:      with an implementation of this function from dm2 */
8943:   DMGetType(dm1,&type);
8944:   DMGetType(dm2,&type2);
8945:   PetscStrcmp(type,type2,&sameType);
8946:   if (!sameType && dm2->ops->getcompatibility) {
8947:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
8948:   } else {
8949:     *set = PETSC_FALSE;
8950:   }
8951:   return(0);
8952: }

8954: /*@C
8955:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

8957:   Logically Collective on DM

8959:   Input Parameters:
8960: + DM - the DM
8961: . f - the monitor function
8962: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8963: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

8965:   Options Database Keys:
8966: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
8967:                             does not cancel those set via the options database.

8969:   Notes:
8970:   Several different monitoring routines may be set by calling
8971:   DMMonitorSet() multiple times; all will be called in the
8972:   order in which they were set.

8974:   Fortran Notes:
8975:   Only a single monitor function can be set for each DM object

8977:   Level: intermediate

8979: .seealso: DMMonitorCancel()
8980: @*/
8981: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
8982: {
8983:   PetscInt       m;

8988:   for (m = 0; m < dm->numbermonitors; ++m) {
8989:     PetscBool identical;

8991:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8992:     if (identical) return(0);
8993:   }
8994:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8995:   dm->monitor[dm->numbermonitors]          = f;
8996:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8997:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
8998:   return(0);
8999: }

9001: /*@
9002:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9004:   Logically Collective on DM

9006:   Input Parameter:
9007: . dm - the DM

9009:   Options Database Key:
9010: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9011:   into a code by calls to DMonitorSet(), but does not cancel those
9012:   set via the options database

9014:   Notes:
9015:   There is no way to clear one specific monitor from a DM object.

9017:   Level: intermediate

9019: .seealso: DMMonitorSet()
9020: @*/
9021: PetscErrorCode DMMonitorCancel(DM dm)
9022: {
9024:   PetscInt       m;

9028:   for (m = 0; m < dm->numbermonitors; ++m) {
9029:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
9030:   }
9031:   dm->numbermonitors = 0;
9032:   return(0);
9033: }

9035: /*@C
9036:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9038:   Collective on DM

9040:   Input Parameters:
9041: + dm   - DM object you wish to monitor
9042: . name - the monitor type one is seeking
9043: . help - message indicating what monitoring is done
9044: . manual - manual page for the monitor
9045: . monitor - the monitor function
9046: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the DM or PetscViewer objects

9048:   Output Parameter:
9049: . flg - Flag set if the monitor was created

9051:   Level: developer

9053: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9054:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9055:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9056:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9057:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9058:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9059:           PetscOptionsFList(), PetscOptionsEList()
9060: @*/
9061: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9062: {
9063:   PetscViewer       viewer;
9064:   PetscViewerFormat format;
9065:   PetscErrorCode    ierr;

9069:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9070:   if (*flg) {
9071:     PetscViewerAndFormat *vf;

9073:     PetscViewerAndFormatCreate(viewer, format, &vf);
9074:     PetscObjectDereference((PetscObject) viewer);
9075:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
9076:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9077:   }
9078:   return(0);
9079: }

9081: /*@
9082:    DMMonitor - runs the user provided monitor routines, if they exist

9084:    Collective on DM

9086:    Input Parameters:
9087: .  dm - The DM

9089:    Level: developer

9091: .seealso: DMMonitorSet()
9092: @*/
9093: PetscErrorCode DMMonitor(DM dm)
9094: {
9095:   PetscInt       m;

9099:   if (!dm) return(0);
9101:   for (m = 0; m < dm->numbermonitors; ++m) {
9102:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9103:   }
9104:   return(0);
9105: }