Actual source code: dm.c

  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: #ifdef PETSC_HAVE_LIBCEED
 11: #include <petscfeceed.h>
 12: #endif

 14: #if defined(PETSC_HAVE_VALGRIND)
 15: #  include <valgrind/memcheck.h>
 16: #endif

 18: PetscClassId  DM_CLASSID;
 19: PetscClassId  DMLABEL_CLASSID;
 20: 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;

 22: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
 23: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","ESSENTIAL_BD_FIELD","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
 24: const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
 25: const char *const DMCopyLabelsModes[] = {"replace","keep","fail","DMCopyLabelsMode","DM_COPY_LABELS_", NULL};

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

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

 33:   Collective

 35:   Input Parameter:
 36: . comm - The communicator for the DM object

 38:   Output Parameter:
 39: . dm - The DM object

 41:   Level: beginner

 43: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
 44: @*/
 45: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
 46: {
 47:   DM             v;
 48:   PetscDS        ds;

 51:   *dm = NULL;
 52:   DMInitializePackage();

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

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

 97:   *dm = v;
 98:   return 0;
 99: }

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

104:   Collective

106:   Input Parameter:
107: . dm - The original DM object

109:   Output Parameter:
110: . newdm  - The new DM object

112:   Level: beginner

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

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

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

123: @*/
124: PetscErrorCode DMClone(DM dm, DM *newdm)
125: {
126:   PetscSF        sf;
127:   Vec            coords;
128:   void          *ctx;
129:   PetscInt       dim, cdim;

133:   DMCreate(PetscObjectComm((PetscObject) dm), newdm);
134:   DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL);
135:   (*newdm)->leveldown  = dm->leveldown;
136:   (*newdm)->levelup    = dm->levelup;
137:   (*newdm)->prealloc_only = dm->prealloc_only;
138:   PetscFree((*newdm)->vectype);
139:   PetscStrallocpy(dm->vectype,(char**)&(*newdm)->vectype);
140:   PetscFree((*newdm)->mattype);
141:   PetscStrallocpy(dm->mattype,(char**)&(*newdm)->mattype);
142:   DMGetDimension(dm, &dim);
143:   DMSetDimension(*newdm, dim);
144:   if (dm->ops->clone) {
145:     (*dm->ops->clone)(dm, newdm);
146:   }
147:   (*newdm)->setupcalled = dm->setupcalled;
148:   DMGetPointSF(dm, &sf);
149:   DMSetPointSF(*newdm, sf);
150:   DMGetApplicationContext(dm, &ctx);
151:   DMSetApplicationContext(*newdm, ctx);
152:   if (dm->coordinateDM) {
153:     DM           ncdm;
154:     PetscSection cs;
155:     PetscInt     pEnd = -1, pEndMax = -1;

157:     DMGetLocalSection(dm->coordinateDM, &cs);
158:     if (cs) PetscSectionGetChart(cs, NULL, &pEnd);
159:     MPI_Allreduce(&pEnd,&pEndMax,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));
160:     if (pEndMax >= 0) {
161:       DMClone(dm->coordinateDM, &ncdm);
162:       DMCopyDisc(dm->coordinateDM, ncdm);
163:       DMSetLocalSection(ncdm, cs);
164:       DMSetCoordinateDM(*newdm, ncdm);
165:       DMDestroy(&ncdm);
166:     }
167:   }
168:   DMGetCoordinateDim(dm, &cdim);
169:   DMSetCoordinateDim(*newdm, cdim);
170:   DMGetCoordinatesLocal(dm, &coords);
171:   if (coords) {
172:     DMSetCoordinatesLocal(*newdm, coords);
173:   } else {
174:     DMGetCoordinates(dm, &coords);
175:     if (coords) DMSetCoordinates(*newdm, coords);
176:   }
177:   {
178:     PetscBool             isper;
179:     const PetscReal      *maxCell, *L;
180:     const DMBoundaryType *bd;
181:     DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
182:     DMSetPeriodicity(*newdm, isper, maxCell,  L,  bd);
183:   }
184:   {
185:     PetscBool useCone, useClosure;

187:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
188:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
189:   }
190:   return 0;
191: }

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

196:    Logically Collective on da

198:    Input Parameters:
199: +  da - initial distributed array
200: -  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

202:    Options Database:
203: .   -dm_vec_type ctype - the type of vector to create

205:    Level: intermediate

207: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
208: @*/
209: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
210: {
212:   PetscFree(da->vectype);
213:   PetscStrallocpy(ctype,(char**)&da->vectype);
214:   return 0;
215: }

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

220:    Logically Collective on da

222:    Input Parameter:
223: .  da - initial distributed array

225:    Output Parameter:
226: .  ctype - the vector type

228:    Level: intermediate

230: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMSetMatType(), DMGetMatType(), DMSetVecType()
231: @*/
232: PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
233: {
235:   *ctype = da->vectype;
236:   return 0;
237: }

239: /*@
240:   VecGetDM - Gets the DM defining the data layout of the vector

242:   Not collective

244:   Input Parameter:
245: . v - The Vec

247:   Output Parameter:
248: . dm - The DM

250:   Level: intermediate

252: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
253: @*/
254: PetscErrorCode VecGetDM(Vec v, DM *dm)
255: {
258:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
259:   return 0;
260: }

262: /*@
263:   VecSetDM - Sets the DM defining the data layout of the vector.

265:   Not collective

267:   Input Parameters:
268: + v - The Vec
269: - dm - The DM

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

273:   Level: intermediate

275: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
276: @*/
277: PetscErrorCode VecSetDM(Vec v, DM dm)
278: {
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: {
305:   dm->coloringtype = ctype;
306:   return 0;
307: }

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

312:    Logically Collective on dm

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

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

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

323:    Level: intermediate

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

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

338:    Logically Collective on dm

340:    Input Parameters:
341: +  dm - the DM context
342: -  ctype - the matrix type

344:    Options Database:
345: .   -dm_mat_type ctype - the type of the matrix to create

347:    Level: intermediate

349: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
350: @*/
351: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
352: {
354:   PetscFree(dm->mattype);
355:   PetscStrallocpy(ctype,(char**)&dm->mattype);
356:   return 0;
357: }

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

362:    Logically Collective on dm

364:    Input Parameter:
365: .  dm - the DM context

367:    Output Parameter:
368: .  ctype - the matrix type

370:    Options Database:
371: .   -dm_mat_type ctype - the matrix type

373:    Level: intermediate

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

384: /*@
385:   MatGetDM - Gets the DM defining the data layout of the matrix

387:   Not collective

389:   Input Parameter:
390: . A - The Mat

392:   Output Parameter:
393: . dm - The DM

395:   Level: intermediate

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

400: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
401: @*/
402: PetscErrorCode MatGetDM(Mat A, DM *dm)
403: {
406:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
407:   return 0;
408: }

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

413:   Not collective

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

419:   Level: intermediate

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

424: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
425: @*/
426: PetscErrorCode MatSetDM(Mat A, DM dm)
427: {
430:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
431:   return 0;
432: }

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

438:    Logically Collective on dm

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

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

448:    Level: advanced

450: .seealso: DMSetFromOptions()
451: @*/
452: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
453: {
455:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
456:   if (dm->sf) {
457:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
458:   }
459:   if (dm->sectionSF) {
460:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
461:   }
462:   return 0;
463: }

465: /*@C
466:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
467:    DM options in the database.

469:    Logically Collective on dm

471:    Input Parameters:
472: +  dm - the DM context
473: -  prefix - the prefix string to prepend to all DM option requests

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

479:    Level: advanced

481: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
482: @*/
483: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
484: {
486:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
487:   return 0;
488: }

490: /*@C
491:    DMGetOptionsPrefix - Gets the prefix used for searching for all
492:    DM options in the database.

494:    Not Collective

496:    Input Parameters:
497: .  dm - the DM context

499:    Output Parameters:
500: .  prefix - pointer to the prefix string used is returned

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

506:    Level: advanced

508: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
509: @*/
510: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
511: {
513:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
514:   return 0;
515: }

517: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
518: {
519:   PetscInt       refct = ((PetscObject) dm)->refct;

521:   *ncrefct = 0;
522:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
523:     refct--;
524:     if (recurseCoarse) {
525:       PetscInt coarseCount;

527:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
528:       refct += coarseCount;
529:     }
530:   }
531:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
532:     refct--;
533:     if (recurseFine) {
534:       PetscInt fineCount;

536:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
537:       refct += fineCount;
538:     }
539:   }
540:   *ncrefct = refct;
541:   return 0;
542: }

544: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
545: {
546:   DMLabelLink    next = dm->labels;

548:   /* destroy the labels */
549:   while (next) {
550:     DMLabelLink tmp = next->next;

552:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
553:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
554:     DMLabelDestroy(&next->label);
555:     PetscFree(next);
556:     next = tmp;
557:   }
558:   dm->labels = NULL;
559:   return 0;
560: }

562: /*@C
563:     DMDestroy - Destroys a vector packer or DM.

565:     Collective on dm

567:     Input Parameter:
568: .   dm - the DM object to destroy

570:     Level: developer

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

574: @*/
575: PetscErrorCode  DMDestroy(DM *dm)
576: {
577:   PetscInt       cnt;
578:   DMNamedVecLink nlink,nnext;

580:   if (!*dm) return 0;

583:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
584:   DMCountNonCyclicReferences(*dm,PETSC_TRUE,PETSC_TRUE,&cnt);
585:   --((PetscObject)(*dm))->refct;
586:   if (--cnt > 0) {*dm = NULL; return 0;}
587:   if (((PetscObject)(*dm))->refct < 0) return 0;
588:   ((PetscObject)(*dm))->refct = 0;

590:   DMClearGlobalVectors(*dm);
591:   DMClearLocalVectors(*dm);

593:   nnext=(*dm)->namedglobal;
594:   (*dm)->namedglobal = NULL;
595:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
596:     nnext = nlink->next;
598:     PetscFree(nlink->name);
599:     VecDestroy(&nlink->X);
600:     PetscFree(nlink);
601:   }
602:   nnext=(*dm)->namedlocal;
603:   (*dm)->namedlocal = NULL;
604:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
605:     nnext = nlink->next;
607:     PetscFree(nlink->name);
608:     VecDestroy(&nlink->X);
609:     PetscFree(nlink);
610:   }

612:   /* Destroy the list of hooks */
613:   {
614:     DMCoarsenHookLink link,next;
615:     for (link=(*dm)->coarsenhook; link; link=next) {
616:       next = link->next;
617:       PetscFree(link);
618:     }
619:     (*dm)->coarsenhook = NULL;
620:   }
621:   {
622:     DMRefineHookLink link,next;
623:     for (link=(*dm)->refinehook; link; link=next) {
624:       next = link->next;
625:       PetscFree(link);
626:     }
627:     (*dm)->refinehook = NULL;
628:   }
629:   {
630:     DMSubDomainHookLink link,next;
631:     for (link=(*dm)->subdomainhook; link; link=next) {
632:       next = link->next;
633:       PetscFree(link);
634:     }
635:     (*dm)->subdomainhook = NULL;
636:   }
637:   {
638:     DMGlobalToLocalHookLink link,next;
639:     for (link=(*dm)->gtolhook; link; link=next) {
640:       next = link->next;
641:       PetscFree(link);
642:     }
643:     (*dm)->gtolhook = NULL;
644:   }
645:   {
646:     DMLocalToGlobalHookLink link,next;
647:     for (link=(*dm)->ltoghook; link; link=next) {
648:       next = link->next;
649:       PetscFree(link);
650:     }
651:     (*dm)->ltoghook = NULL;
652:   }
653:   /* Destroy the work arrays */
654:   {
655:     DMWorkLink link,next;
657:     for (link=(*dm)->workin; link; link=next) {
658:       next = link->next;
659:       PetscFree(link->mem);
660:       PetscFree(link);
661:     }
662:     (*dm)->workin = NULL;
663:   }
664:   /* destroy the labels */
665:   DMDestroyLabelLinkList_Internal(*dm);
666:   /* destroy the fields */
667:   DMClearFields(*dm);
668:   /* destroy the boundaries */
669:   {
670:     DMBoundary next = (*dm)->boundary;
671:     while (next) {
672:       DMBoundary b = next;

674:       next = b->next;
675:       PetscFree(b);
676:     }
677:   }

679:   PetscObjectDestroy(&(*dm)->dmksp);
680:   PetscObjectDestroy(&(*dm)->dmsnes);
681:   PetscObjectDestroy(&(*dm)->dmts);

683:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
684:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
685:   }
686:   MatFDColoringDestroy(&(*dm)->fd);
687:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
688:   PetscFree((*dm)->vectype);
689:   PetscFree((*dm)->mattype);

691:   PetscSectionDestroy(&(*dm)->localSection);
692:   PetscSectionDestroy(&(*dm)->globalSection);
693:   PetscLayoutDestroy(&(*dm)->map);
694:   PetscSectionDestroy(&(*dm)->defaultConstraint.section);
695:   MatDestroy(&(*dm)->defaultConstraint.mat);
696:   PetscSFDestroy(&(*dm)->sf);
697:   PetscSFDestroy(&(*dm)->sectionSF);
698:   if ((*dm)->useNatural) {
699:     if ((*dm)->sfNatural) {
700:       PetscSFDestroy(&(*dm)->sfNatural);
701:     }
702:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
703:   }
704:   {
705:     Vec     *auxData;
706:     PetscInt n, i, off = 0;

708:     PetscHMapAuxGetSize((*dm)->auxData, &n);
709:     PetscMalloc1(n, &auxData);
710:     PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
711:     for (i = 0; i < n; ++i) VecDestroy(&auxData[i]);
712:     PetscFree(auxData);
713:     PetscHMapAuxDestroy(&(*dm)->auxData);
714:   }
715:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
716:     DMSetFineDM((*dm)->coarseMesh,NULL);
717:   }

719:   DMDestroy(&(*dm)->coarseMesh);
720:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
721:     DMSetCoarseDM((*dm)->fineMesh,NULL);
722:   }
723:   DMDestroy(&(*dm)->fineMesh);
724:   DMFieldDestroy(&(*dm)->coordinateField);
725:   DMDestroy(&(*dm)->coordinateDM);
726:   VecDestroy(&(*dm)->coordinates);
727:   VecDestroy(&(*dm)->coordinatesLocal);
728:   PetscFree((*dm)->L);
729:   PetscFree((*dm)->maxCell);
730:   PetscFree((*dm)->bdtype);
731:   if ((*dm)->transformDestroy) (*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);
732:   DMDestroy(&(*dm)->transformDM);
733:   VecDestroy(&(*dm)->transform);

735:   DMClearDS(*dm);
736:   DMDestroy(&(*dm)->dmBC);
737:   /* if memory was published with SAWs then destroy it */
738:   PetscObjectSAWsViewOff((PetscObject)*dm);

740:   if ((*dm)->ops->destroy) {
741:     (*(*dm)->ops->destroy)(*dm);
742:   }
743:   DMMonitorCancel(*dm);
744: #ifdef PETSC_HAVE_LIBCEED
745:   CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
746:   CeedDestroy(&(*dm)->ceed);
747: #endif
748:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
749:   PetscHeaderDestroy(dm);
750:   return 0;
751: }

753: /*@
754:     DMSetUp - sets up the data structures inside a DM object

756:     Collective on dm

758:     Input Parameter:
759: .   dm - the DM object to setup

761:     Level: developer

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

765: @*/
766: PetscErrorCode  DMSetUp(DM dm)
767: {
769:   if (dm->setupcalled) return 0;
770:   if (dm->ops->setup) {
771:     (*dm->ops->setup)(dm);
772:   }
773:   dm->setupcalled = PETSC_TRUE;
774:   return 0;
775: }

777: /*@
778:     DMSetFromOptions - sets parameters in a DM from the options database

780:     Collective on dm

782:     Input Parameter:
783: .   dm - the DM object to set options for

785:     Options Database:
786: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
787: .   -dm_vec_type <type>  - type of vector to create inside DM
788: .   -dm_mat_type <type>  - type of matrix to create inside DM
789: .   -dm_is_coloring_type - <global or local>
790: -   -dm_bind_below <n>   - bind (force execution on CPU) for Vec and Mat objects with local size (number of vector entries or matrix rows) below n; currently only supported for DMDA

792:     DMPLEX Specific creation options
793: + -dm_plex_filename <str>           - File containing a mesh
794: . -dm_plex_boundary_filename <str>  - File containing a mesh boundary
795: . -dm_plex_name <str>               - Name of the mesh in the file
796: . -dm_plex_shape <shape>            - The domain shape, such as DM_SHAPE_BOX, DM_SHAPE_SPHERE, etc.
797: . -dm_plex_cell <ct>                - Cell shape
798: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
799: . -dm_plex_dim <dim>                - Set the topological dimension
800: . -dm_plex_simplex <bool>           - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
801: . -dm_plex_interpolate <bool>       - PETSC_TRUE turns on topological interpolation (creating edges and faces)
802: . -dm_plex_scale <sc>               - Scale factor for mesh coordinates
803: . -dm_plex_box_faces <m,n,p>        - Number of faces along each dimension
804: . -dm_plex_box_lower <x,y,z>        - Specify lower-left-bottom coordinates for the box
805: . -dm_plex_box_upper <x,y,z>        - Specify upper-right-top coordinates for the box
806: . -dm_plex_box_bd <bx,by,bz>        - Specify the DMBoundaryType for each direction
807: . -dm_plex_sphere_radius <r>        - The sphere radius
808: . -dm_plex_ball_radius <r>          - Radius of the ball
809: . -dm_plex_cylinder_bd <bz>         - Boundary type in the z direction
810: . -dm_plex_cylinder_num_wedges <n>  - Number of wedges around the cylinder
811: . -dm_plex_reorder <order>          - Reorder the mesh using the specified algorithm
812: . -dm_refine_pre <n>                - The number of refinements before distribution
813: . -dm_refine_uniform_pre <bool>     - Flag for uniform refinement before distribution
814: . -dm_refine_volume_limit_pre <v>   - The maximum cell volume after refinement before distribution
815: . -dm_refine <n>                    - The number of refinements after distribution
816: . -dm_extrude <l>                   - Activate extrusion and specify the number of layers to extrude
817: . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
818: . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
819: . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
820: . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
821: . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
822: . -dm_plex_create_fv_ghost_cells    - Flag to create finite volume ghost cells on the boundary
823: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
824: . -dm_distribute <bool>             - Flag to redistribute a mesh among processes
825: . -dm_distribute_overlap <n>        - The size of the overlap halo
826: . -dm_plex_adj_cone <bool>          - Set adjacency direction
827: - -dm_plex_adj_closure <bool>       - Set adjacency size

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

838:     Level: intermediate

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

843: @*/
844: PetscErrorCode DMSetFromOptions(DM dm)
845: {
846:   char           typeName[256];
847:   PetscBool      flg;

851:   dm->setfromoptionscalled = PETSC_TRUE;
852:   if (dm->sf) PetscSFSetFromOptions(dm->sf);
853:   if (dm->sectionSF) PetscSFSetFromOptions(dm->sectionSF);
854:   PetscObjectOptionsBegin((PetscObject)dm);
855:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
856:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
857:   if (flg) {
858:     DMSetVecType(dm,typeName);
859:   }
860:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
861:   if (flg) {
862:     DMSetMatType(dm,typeName);
863:   }
864:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
865:   PetscOptionsInt("-dm_bind_below","Set the size threshold (in entries) below which the Vec is bound to the CPU","VecBindToCPU",dm->bind_below,&dm->bind_below,&flg);
866:   if (dm->ops->setfromoptions) {
867:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
868:   }
869:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
870:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
871:   PetscOptionsEnd();
872:   return 0;
873: }

875: /*@C
876:    DMViewFromOptions - View from Options

878:    Collective on DM

880:    Input Parameters:
881: +  dm - the DM object
882: .  obj - Optional object
883: -  name - command line option

885:    Level: intermediate
886: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
887: @*/
888: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
889: {
891:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
892:   return 0;
893: }

895: /*@C
896:     DMView - Views a DM

898:     Collective on dm

900:     Input Parameters:
901: +   dm - the DM object to view
902: -   v - the viewer

904:     Notes:
905:     Using PETSCVIEWERHDF5 type with PETSC_VIEWER_HDF5_PETSC format, one can save multiple DMPlex
906:     meshes in a single HDF5 file. This in turn requires one to name the DMPlex object with PetscObjectSetName()
907:     before saving it with DMView() and before loading it with DMLoad() for identification of the mesh object.

909:     Level: beginner

911: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMLoad(), PetscObjectSetName()

913: @*/
914: PetscErrorCode  DMView(DM dm,PetscViewer v)
915: {
916:   PetscBool         isbinary;
917:   PetscMPIInt       size;
918:   PetscViewerFormat format;

921:   if (!v) {
922:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
923:   }
925:   /* Ideally, we would like to have this test on.
926:      However, it currently breaks socket viz via GLVis.
927:      During DMView(parallel_mesh,glvis_viewer), each
928:      process opens a sequential ASCII socket to visualize
929:      the local mesh, and PetscObjectView(dm,local_socket)
930:      is internally called inside VecView_GLVis, incurring
931:      in an error here */
933:   PetscViewerCheckWritable(v);

935:   PetscViewerGetFormat(v,&format);
936:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
937:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return 0;
938:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
939:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
940:   if (isbinary) {
941:     PetscInt classid = DM_FILE_CLASSID;
942:     char     type[256];

944:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
945:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
946:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
947:   }
948:   if (dm->ops->view) {
949:     (*dm->ops->view)(dm,v);
950:   }
951:   return 0;
952: }

954: /*@
955:     DMCreateGlobalVector - Creates a global vector from a DM object

957:     Collective on dm

959:     Input Parameter:
960: .   dm - the DM object

962:     Output Parameter:
963: .   vec - the global vector

965:     Level: beginner

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

969: @*/
970: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
971: {
975:   (*dm->ops->createglobalvector)(dm,vec);
976:   if (PetscDefined(USE_DEBUG)) {
977:     DM vdm;

979:     VecGetDM(*vec,&vdm);
981:   }
982:   return 0;
983: }

985: /*@
986:     DMCreateLocalVector - Creates a local vector from a DM object

988:     Not Collective

990:     Input Parameter:
991: .   dm - the DM object

993:     Output Parameter:
994: .   vec - the local vector

996:     Level: beginner

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

1000: @*/
1001: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
1002: {
1006:   (*dm->ops->createlocalvector)(dm,vec);
1007:   if (PetscDefined(USE_DEBUG)) {
1008:     DM vdm;

1010:     VecGetDM(*vec,&vdm);
1012:   }
1013:   return 0;
1014: }

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

1019:    Collective on dm

1021:    Input Parameter:
1022: .  dm - the DM that provides the mapping

1024:    Output Parameter:
1025: .  ltog - the mapping

1027:    Level: intermediate

1029:    Notes:
1030:    This mapping can then be used by VecSetLocalToGlobalMapping() or
1031:    MatSetLocalToGlobalMapping().

1033: .seealso: DMCreateLocalVector()
1034: @*/
1035: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
1036: {
1037:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

1041:   if (!dm->ltogmap) {
1042:     PetscSection section, sectionGlobal;

1044:     DMGetLocalSection(dm, &section);
1045:     if (section) {
1046:       const PetscInt *cdofs;
1047:       PetscInt       *ltog;
1048:       PetscInt        pStart, pEnd, n, p, k, l;

1050:       DMGetGlobalSection(dm, &sectionGlobal);
1051:       PetscSectionGetChart(section, &pStart, &pEnd);
1052:       PetscSectionGetStorageSize(section, &n);
1053:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1054:       for (p = pStart, l = 0; p < pEnd; ++p) {
1055:         PetscInt bdof, cdof, dof, off, c, cind;

1057:         /* Should probably use constrained dofs */
1058:         PetscSectionGetDof(section, p, &dof);
1059:         PetscSectionGetConstraintDof(section, p, &cdof);
1060:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1061:         PetscSectionGetOffset(sectionGlobal, p, &off);
1062:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1063:         bdof = cdof && (dof-cdof) ? 1 : dof;
1064:         if (dof) {
1065:           bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1066:         }

1068:         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1069:           if (cind < cdof && c == cdofs[cind]) {
1070:             ltog[l] = off < 0 ? off-c : -(off+c+1);
1071:             cind++;
1072:           } else {
1073:             ltog[l] = (off < 0 ? -(off+1) : off) + c - cind;
1074:           }
1075:         }
1076:       }
1077:       /* Must have same blocksize on all procs (some might have no points) */
1078:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
1079:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
1080:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
1081:       else                            {bs = bsMinMax[0];}
1082:       bs = bs < 0 ? 1 : bs;
1083:       /* Must reduce indices by blocksize */
1084:       if (bs > 1) {
1085:         for (l = 0, k = 0; l < n; l += bs, ++k) {
1086:           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1087:           ltog[k] = ltog[l] >= 0 ? ltog[l]/bs : -(-(ltog[l]+1)/bs + 1);
1088:         }
1089:         n /= bs;
1090:       }
1091:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1092:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
1093:     } else {
1095:       (*dm->ops->getlocaltoglobalmapping)(dm);
1096:     }
1097:   }
1098:   *ltog = dm->ltogmap;
1099:   return 0;
1100: }

1102: /*@
1103:    DMGetBlockSize - Gets the inherent block size associated with a DM

1105:    Not Collective

1107:    Input Parameter:
1108: .  dm - the DM with block structure

1110:    Output Parameter:
1111: .  bs - the block size, 1 implies no exploitable block structure

1113:    Level: intermediate

1115: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
1116: @*/
1117: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
1118: {
1122:   *bs = dm->bs;
1123:   return 0;
1124: }

1126: /*@C
1127:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

1129:     Collective on dmc

1131:     Input Parameters:
1132: +   dmc - the DM object
1133: -   dmf - the second, finer DM object

1135:     Output Parameters:
1136: +  mat - the interpolation
1137: -  vec - the scaling (optional)

1139:     Level: developer

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

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

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

1150: @*/
1151: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
1152: {
1157:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
1158:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
1159:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
1160:   return 0;
1161: }

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

1166:   Input Parameters:
1167: +      dac - DM that defines a coarse mesh
1168: .      daf - DM that defines a fine mesh
1169: -      mat - the restriction (or interpolation operator) from fine to coarse

1171:   Output Parameter:
1172: .    scale - the scaled vector

1174:   Level: developer

1176:   Developer Notes:
1177:   If the fine-scale DMDA has the -dm_bind_below option set to true, then DMCreateInterpolationScale() calls MatSetBindingPropagates()
1178:   on the restriction/interpolation operator to set the bindingpropagates flag to true.

1180: .seealso: DMCreateInterpolation()

1182: @*/
1183: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
1184: {
1185:   Vec            fine;
1186:   PetscScalar    one = 1.0;
1187: #if defined(PETSC_HAVE_CUDA)
1188:   PetscBool      bindingpropagates,isbound;
1189: #endif

1191:   DMCreateGlobalVector(daf,&fine);
1192:   DMCreateGlobalVector(dac,scale);
1193:   VecSet(fine,one);
1194: #if defined(PETSC_HAVE_CUDA)
1195:   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1196:    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1197:    * we'll need to do it for that case, too.*/
1198:   VecGetBindingPropagates(fine,&bindingpropagates);
1199:   if (bindingpropagates) {
1200:     MatSetBindingPropagates(mat,PETSC_TRUE);
1201:     VecBoundToCPU(fine,&isbound);
1202:     MatBindToCPU(mat,isbound);
1203:   }
1204: #endif
1205:   MatRestrict(mat,fine,*scale);
1206:   VecDestroy(&fine);
1207:   VecReciprocal(*scale);
1208:   return 0;
1209: }

1211: /*@
1212:     DMCreateRestriction - Gets restriction matrix between two DM objects

1214:     Collective on dmc

1216:     Input Parameters:
1217: +   dmc - the DM object
1218: -   dmf - the second, finer DM object

1220:     Output Parameter:
1221: .  mat - the restriction

1223:     Level: developer

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

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

1231: @*/
1232: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
1233: {
1238:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
1239:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
1240:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
1241:   return 0;
1242: }

1244: /*@
1245:     DMCreateInjection - Gets injection matrix between two DM objects

1247:     Collective on dac

1249:     Input Parameters:
1250: +   dac - the DM object
1251: -   daf - the second, finer DM object

1253:     Output Parameter:
1254: .   mat - the injection

1256:     Level: developer

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

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

1264: @*/
1265: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
1266: {
1271:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
1272:   (*dac->ops->createinjection)(dac,daf,mat);
1273:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
1274:   return 0;
1275: }

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

1280:   Collective on dac

1282:   Input Parameters:
1283: + dmc - the target DM object
1284: - dmf - the source DM object

1286:   Output Parameter:
1287: . mat - the mass matrix

1289:   Level: developer

1291: .seealso DMCreateMassMatrixLumped(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1292: @*/
1293: PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1294: {
1299:   (*dmc->ops->createmassmatrix)(dmc, dmf, mat);
1300:   return 0;
1301: }

1303: /*@
1304:   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given DM

1306:   Collective on dm

1308:   Input Parameter:
1309: . dm - the DM object

1311:   Output Parameter:
1312: . lm - the lumped mass matrix

1314:   Level: developer

1316: .seealso DMCreateMassMatrix(), DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
1317: @*/
1318: PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *lm)
1319: {
1323:   (*dm->ops->createmassmatrixlumped)(dm, lm);
1324:   return 0;
1325: }

1327: /*@
1328:     DMCreateColoring - Gets coloring for a DM

1330:     Collective on dm

1332:     Input Parameters:
1333: +   dm - the DM object
1334: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

1336:     Output Parameter:
1337: .   coloring - the coloring

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

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

1345:     Level: developer

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

1349: @*/
1350: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
1351: {
1355:   (*dm->ops->getcoloring)(dm,ctype,coloring);
1356:   return 0;
1357: }

1359: /*@
1360:     DMCreateMatrix - Gets empty Jacobian for a DM

1362:     Collective on dm

1364:     Input Parameter:
1365: .   dm - the DM object

1367:     Output Parameter:
1368: .   mat - the empty Jacobian

1370:     Level: beginner

1372:     Options Database Keys:
1373: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros

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

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

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

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

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

1390: @*/
1391: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
1392: {
1396:   MatInitializePackage();
1397:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
1398:   (*dm->ops->creatematrix)(dm,mat);
1399:   if (PetscDefined(USE_DEBUG)) {
1400:     DM mdm;

1402:     MatGetDM(*mat,&mdm);
1404:   }
1405:   /* Handle nullspace and near nullspace */
1406:   if (dm->Nf) {
1407:     MatNullSpace nullSpace;
1408:     PetscInt     Nf, f;

1410:     DMGetNumFields(dm, &Nf);
1411:     for (f = 0; f < Nf; ++f) {
1412:       if (dm->nullspaceConstructors[f]) {
1413:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1414:         MatSetNullSpace(*mat, nullSpace);
1415:         MatNullSpaceDestroy(&nullSpace);
1416:         break;
1417:       }
1418:     }
1419:     for (f = 0; f < Nf; ++f) {
1420:       if (dm->nearnullspaceConstructors[f]) {
1421:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1422:         MatSetNearNullSpace(*mat, nullSpace);
1423:         MatNullSpaceDestroy(&nullSpace);
1424:       }
1425:     }
1426:   }
1427:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
1428:   return 0;
1429: }

1431: /*@
1432:   DMSetMatrixPreallocateSkip - When DMCreateMatrix() is called the matrix sizes and ISLocalToGlobalMapping will be
1433:   properly set, but the entries will not be preallocated. This is most useful to reduce initialization costs when
1434:   MatSetPreallocationCOO() and MatSetValuesCOO() will be used.

1436:   Logically Collective on dm

1438:   Input Parameters:
1439: + dm - the DM
1440: - skip - PETSC_TRUE to skip preallocation

1442:   Level: developer

1444: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1445: @*/
1446: PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1447: {
1449:   dm->prealloc_skip = skip;
1450:   return 0;
1451: }

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

1457:   Logically Collective on dm

1459:   Input Parameters:
1460: + dm - the DM
1461: - only - PETSC_TRUE if only want preallocation

1463:   Level: developer

1465:   Options Database Keys:
1466: . -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros

1468: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
1469: @*/
1470: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1471: {
1473:   dm->prealloc_only = only;
1474:   return 0;
1475: }

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

1481:   Logically Collective on dm

1483:   Input Parameters:
1484: + dm - the DM
1485: - only - PETSC_TRUE if only want matrix stucture

1487:   Level: developer
1488: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
1489: @*/
1490: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1491: {
1493:   dm->structure_only = only;
1494:   return 0;
1495: }

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

1500:   Not Collective

1502:   Input Parameters:
1503: + dm - the DM object
1504: . count - The minimum size
1505: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

1507:   Output Parameter:
1508: . array - the work array

1510:   Level: developer

1512: .seealso DMDestroy(), DMCreate()
1513: @*/
1514: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1515: {
1516:   DMWorkLink     link;
1517:   PetscMPIInt    dsize;

1521:   if (dm->workin) {
1522:     link       = dm->workin;
1523:     dm->workin = dm->workin->next;
1524:   } else {
1525:     PetscNewLog(dm,&link);
1526:   }
1527:   MPI_Type_size(dtype,&dsize);
1528:   if (((size_t)dsize*count) > link->bytes) {
1529:     PetscFree(link->mem);
1530:     PetscMalloc(dsize*count,&link->mem);
1531:     link->bytes = dsize*count;
1532:   }
1533:   link->next   = dm->workout;
1534:   dm->workout  = link;
1535: #if defined(PETSC_HAVE_VALGRIND)
1536:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
1537:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
1538: #endif
1539:   *(void**)mem = link->mem;
1540:   return 0;
1541: }

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

1546:   Not Collective

1548:   Input Parameters:
1549: + dm - the DM object
1550: . count - The minimum size
1551: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1553:   Output Parameter:
1554: . array - the work array

1556:   Level: developer

1558:   Developer Notes:
1559:     count and dtype are ignored, they are only needed for DMGetWorkArray()

1561: .seealso DMDestroy(), DMCreate()
1562: @*/
1563: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
1564: {
1565:   DMWorkLink *p,link;

1569:   for (p=&dm->workout; (link=*p); p=&link->next) {
1570:     if (link->mem == *(void**)mem) {
1571:       *p           = link->next;
1572:       link->next   = dm->workin;
1573:       dm->workin   = link;
1574:       *(void**)mem = NULL;
1575:       return 0;
1576:     }
1577:   }
1578:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1579: }

1581: /*@C
1582:   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field when function spaces are joined or split, such as in DMCreateSubDM()

1584:   Logically collective on DM

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

1591:   Calling sequence of nullsp:
1592: .vb
1593:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1594: .ve
1595: +  dm        - The present DM
1596: .  origField - The field number given above, in the original DM
1597: .  field     - The field number in dm
1598: -  nullSpace - The nullspace for the given field

1600:   This function is currently not available from Fortran.

1602:    Level: intermediate

1604: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1605: @*/
1606: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace*))
1607: {
1610:   dm->nullspaceConstructors[field] = nullsp;
1611:   return 0;
1612: }

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

1617:   Not collective

1619:   Input Parameters:
1620: + dm     - The DM
1621: - field  - The field number for the nullspace

1623:   Output Parameter:
1624: . nullsp - A callback to create the nullspace

1626:   Calling sequence of nullsp:
1627: .vb
1628:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1629: .ve
1630: +  dm        - The present DM
1631: .  origField - The field number given above, in the original DM
1632: .  field     - The field number in dm
1633: -  nullSpace - The nullspace for the given field

1635:   This function is currently not available from Fortran.

1637:    Level: intermediate

1639: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1640: @*/
1641: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1642: {
1646:   *nullsp = dm->nullspaceConstructors[field];
1647:   return 0;
1648: }

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

1653:   Logically collective on DM

1655:   Input Parameters:
1656: + dm     - The DM
1657: . field  - The field number for the nullspace
1658: - nullsp - A callback to create the near-nullspace

1660:   Calling sequence of nullsp:
1661: .vb
1662:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1663: .ve
1664: +  dm        - The present DM
1665: .  origField - The field number given above, in the original DM
1666: .  field     - The field number in dm
1667: -  nullSpace - The nullspace for the given field

1669:   This function is currently not available from Fortran.

1671:    Level: intermediate

1673: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1674: @*/
1675: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1676: {
1679:   dm->nearnullspaceConstructors[field] = nullsp;
1680:   return 0;
1681: }

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

1686:   Not collective

1688:   Input Parameters:
1689: + dm     - The DM
1690: - field  - The field number for the nullspace

1692:   Output Parameter:
1693: . nullsp - A callback to create the near-nullspace

1695:   Calling sequence of nullsp:
1696: .vb
1697:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1698: .ve
1699: +  dm        - The present DM
1700: .  origField - The field number given above, in the original DM
1701: .  field     - The field number in dm
1702: -  nullSpace - The nullspace for the given field

1704:   This function is currently not available from Fortran.

1706:    Level: intermediate

1708: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
1709: @*/
1710: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1711: {
1715:   *nullsp = dm->nearnullspaceConstructors[field];
1716:   return 0;
1717: }

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

1722:   Not collective

1724:   Input Parameter:
1725: . dm - the DM object

1727:   Output Parameters:
1728: + numFields  - The number of fields (or NULL if not requested)
1729: . fieldNames - The name for each field (or NULL if not requested)
1730: - fields     - The global indices for each field (or NULL if not requested)

1732:   Level: intermediate

1734:   Notes:
1735:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1736:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1737:   PetscFree().

1739: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1740: @*/
1741: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1742: {
1743:   PetscSection   section, sectionGlobal;

1746:   if (numFields) {
1748:     *numFields = 0;
1749:   }
1750:   if (fieldNames) {
1752:     *fieldNames = NULL;
1753:   }
1754:   if (fields) {
1756:     *fields = NULL;
1757:   }
1758:   DMGetLocalSection(dm, &section);
1759:   if (section) {
1760:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1761:     PetscInt nF, f, pStart, pEnd, p;

1763:     DMGetGlobalSection(dm, &sectionGlobal);
1764:     PetscSectionGetNumFields(section, &nF);
1765:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
1766:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1767:     for (f = 0; f < nF; ++f) {
1768:       fieldSizes[f] = 0;
1769:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1770:     }
1771:     for (p = pStart; p < pEnd; ++p) {
1772:       PetscInt gdof;

1774:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1775:       if (gdof > 0) {
1776:         for (f = 0; f < nF; ++f) {
1777:           PetscInt fdof, fcdof, fpdof;

1779:           PetscSectionGetFieldDof(section, p, f, &fdof);
1780:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1781:           fpdof = fdof-fcdof;
1782:           if (fpdof && fpdof != fieldNc[f]) {
1783:             /* Layout does not admit a pointwise block size */
1784:             fieldNc[f] = 1;
1785:           }
1786:           fieldSizes[f] += fpdof;
1787:         }
1788:       }
1789:     }
1790:     for (f = 0; f < nF; ++f) {
1791:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1792:       fieldSizes[f] = 0;
1793:     }
1794:     for (p = pStart; p < pEnd; ++p) {
1795:       PetscInt gdof, goff;

1797:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1798:       if (gdof > 0) {
1799:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1800:         for (f = 0; f < nF; ++f) {
1801:           PetscInt fdof, fcdof, fc;

1803:           PetscSectionGetFieldDof(section, p, f, &fdof);
1804:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1805:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1806:             fieldIndices[f][fieldSizes[f]] = goff++;
1807:           }
1808:         }
1809:       }
1810:     }
1811:     if (numFields) *numFields = nF;
1812:     if (fieldNames) {
1813:       PetscMalloc1(nF, fieldNames);
1814:       for (f = 0; f < nF; ++f) {
1815:         const char *fieldName;

1817:         PetscSectionGetFieldName(section, f, &fieldName);
1818:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
1819:       }
1820:     }
1821:     if (fields) {
1822:       PetscMalloc1(nF, fields);
1823:       for (f = 0; f < nF; ++f) {
1824:         PetscInt bs, in[2], out[2];

1826:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1827:         in[0] = -fieldNc[f];
1828:         in[1] = fieldNc[f];
1829:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1830:         bs    = (-out[0] == out[1]) ? out[1] : 1;
1831:         ISSetBlockSize((*fields)[f], bs);
1832:       }
1833:     }
1834:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
1835:   } else if (dm->ops->createfieldis) {
1836:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
1837:   }
1838:   return 0;
1839: }

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

1847:   Not collective

1849:   Input Parameter:
1850: . dm - the DM object

1852:   Output Parameters:
1853: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1854: . namelist  - The name for each field (or NULL if not requested)
1855: . islist    - The global indices for each field (or NULL if not requested)
1856: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

1858:   Level: intermediate

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

1865: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1866: @*/
1867: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1868: {
1870:   if (len) {
1872:     *len = 0;
1873:   }
1874:   if (namelist) {
1876:     *namelist = NULL;
1877:   }
1878:   if (islist) {
1880:     *islist = NULL;
1881:   }
1882:   if (dmlist) {
1884:     *dmlist = NULL;
1885:   }
1886:   /*
1887:    Is it a good idea to apply the following check across all impls?
1888:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1889:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1890:    */
1892:   if (!dm->ops->createfielddecomposition) {
1893:     PetscSection section;
1894:     PetscInt     numFields, f;

1896:     DMGetLocalSection(dm, &section);
1897:     if (section) PetscSectionGetNumFields(section, &numFields);
1898:     if (section && numFields && dm->ops->createsubdm) {
1899:       if (len) *len = numFields;
1900:       if (namelist) PetscMalloc1(numFields,namelist);
1901:       if (islist)   PetscMalloc1(numFields,islist);
1902:       if (dmlist)   PetscMalloc1(numFields,dmlist);
1903:       for (f = 0; f < numFields; ++f) {
1904:         const char *fieldName;

1906:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1907:         if (namelist) {
1908:           PetscSectionGetFieldName(section, f, &fieldName);
1909:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
1910:         }
1911:       }
1912:     } else {
1913:       DMCreateFieldIS(dm, len, namelist, islist);
1914:       /* By default there are no DMs associated with subproblems. */
1915:       if (dmlist) *dmlist = NULL;
1916:     }
1917:   } else {
1918:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
1919:   }
1920:   return 0;
1921: }

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

1927:   Not collective

1929:   Input Parameters:
1930: + dm        - The DM object
1931: . numFields - The number of fields in this subproblem
1932: - fields    - The field numbers of the selected fields

1934:   Output Parameters:
1935: + is - The global indices for the subproblem
1936: - subdm - The DM for the subproblem

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

1940:   Level: intermediate

1942: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1943: @*/
1944: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
1945: {
1951:   (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
1952:   return 0;
1953: }

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

1958:   Not collective

1960:   Input Parameters:
1961: + dms - The DM objects
1962: - len - The number of DMs

1964:   Output Parameters:
1965: + is - The global indices for the subproblem, or NULL
1966: - superdm - The DM for the superproblem

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

1970:   Level: intermediate

1972: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1973: @*/
1974: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
1975: {
1976:   PetscInt       i;

1983:   if (len) {
1984:     DM dm = dms[0];
1986:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
1987:   }
1988:   return 0;
1989: }

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

1998:   Not collective

2000:   Input Parameter:
2001: . dm - the DM object

2003:   Output Parameters:
2004: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
2005: . namelist    - The name for each subdomain (or NULL if not requested)
2006: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2007: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2008: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

2010:   Level: intermediate

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

2017: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
2018: @*/
2019: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2020: {
2021:   DMSubDomainHookLink link;
2022:   PetscInt            i,l;

2030:   /*
2031:    Is it a good idea to apply the following check across all impls?
2032:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2033:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2034:    */
2036:   if (dm->ops->createdomaindecomposition) {
2037:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
2038:     /* copy subdomain hooks and context over to the subdomain DMs */
2039:     if (dmlist && *dmlist) {
2040:       for (i = 0; i < l; i++) {
2041:         for (link=dm->subdomainhook; link; link=link->next) {
2042:           if (link->ddhook) (*link->ddhook)(dm,(*dmlist)[i],link->ctx);
2043:         }
2044:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2045:       }
2046:     }
2047:     if (len) *len = l;
2048:   }
2049:   return 0;
2050: }

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

2055:   Not collective

2057:   Input Parameters:
2058: + dm - the DM object
2059: . n  - the number of subdomain scatters
2060: - subdms - the local subdomains

2062:   Output Parameters:
2063: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2064: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2065: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

2073:   Level: developer

2075: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
2076: @*/
2077: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
2078: {
2082:   (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);
2083:   return 0;
2084: }

2086: /*@
2087:   DMRefine - Refines a DM object

2089:   Collective on dm

2091:   Input Parameters:
2092: + dm   - the DM object
2093: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

2095:   Output Parameter:
2096: . dmf - the refined DM, or NULL

2098:   Options Database Keys:
2099: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex

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

2103:   Level: developer

2105: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2106: @*/
2107: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
2108: {
2109:   DMRefineHookLink link;

2113:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
2114:   (*dm->ops->refine)(dm,comm,dmf);
2115:   if (*dmf) {
2116:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2120:     (*dmf)->ctx       = dm->ctx;
2121:     (*dmf)->leveldown = dm->leveldown;
2122:     (*dmf)->levelup   = dm->levelup + 1;

2124:     DMSetMatType(*dmf,dm->mattype);
2125:     for (link=dm->refinehook; link; link=link->next) {
2126:       if (link->refinehook) {
2127:         (*link->refinehook)(dm,*dmf,link->ctx);
2128:       }
2129:     }
2130:   }
2131:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
2132:   return 0;
2133: }

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

2138:    Logically Collective

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

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

2149: +  coarse - coarse level DM
2150: .  fine - fine level DM to interpolate problem to
2151: -  ctx - optional user-defined function context

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

2156: +  coarse - coarse level DM
2157: .  interp - matrix interpolating a coarse-level solution to the finer grid
2158: .  fine - fine level DM to update
2159: -  ctx - optional user-defined function context

2161:    Level: advanced

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

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

2168:    This function is currently not available from Fortran.

2170: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2171: @*/
2172: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2173: {
2174:   DMRefineHookLink link,*p;

2177:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
2178:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return 0;
2179:   }
2180:   PetscNew(&link);
2181:   link->refinehook = refinehook;
2182:   link->interphook = interphook;
2183:   link->ctx        = ctx;
2184:   link->next       = NULL;
2185:   *p               = link;
2186:   return 0;
2187: }

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

2192:    Logically Collective

2194:    Input Parameters:
2195: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
2196: .  refinehook - function to run when setting up a coarser level
2197: .  interphook - function to run to update data on finer levels (once per SNESSolve())
2198: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2200:    Level: advanced

2202:    Notes:
2203:    This function does nothing if the hook is not in the list.

2205:    This function is currently not available from Fortran.

2207: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2208: @*/
2209: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
2210: {
2211:   DMRefineHookLink link,*p;

2214:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
2215:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2216:       link = *p;
2217:       *p = link->next;
2218:       PetscFree(link);
2219:       break;
2220:     }
2221:   }
2222:   return 0;
2223: }

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

2228:    Collective if any hooks are

2230:    Input Parameters:
2231: +  coarse - coarser DM to use as a base
2232: .  interp - interpolation matrix, apply using MatInterpolate()
2233: -  fine - finer DM to update

2235:    Level: developer

2237: .seealso: DMRefineHookAdd(), MatInterpolate()
2238: @*/
2239: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
2240: {
2241:   DMRefineHookLink link;

2243:   for (link=fine->refinehook; link; link=link->next) {
2244:     if (link->interphook) {
2245:       (*link->interphook)(coarse,interp,fine,link->ctx);
2246:     }
2247:   }
2248:   return 0;
2249: }

2251: /*@
2252:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2254:    Collective on DM

2256:    Input Parameters:
2257: +  coarse - coarse DM
2258: .  fine   - fine DM
2259: .  interp - (optional) the matrix computed by DMCreateInterpolation().  Implementations may not need this, but if it
2260:             is available it can avoid some recomputation.  If it is provided, MatInterpolate() will be used if
2261:             the coarse DM does not have a specialized implementation.
2262: -  coarseSol - solution on the coarse mesh

2264:    Output Parameter:
2265: .  fineSol - the interpolation of coarseSol to the fine mesh

2267:    Level: developer

2269:    Note: This function exists because the interpolation of a solution vector between meshes is not always a linear
2270:    map.  For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2271:    out of the solution vector.  Or if interpolation is inherently a nonlinear operation, such as a method using
2272:    slope-limiting reconstruction.

2274: .seealso DMInterpolate(), DMCreateInterpolation()
2275: @*/
2276: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2277: {
2278:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;


2285:   PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
2286:   if (interpsol) {
2287:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2288:   } else if (interp) {
2289:     MatInterpolate(interp, coarseSol, fineSol);
2290:   } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2291:   return 0;
2292: }

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

2297:     Not Collective

2299:     Input Parameter:
2300: .   dm - the DM object

2302:     Output Parameter:
2303: .   level - number of refinements

2305:     Level: developer

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

2309: @*/
2310: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
2311: {
2313:   *level = dm->levelup;
2314:   return 0;
2315: }

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

2320:     Not Collective

2322:     Input Parameters:
2323: +   dm - the DM object
2324: -   level - number of refinements

2326:     Level: advanced

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

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

2333: @*/
2334: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
2335: {
2337:   dm->levelup = level;
2338:   return 0;
2339: }

2341: /*@
2342:   DMExtrude - Extrude a DM object from a surface

2344:   Collective on dm

2346:   Input Parameters:
2347: + dm     - the DM object
2348: - layers - the number of extruded cell layers

2350:   Output Parameter:
2351: . dme - the extruded DM, or NULL

2353:   Note: If no extrusion was done, the return value is NULL

2355:   Level: developer

2357: .seealso DMRefine(), DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector()
2358: @*/
2359: PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2360: {
2363:   (*dm->ops->extrude)(dm, layers, dme);
2364:   if (*dme) {
2365:     (*dme)->ops->creatematrix = dm->ops->creatematrix;
2366:     PetscObjectCopyFortranFunctionPointers((PetscObject) dm, (PetscObject) *dme);
2367:     (*dme)->ctx = dm->ctx;
2368:     DMSetMatType(*dme, dm->mattype);
2369:   }
2370:   return 0;
2371: }

2373: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2374: {
2377:   *tdm = dm->transformDM;
2378:   return 0;
2379: }

2381: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2382: {
2385:   *tv = dm->transform;
2386:   return 0;
2387: }

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

2392:   Input Parameter:
2393: . dm - The DM

2395:   Output Parameter:
2396: . flg - PETSC_TRUE if a basis transformation should be done

2398:   Level: developer

2400: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
2401: @*/
2402: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2403: {
2404:   Vec            tv;

2408:   DMGetBasisTransformVec_Internal(dm, &tv);
2409:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2410:   return 0;
2411: }

2413: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2414: {
2415:   PetscSection   s, ts;
2416:   PetscScalar   *ta;
2417:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2419:   DMGetCoordinateDim(dm, &cdim);
2420:   DMGetLocalSection(dm, &s);
2421:   PetscSectionGetChart(s, &pStart, &pEnd);
2422:   PetscSectionGetNumFields(s, &Nf);
2423:   DMClone(dm, &dm->transformDM);
2424:   DMGetLocalSection(dm->transformDM, &ts);
2425:   PetscSectionSetNumFields(ts, Nf);
2426:   PetscSectionSetChart(ts, pStart, pEnd);
2427:   for (f = 0; f < Nf; ++f) {
2428:     PetscSectionGetFieldComponents(s, f, &Nc);
2429:     /* We could start to label fields by their transformation properties */
2430:     if (Nc != cdim) continue;
2431:     for (p = pStart; p < pEnd; ++p) {
2432:       PetscSectionGetFieldDof(s, p, f, &dof);
2433:       if (!dof) continue;
2434:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2435:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2436:     }
2437:   }
2438:   PetscSectionSetUp(ts);
2439:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2440:   VecGetArray(dm->transform, &ta);
2441:   for (p = pStart; p < pEnd; ++p) {
2442:     for (f = 0; f < Nf; ++f) {
2443:       PetscSectionGetFieldDof(ts, p, f, &dof);
2444:       if (dof) {
2445:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2446:         PetscScalar       *tva;
2447:         const PetscScalar *A;

2449:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2450:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2451:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
2452:         PetscArraycpy(tva, A, PetscSqr(cdim));
2453:       }
2454:     }
2455:   }
2456:   VecRestoreArray(dm->transform, &ta);
2457:   return 0;
2458: }

2460: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2461: {
2464:   newdm->transformCtx       = dm->transformCtx;
2465:   newdm->transformSetUp     = dm->transformSetUp;
2466:   newdm->transformDestroy   = NULL;
2467:   newdm->transformGetMatrix = dm->transformGetMatrix;
2468:   if (newdm->transformSetUp) DMConstructBasisTransform_Internal(newdm);
2469:   return 0;
2470: }

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

2475:    Logically Collective

2477:    Input Parameters:
2478: +  dm - the DM
2479: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
2480: .  endhook - function to run after DMGlobalToLocalEnd() has completed
2481: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2486: +  dm - global DM
2487: .  g - global vector
2488: .  mode - mode
2489: .  l - local vector
2490: -  ctx - optional user-defined function context

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

2495: +  global - global DM
2496: -  ctx - optional user-defined function context

2498:    Level: advanced

2500: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2501: @*/
2502: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2503: {
2504:   DMGlobalToLocalHookLink link,*p;

2507:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2508:   PetscNew(&link);
2509:   link->beginhook = beginhook;
2510:   link->endhook   = endhook;
2511:   link->ctx       = ctx;
2512:   link->next      = NULL;
2513:   *p              = link;
2514:   return 0;
2515: }

2517: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2518: {
2519:   Mat cMat;
2520:   Vec cVec, cBias;
2521:   PetscSection section, cSec;
2522:   PetscInt pStart, pEnd, p, dof;

2525:   DMGetDefaultConstraints(dm,&cSec,&cMat,&cBias);
2526:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2527:     PetscInt nRows;

2529:     MatGetSize(cMat,&nRows,NULL);
2530:     if (nRows <= 0) return 0;
2531:     DMGetLocalSection(dm,&section);
2532:     MatCreateVecs(cMat,NULL,&cVec);
2533:     MatMult(cMat,l,cVec);
2534:     if (cBias) VecAXPY(cVec,1.,cBias);
2535:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2536:     for (p = pStart; p < pEnd; p++) {
2537:       PetscSectionGetDof(cSec,p,&dof);
2538:       if (dof) {
2539:         PetscScalar *vals;
2540:         VecGetValuesSection(cVec,cSec,p,&vals);
2541:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
2542:       }
2543:     }
2544:     VecDestroy(&cVec);
2545:   }
2546:   return 0;
2547: }

2549: /*@
2550:     DMGlobalToLocal - update local vectors from global vector

2552:     Neighbor-wise Collective on dm

2554:     Input Parameters:
2555: +   dm - the DM object
2556: .   g - the global vector
2557: .   mode - INSERT_VALUES or ADD_VALUES
2558: -   l - the local vector

2560:     Notes:
2561:     The communication involved in this update can be overlapped with computation by using
2562:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

2564:     Level: beginner

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

2568: @*/
2569: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
2570: {
2571:   DMGlobalToLocalBegin(dm,g,mode,l);
2572:   DMGlobalToLocalEnd(dm,g,mode,l);
2573:   return 0;
2574: }

2576: /*@
2577:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2579:     Neighbor-wise Collective on dm

2581:     Input Parameters:
2582: +   dm - the DM object
2583: .   g - the global vector
2584: .   mode - INSERT_VALUES or ADD_VALUES
2585: -   l - the local vector

2587:     Level: intermediate

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

2591: @*/
2592: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
2593: {
2594:   PetscSF                 sf;
2595:   DMGlobalToLocalHookLink link;

2598:   for (link=dm->gtolhook; link; link=link->next) {
2599:     if (link->beginhook) {
2600:       (*link->beginhook)(dm,g,mode,l,link->ctx);
2601:     }
2602:   }
2603:   DMGetSectionSF(dm, &sf);
2604:   if (sf) {
2605:     const PetscScalar *gArray;
2606:     PetscScalar       *lArray;
2607:     PetscMemType      lmtype,gmtype;

2610:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2611:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2612:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2613:     VecRestoreArrayAndMemType(l, &lArray);
2614:     VecRestoreArrayReadAndMemType(g, &gArray);
2615:   } else {
2617:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2618:   }
2619:   return 0;
2620: }

2622: /*@
2623:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2625:     Neighbor-wise Collective on dm

2627:     Input Parameters:
2628: +   dm - the DM object
2629: .   g - the global vector
2630: .   mode - INSERT_VALUES or ADD_VALUES
2631: -   l - the local vector

2633:     Level: intermediate

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

2637: @*/
2638: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
2639: {
2640:   PetscSF                 sf;
2641:   const PetscScalar      *gArray;
2642:   PetscScalar            *lArray;
2643:   PetscBool               transform;
2644:   DMGlobalToLocalHookLink link;
2645:   PetscMemType            lmtype,gmtype;

2648:   DMGetSectionSF(dm, &sf);
2649:   DMHasBasisTransform(dm, &transform);
2650:   if (sf) {

2653:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2654:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2655:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
2656:     VecRestoreArrayAndMemType(l, &lArray);
2657:     VecRestoreArrayReadAndMemType(g, &gArray);
2658:     if (transform) DMPlexGlobalToLocalBasis(dm, l);
2659:   } else {
2661:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
2662:   }
2663:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
2664:   for (link=dm->gtolhook; link; link=link->next) {
2665:     if (link->endhook) (*link->endhook)(dm,g,mode,l,link->ctx);
2666:   }
2667:   return 0;
2668: }

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

2673:    Logically Collective

2675:    Input Parameters:
2676: +  dm - the DM
2677: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
2678: .  endhook - function to run after DMLocalToGlobalEnd() has completed
2679: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2684: +  dm - global DM
2685: .  l - local vector
2686: .  mode - mode
2687: .  g - global vector
2688: -  ctx - optional user-defined function context

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

2693: +  global - global DM
2694: .  l - local vector
2695: .  mode - mode
2696: .  g - global vector
2697: -  ctx - optional user-defined function context

2699:    Level: advanced

2701: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2702: @*/
2703: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
2704: {
2705:   DMLocalToGlobalHookLink link,*p;

2708:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2709:   PetscNew(&link);
2710:   link->beginhook = beginhook;
2711:   link->endhook   = endhook;
2712:   link->ctx       = ctx;
2713:   link->next      = NULL;
2714:   *p              = link;
2715:   return 0;
2716: }

2718: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2719: {
2720:   Mat cMat;
2721:   Vec cVec;
2722:   PetscSection section, cSec;
2723:   PetscInt pStart, pEnd, p, dof;

2726:   DMGetDefaultConstraints(dm,&cSec,&cMat,NULL);
2727:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2728:     PetscInt nRows;

2730:     MatGetSize(cMat,&nRows,NULL);
2731:     if (nRows <= 0) return 0;
2732:     DMGetLocalSection(dm,&section);
2733:     MatCreateVecs(cMat,NULL,&cVec);
2734:     PetscSectionGetChart(cSec,&pStart,&pEnd);
2735:     for (p = pStart; p < pEnd; p++) {
2736:       PetscSectionGetDof(cSec,p,&dof);
2737:       if (dof) {
2738:         PetscInt d;
2739:         PetscScalar *vals;
2740:         VecGetValuesSection(l,section,p,&vals);
2741:         VecSetValuesSection(cVec,cSec,p,vals,mode);
2742:         /* for this to be the true transpose, we have to zero the values that
2743:          * we just extracted */
2744:         for (d = 0; d < dof; d++) {
2745:           vals[d] = 0.;
2746:         }
2747:       }
2748:     }
2749:     MatMultTransposeAdd(cMat,cVec,l,l);
2750:     VecDestroy(&cVec);
2751:   }
2752:   return 0;
2753: }
2754: /*@
2755:     DMLocalToGlobal - updates global vectors from local vectors

2757:     Neighbor-wise Collective on dm

2759:     Input Parameters:
2760: +   dm - the DM object
2761: .   l - the local vector
2762: .   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.
2763: -   g - the global vector

2765:     Notes:
2766:     The communication involved in this update can be overlapped with computation by using
2767:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

2772:     Level: beginner

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

2776: @*/
2777: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
2778: {
2779:   DMLocalToGlobalBegin(dm,l,mode,g);
2780:   DMLocalToGlobalEnd(dm,l,mode,g);
2781:   return 0;
2782: }

2784: /*@
2785:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2787:     Neighbor-wise Collective on dm

2789:     Input Parameters:
2790: +   dm - the DM object
2791: .   l - the local vector
2792: .   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.
2793: -   g - the global vector

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

2799:     Level: intermediate

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

2803: @*/
2804: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
2805: {
2806:   PetscSF                 sf;
2807:   PetscSection            s, gs;
2808:   DMLocalToGlobalHookLink link;
2809:   Vec                     tmpl;
2810:   const PetscScalar      *lArray;
2811:   PetscScalar            *gArray;
2812:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2813:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

2816:   for (link=dm->ltoghook; link; link=link->next) {
2817:     if (link->beginhook) {
2818:       (*link->beginhook)(dm,l,mode,g,link->ctx);
2819:     }
2820:   }
2821:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
2822:   DMGetSectionSF(dm, &sf);
2823:   DMGetLocalSection(dm, &s);
2824:   switch (mode) {
2825:   case INSERT_VALUES:
2826:   case INSERT_ALL_VALUES:
2827:   case INSERT_BC_VALUES:
2828:     isInsert = PETSC_TRUE; break;
2829:   case ADD_VALUES:
2830:   case ADD_ALL_VALUES:
2831:   case ADD_BC_VALUES:
2832:     isInsert = PETSC_FALSE; break;
2833:   default:
2834:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2835:   }
2836:   if ((sf && !isInsert) || (s && isInsert)) {
2837:     DMHasBasisTransform(dm, &transform);
2838:     if (transform) {
2839:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2840:       VecCopy(l, tmpl);
2841:       DMPlexLocalToGlobalBasis(dm, tmpl);
2842:       VecGetArrayRead(tmpl, &lArray);
2843:     } else if (isInsert) {
2844:       VecGetArrayRead(l, &lArray);
2845:     } else {
2846:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2847:       l_inplace = PETSC_TRUE;
2848:     }
2849:     if (s && isInsert) {
2850:       VecGetArray(g, &gArray);
2851:     } else {
2852:       VecGetArrayAndMemType(g, &gArray, &gmtype);
2853:       g_inplace = PETSC_TRUE;
2854:     }
2855:     if (sf && !isInsert) {
2856:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2857:     } else if (s && isInsert) {
2858:       PetscInt gStart, pStart, pEnd, p;

2860:       DMGetGlobalSection(dm, &gs);
2861:       PetscSectionGetChart(s, &pStart, &pEnd);
2862:       VecGetOwnershipRange(g, &gStart, NULL);
2863:       for (p = pStart; p < pEnd; ++p) {
2864:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2866:         PetscSectionGetDof(s, p, &dof);
2867:         PetscSectionGetDof(gs, p, &gdof);
2868:         PetscSectionGetConstraintDof(s, p, &cdof);
2869:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2870:         PetscSectionGetOffset(s, p, &off);
2871:         PetscSectionGetOffset(gs, p, &goff);
2872:         /* Ignore off-process data and points with no global data */
2873:         if (!gdof || goff < 0) continue;
2875:         /* If no constraints are enforced in the global vector */
2876:         if (!gcdof) {
2877:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
2878:           /* If constraints are enforced in the global vector */
2879:         } else if (cdof == gcdof) {
2880:           const PetscInt *cdofs;
2881:           PetscInt        cind = 0;

2883:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2884:           for (d = 0, e = 0; d < dof; ++d) {
2885:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
2886:             gArray[goff-gStart+e++] = lArray[off+d];
2887:           }
2888:         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
2889:       }
2890:     }
2891:     if (g_inplace) {
2892:       VecRestoreArrayAndMemType(g, &gArray);
2893:     } else {
2894:       VecRestoreArray(g, &gArray);
2895:     }
2896:     if (transform) {
2897:       VecRestoreArrayRead(tmpl, &lArray);
2898:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2899:     } else if (l_inplace) {
2900:       VecRestoreArrayReadAndMemType(l, &lArray);
2901:     } else {
2902:       VecRestoreArrayRead(l, &lArray);
2903:     }
2904:   } else {
2906:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2907:   }
2908:   return 0;
2909: }

2911: /*@
2912:     DMLocalToGlobalEnd - updates global vectors from local vectors

2914:     Neighbor-wise Collective on dm

2916:     Input Parameters:
2917: +   dm - the DM object
2918: .   l - the local vector
2919: .   mode - INSERT_VALUES or ADD_VALUES
2920: -   g - the global vector

2922:     Level: intermediate

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

2926: @*/
2927: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
2928: {
2929:   PetscSF                 sf;
2930:   PetscSection            s;
2931:   DMLocalToGlobalHookLink link;
2932:   PetscBool               isInsert, transform;

2935:   DMGetSectionSF(dm, &sf);
2936:   DMGetLocalSection(dm, &s);
2937:   switch (mode) {
2938:   case INSERT_VALUES:
2939:   case INSERT_ALL_VALUES:
2940:     isInsert = PETSC_TRUE; break;
2941:   case ADD_VALUES:
2942:   case ADD_ALL_VALUES:
2943:     isInsert = PETSC_FALSE; break;
2944:   default:
2945:     SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
2946:   }
2947:   if (sf && !isInsert) {
2948:     const PetscScalar *lArray;
2949:     PetscScalar       *gArray;
2950:     Vec                tmpl;

2952:     DMHasBasisTransform(dm, &transform);
2953:     if (transform) {
2954:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2955:       VecGetArrayRead(tmpl, &lArray);
2956:     } else {
2957:       VecGetArrayReadAndMemType(l, &lArray, NULL);
2958:     }
2959:     VecGetArrayAndMemType(g, &gArray, NULL);
2960:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
2961:     if (transform) {
2962:       VecRestoreArrayRead(tmpl, &lArray);
2963:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2964:     } else {
2965:       VecRestoreArrayReadAndMemType(l, &lArray);
2966:     }
2967:     VecRestoreArrayAndMemType(g, &gArray);
2968:   } else if (s && isInsert) {
2969:   } else {
2971:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
2972:   }
2973:   for (link=dm->ltoghook; link; link=link->next) {
2974:     if (link->endhook) (*link->endhook)(dm,g,mode,l,link->ctx);
2975:   }
2976:   return 0;
2977: }

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

2984:    Neighbor-wise Collective on dm

2986:    Input Parameters:
2987: +  dm - the DM object
2988: .  g - the original local vector
2989: -  mode - one of INSERT_VALUES or ADD_VALUES

2991:    Output Parameter:
2992: .  l  - the local vector with correct ghost values

2994:    Level: intermediate

2996:    Notes:
2997:    The local vectors used here need not be the same as those
2998:    obtained from DMCreateLocalVector(), BUT they
2999:    must have the same parallel data layout; they could, for example, be
3000:    obtained with VecDuplicate() from the DM originating vectors.

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

3004: @*/
3005: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
3006: {
3009:   (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3010:   return 0;
3011: }

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

3018:    Neighbor-wise Collective on dm

3020:    Input Parameters:
3021: +  da - the DM object
3022: .  g - the original local vector
3023: -  mode - one of INSERT_VALUES or ADD_VALUES

3025:    Output Parameter:
3026: .  l  - the local vector with correct ghost values

3028:    Level: intermediate

3030:    Notes:
3031:    The local vectors used here need not be the same as those
3032:    obtained from DMCreateLocalVector(), BUT they
3033:    must have the same parallel data layout; they could, for example, be
3034:    obtained with VecDuplicate() from the DM originating vectors.

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

3038: @*/
3039: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
3040: {
3043:   (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
3044:   return 0;
3045: }

3047: /*@
3048:     DMCoarsen - Coarsens a DM object

3050:     Collective on dm

3052:     Input Parameters:
3053: +   dm - the DM object
3054: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

3056:     Output Parameter:
3057: .   dmc - the coarsened DM

3059:     Level: developer

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

3063: @*/
3064: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3065: {
3066:   DMCoarsenHookLink link;

3070:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
3071:   (*dm->ops->coarsen)(dm, comm, dmc);
3072:   if (*dmc) {
3073:     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3074:     DMSetCoarseDM(dm,*dmc);
3075:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3076:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
3077:     (*dmc)->ctx               = dm->ctx;
3078:     (*dmc)->levelup           = dm->levelup;
3079:     (*dmc)->leveldown         = dm->leveldown + 1;
3080:     DMSetMatType(*dmc,dm->mattype);
3081:     for (link=dm->coarsenhook; link; link=link->next) {
3082:       if (link->coarsenhook) (*link->coarsenhook)(dm,*dmc,link->ctx);
3083:     }
3084:   }
3085:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
3087:   return 0;
3088: }

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

3093:    Logically Collective

3095:    Input Parameters:
3096: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3097: .  coarsenhook - function to run when setting up a coarser level
3098: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3099: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

3104: +  fine - fine level DM
3105: .  coarse - coarse level DM to restrict problem to
3106: -  ctx - optional user-defined function context

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

3111: +  fine - fine level DM
3112: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
3113: .  rscale - scaling vector for restriction
3114: .  inject - matrix restricting by injection
3115: .  coarse - coarse level DM to update
3116: -  ctx - optional user-defined function context

3118:    Level: advanced

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

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

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

3128:    This function is currently not available from Fortran.

3130: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3131: @*/
3132: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3133: {
3134:   DMCoarsenHookLink link,*p;

3137:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3138:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3139:   }
3140:   PetscNew(&link);
3141:   link->coarsenhook  = coarsenhook;
3142:   link->restricthook = restricthook;
3143:   link->ctx          = ctx;
3144:   link->next         = NULL;
3145:   *p                 = link;
3146:   return 0;
3147: }

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

3152:    Logically Collective

3154:    Input Parameters:
3155: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
3156: .  coarsenhook - function to run when setting up a coarser level
3157: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
3158: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3160:    Level: advanced

3162:    Notes:
3163:    This function does nothing if the hook is not in the list.

3165:    This function is currently not available from Fortran.

3167: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3168: @*/
3169: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
3170: {
3171:   DMCoarsenHookLink link,*p;

3174:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3175:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3176:       link = *p;
3177:       *p = link->next;
3178:       PetscFree(link);
3179:       break;
3180:     }
3181:   }
3182:   return 0;
3183: }

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

3188:    Collective if any hooks are

3190:    Input Parameters:
3191: +  fine - finer DM to use as a base
3192: .  restrct - restriction matrix, apply using MatRestrict()
3193: .  rscale - scaling vector for restriction
3194: .  inject - injection matrix, also use MatRestrict()
3195: -  coarse - coarser DM to update

3197:    Level: developer

3199: .seealso: DMCoarsenHookAdd(), MatRestrict()
3200: @*/
3201: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
3202: {
3203:   DMCoarsenHookLink link;

3205:   for (link=fine->coarsenhook; link; link=link->next) {
3206:     if (link->restricthook) {
3207:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
3208:     }
3209:   }
3210:   return 0;
3211: }

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

3216:    Logically Collective on global

3218:    Input Parameters:
3219: +  global - global DM
3220: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3221: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3222: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3224:    Calling sequence for ddhook:
3225: $    ddhook(DM global,DM block,void *ctx)

3227: +  global - global DM
3228: .  block  - block DM
3229: -  ctx - optional user-defined function context

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

3234: +  global - global DM
3235: .  out    - scatter to the outer (with ghost and overlap points) block vector
3236: .  in     - scatter to block vector values only owned locally
3237: .  block  - block DM
3238: -  ctx - optional user-defined function context

3240:    Level: advanced

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

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

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

3250:    This function is currently not available from Fortran.

3252: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3253: @*/
3254: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3255: {
3256:   DMSubDomainHookLink link,*p;

3259:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
3260:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3261:   }
3262:   PetscNew(&link);
3263:   link->restricthook = restricthook;
3264:   link->ddhook       = ddhook;
3265:   link->ctx          = ctx;
3266:   link->next         = NULL;
3267:   *p                 = link;
3268:   return 0;
3269: }

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

3274:    Logically Collective

3276:    Input Parameters:
3277: +  global - global DM
3278: .  ddhook - function to run to pass data to the decomposition DM upon its creation
3279: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3280: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3282:    Level: advanced

3284:    Notes:

3286:    This function is currently not available from Fortran.

3288: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
3289: @*/
3290: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
3291: {
3292:   DMSubDomainHookLink link,*p;

3295:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
3296:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3297:       link = *p;
3298:       *p = link->next;
3299:       PetscFree(link);
3300:       break;
3301:     }
3302:   }
3303:   return 0;
3304: }

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

3309:    Collective if any hooks are

3311:    Input Parameters:
3312: +  fine - finer DM to use as a base
3313: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3314: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3315: -  coarse - coarer DM to update

3317:    Level: developer

3319: .seealso: DMCoarsenHookAdd(), MatRestrict()
3320: @*/
3321: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
3322: {
3323:   DMSubDomainHookLink link;

3325:   for (link=global->subdomainhook; link; link=link->next) {
3326:     if (link->restricthook) {
3327:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
3328:     }
3329:   }
3330:   return 0;
3331: }

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

3336:     Not Collective

3338:     Input Parameter:
3339: .   dm - the DM object

3341:     Output Parameter:
3342: .   level - number of coarsenings

3344:     Level: developer

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

3348: @*/
3349: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
3350: {
3353:   *level = dm->leveldown;
3354:   return 0;
3355: }

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

3360:     Not Collective

3362:     Input Parameters:
3363: +   dm - the DM object
3364: -   level - number of coarsenings

3366:     Level: developer

3368: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
3369: @*/
3370: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
3371: {
3373:   dm->leveldown = level;
3374:   return 0;
3375: }

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

3380:     Collective on dm

3382:     Input Parameters:
3383: +   dm - the DM object
3384: -   nlevels - the number of levels of refinement

3386:     Output Parameter:
3387: .   dmf - the refined DM hierarchy

3389:     Level: developer

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

3393: @*/
3394: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
3395: {
3398:   if (nlevels == 0) return 0;
3400:   if (dm->ops->refinehierarchy) {
3401:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
3402:   } else if (dm->ops->refine) {
3403:     PetscInt i;

3405:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
3406:     for (i=1; i<nlevels; i++) {
3407:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
3408:     }
3409:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
3410:   return 0;
3411: }

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

3416:     Collective on dm

3418:     Input Parameters:
3419: +   dm - the DM object
3420: -   nlevels - the number of levels of coarsening

3422:     Output Parameter:
3423: .   dmc - the coarsened DM hierarchy

3425:     Level: developer

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

3429: @*/
3430: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3431: {
3434:   if (nlevels == 0) return 0;
3436:   if (dm->ops->coarsenhierarchy) {
3437:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
3438:   } else if (dm->ops->coarsen) {
3439:     PetscInt i;

3441:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
3442:     for (i=1; i<nlevels; i++) {
3443:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
3444:     }
3445:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
3446:   return 0;
3447: }

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

3452:     Not Collective

3454:     Input Parameters:
3455: +   dm - the DM object
3456: -   destroy - the destroy function

3458:     Level: intermediate

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

3462: @*/
3463: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
3464: {
3466:   dm->ctxdestroy = destroy;
3467:   return 0;
3468: }

3470: /*@
3471:     DMSetApplicationContext - Set a user context into a DM object

3473:     Not Collective

3475:     Input Parameters:
3476: +   dm - the DM object
3477: -   ctx - the user context

3479:     Level: intermediate

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

3483: @*/
3484: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
3485: {
3487:   dm->ctx = ctx;
3488:   return 0;
3489: }

3491: /*@
3492:     DMGetApplicationContext - Gets a user context from a DM object

3494:     Not Collective

3496:     Input Parameter:
3497: .   dm - the DM object

3499:     Output Parameter:
3500: .   ctx - the user context

3502:     Level: intermediate

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

3506: @*/
3507: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
3508: {
3510:   *(void**)ctx = dm->ctx;
3511:   return 0;
3512: }

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

3517:     Logically Collective on dm

3519:     Input Parameters:
3520: +   dm - the DM object
3521: -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)

3523:     Level: intermediate

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

3528: @*/
3529: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
3530: {
3532:   dm->ops->computevariablebounds = f;
3533:   return 0;
3534: }

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

3539:     Not Collective

3541:     Input Parameter:
3542: .   dm - the DM object to destroy

3544:     Output Parameter:
3545: .   flg - PETSC_TRUE if the variable bounds function exists

3547:     Level: developer

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

3551: @*/
3552: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
3553: {
3556:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3557:   return 0;
3558: }

3560: /*@C
3561:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

3563:     Logically Collective on dm

3565:     Input Parameter:
3566: .   dm - the DM object

3568:     Output parameters:
3569: +   xl - lower bound
3570: -   xu - upper bound

3572:     Level: advanced

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

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

3579: @*/
3580: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3581: {
3586:   (*dm->ops->computevariablebounds)(dm, xl,xu);
3587:   return 0;
3588: }

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

3593:     Not Collective

3595:     Input Parameter:
3596: .   dm - the DM object

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

3601:     Level: developer

3603: .seealso DMCreateColoring()

3605: @*/
3606: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
3607: {
3610:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3611:   return 0;
3612: }

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

3617:     Not Collective

3619:     Input Parameter:
3620: .   dm - the DM object

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

3625:     Level: developer

3627: .seealso DMCreateRestriction()

3629: @*/
3630: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
3631: {
3634:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3635:   return 0;
3636: }

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

3641:     Not Collective

3643:     Input Parameter:
3644: .   dm - the DM object

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

3649:     Level: developer

3651: .seealso DMCreateInjection()

3653: @*/
3654: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
3655: {
3658:   if (dm->ops->hascreateinjection) {
3659:     (*dm->ops->hascreateinjection)(dm,flg);
3660:   } else {
3661:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3662:   }
3663:   return 0;
3664: }

3666: PetscFunctionList DMList              = NULL;
3667: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3669: /*@C
3670:   DMSetType - Builds a DM, for a particular DM implementation.

3672:   Collective on dm

3674:   Input Parameters:
3675: + dm     - The DM object
3676: - method - The name of the DM type

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

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

3684:   Level: intermediate

3686: .seealso: DMGetType(), DMCreate()
3687: @*/
3688: PetscErrorCode  DMSetType(DM dm, DMType method)
3689: {
3690:   PetscErrorCode (*r)(DM);
3691:   PetscBool      match;

3694:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
3695:   if (match) return 0;

3697:   DMRegisterAll();
3698:   PetscFunctionListFind(DMList,method,&r);

3701:   if (dm->ops->destroy) {
3702:     (*dm->ops->destroy)(dm);
3703:   }
3704:   PetscMemzero(dm->ops,sizeof(*dm->ops));
3705:   PetscObjectChangeTypeName((PetscObject)dm,method);
3706:   (*r)(dm);
3707:   return 0;
3708: }

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

3713:   Not Collective

3715:   Input Parameter:
3716: . dm  - The DM

3718:   Output Parameter:
3719: . type - The DM type name

3721:   Level: intermediate

3723: .seealso: DMSetType(), DMCreate()
3724: @*/
3725: PetscErrorCode  DMGetType(DM dm, DMType *type)
3726: {
3729:   DMRegisterAll();
3730:   *type = ((PetscObject)dm)->type_name;
3731:   return 0;
3732: }

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

3737:   Collective on dm

3739:   Input Parameters:
3740: + dm - the DM
3741: - newtype - new DM type (use "same" for the same type)

3743:   Output Parameter:
3744: . M - pointer to new DM

3746:   Notes:
3747:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
3748:   the MPI communicator of the generated DM is always the same as the communicator
3749:   of the input DM.

3751:   Level: intermediate

3753: .seealso: DMCreate()
3754: @*/
3755: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3756: {
3757:   DM             B;
3758:   char           convname[256];
3759:   PetscBool      sametype/*, issame */;

3764:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
3765:   /* PetscStrcmp(newtype, "same", &issame); */
3766:   if (sametype) {
3767:     *M   = dm;
3768:     PetscObjectReference((PetscObject) dm);
3769:     return 0;
3770:   } else {
3771:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

3773:     /*
3774:        Order of precedence:
3775:        1) See if a specialized converter is known to the current DM.
3776:        2) See if a specialized converter is known to the desired DM class.
3777:        3) See if a good general converter is registered for the desired class
3778:        4) See if a good general converter is known for the current matrix.
3779:        5) Use a really basic converter.
3780:     */

3782:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3783:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3784:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3785:     PetscStrlcat(convname,"_",sizeof(convname));
3786:     PetscStrlcat(convname,newtype,sizeof(convname));
3787:     PetscStrlcat(convname,"_C",sizeof(convname));
3788:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
3789:     if (conv) goto foundconv;

3791:     /* 2)  See if a specialized converter is known to the desired DM class. */
3792:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3793:     DMSetType(B, newtype);
3794:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
3795:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
3796:     PetscStrlcat(convname,"_",sizeof(convname));
3797:     PetscStrlcat(convname,newtype,sizeof(convname));
3798:     PetscStrlcat(convname,"_C",sizeof(convname));
3799:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
3800:     if (conv) {
3801:       DMDestroy(&B);
3802:       goto foundconv;
3803:     }

3805: #if 0
3806:     /* 3) See if a good general converter is registered for the desired class */
3807:     conv = B->ops->convertfrom;
3808:     DMDestroy(&B);
3809:     if (conv) goto foundconv;

3811:     /* 4) See if a good general converter is known for the current matrix */
3812:     if (dm->ops->convert) {
3813:       conv = dm->ops->convert;
3814:     }
3815:     if (conv) goto foundconv;
3816: #endif

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

3821: foundconv:
3822:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
3823:     (*conv)(dm,newtype,M);
3824:     /* Things that are independent of DM type: We should consult DMClone() here */
3825:     {
3826:       PetscBool             isper;
3827:       const PetscReal      *maxCell, *L;
3828:       const DMBoundaryType *bd;
3829:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
3830:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
3831:       (*M)->prealloc_only = dm->prealloc_only;
3832:       PetscFree((*M)->vectype);
3833:       PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
3834:       PetscFree((*M)->mattype);
3835:       PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
3836:     }
3837:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
3838:   }
3839:   PetscObjectStateIncrease((PetscObject) *M);
3840:   return 0;
3841: }

3843: /*--------------------------------------------------------------------------------------------------------------------*/

3845: /*@C
3846:   DMRegister -  Adds a new DM component implementation

3848:   Not Collective

3850:   Input Parameters:
3851: + name        - The name of a new user-defined creation routine
3852: - create_func - The creation routine itself

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

3857:   Sample usage:
3858: .vb
3859:     DMRegister("my_da", MyDMCreate);
3860: .ve

3862:   Then, your DM type can be chosen with the procedural interface via
3863: .vb
3864:     DMCreate(MPI_Comm, DM *);
3865:     DMSetType(DM,"my_da");
3866: .ve
3867:    or at runtime via the option
3868: .vb
3869:     -da_type my_da
3870: .ve

3872:   Level: advanced

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

3876: @*/
3877: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
3878: {
3879:   DMInitializePackage();
3880:   PetscFunctionListAdd(&DMList,sname,function);
3881:   return 0;
3882: }

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

3887:   Collective on viewer

3889:   Input Parameters:
3890: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
3891:            some related function before a call to DMLoad().
3892: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
3893:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

3895:    Level: intermediate

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

3900:   Using PETSCVIEWERHDF5 type with PETSC_VIEWER_HDF5_PETSC format, one can save multiple DMPlex
3901:   meshes in a single HDF5 file. This in turn requires one to name the DMPlex object with PetscObjectSetName()
3902:   before saving it with DMView() and before loading it with DMLoad() for identification of the mesh object.

3904:   Notes for advanced users:
3905:   Most users should not need to know the details of the binary storage
3906:   format, since DMLoad() and DMView() completely hide these details.
3907:   But for anyone who's interested, the standard binary matrix storage
3908:   format is
3909: .vb
3910:      has not yet been determined
3911: .ve

3913: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
3914: @*/
3915: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
3916: {
3917:   PetscBool      isbinary, ishdf5;

3921:   PetscViewerCheckReadable(viewer);
3922:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
3923:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
3924:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
3925:   if (isbinary) {
3926:     PetscInt classid;
3927:     char     type[256];

3929:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
3931:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
3932:     DMSetType(newdm, type);
3933:     if (newdm->ops->load) (*newdm->ops->load)(newdm,viewer);
3934:   } else if (ishdf5) {
3935:     if (newdm->ops->load) (*newdm->ops->load)(newdm,viewer);
3936:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
3937:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
3938:   return 0;
3939: }

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

3944:   Not collective

3946:   Input Parameter:
3947: . dm - the DM

3949:   Output Parameters:
3950: + lmin - local minimum coordinates (length coord dim, optional)
3951: - lmax - local maximim coordinates (length coord dim, optional)

3953:   Level: beginner

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

3957: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
3958: @*/
3959: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
3960: {
3961:   Vec                coords = NULL;
3962:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
3963:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
3964:   const PetscScalar *local_coords;
3965:   PetscInt           N, Ni;
3966:   PetscInt           cdim, i, j;

3969:   DMGetCoordinateDim(dm, &cdim);
3970:   DMGetCoordinates(dm, &coords);
3971:   if (coords) {
3972:     VecGetArrayRead(coords, &local_coords);
3973:     VecGetLocalSize(coords, &N);
3974:     Ni   = N/cdim;
3975:     for (i = 0; i < Ni; ++i) {
3976:       for (j = 0; j < 3; ++j) {
3977:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3978:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
3979:       }
3980:     }
3981:     VecRestoreArrayRead(coords, &local_coords);
3982:   } else {
3983:     PetscBool isda;

3985:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
3986:     if (isda) DMGetLocalBoundingIndices_DMDA(dm, min, max);
3987:   }
3988:   if (lmin) PetscArraycpy(lmin, min, cdim);
3989:   if (lmax) PetscArraycpy(lmax, max, cdim);
3990:   return 0;
3991: }

3993: /*@
3994:   DMGetBoundingBox - Returns the global bounding box for the DM.

3996:   Collective

3998:   Input Parameter:
3999: . dm - the DM

4001:   Output Parameters:
4002: + gmin - global minimum coordinates (length coord dim, optional)
4003: - gmax - global maximim coordinates (length coord dim, optional)

4005:   Level: beginner

4007: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
4008: @*/
4009: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
4010: {
4011:   PetscReal      lmin[3], lmax[3];
4012:   PetscInt       cdim;
4013:   PetscMPIInt    count;

4016:   DMGetCoordinateDim(dm, &cdim);
4017:   PetscMPIIntCast(cdim, &count);
4018:   DMGetLocalBoundingBox(dm, lmin, lmax);
4019:   if (gmin) MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));
4020:   if (gmax) MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));
4021:   return 0;
4022: }

4024: /******************************** FEM Support **********************************/

4026: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4027: {
4028:   PetscInt       f;

4030:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4031:   for (f = 0; f < len; ++f) {
4032:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
4033:   }
4034:   return 0;
4035: }

4037: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4038: {
4039:   PetscInt       f, g;

4041:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
4042:   for (f = 0; f < rows; ++f) {
4043:     PetscPrintf(PETSC_COMM_SELF, "  |");
4044:     for (g = 0; g < cols; ++g) {
4045:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
4046:     }
4047:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4048:   }
4049:   return 0;
4050: }

4052: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4053: {
4054:   PetscInt          localSize, bs;
4055:   PetscMPIInt       size;
4056:   Vec               x, xglob;
4057:   const PetscScalar *xarray;

4059:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
4060:   VecDuplicate(X, &x);
4061:   VecCopy(X, x);
4062:   VecChop(x, tol);
4063:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
4064:   if (size > 1) {
4065:     VecGetLocalSize(x,&localSize);
4066:     VecGetArrayRead(x,&xarray);
4067:     VecGetBlockSize(x,&bs);
4068:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
4069:   } else {
4070:     xglob = x;
4071:   }
4072:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
4073:   if (size > 1) {
4074:     VecDestroy(&xglob);
4075:     VecRestoreArrayRead(x,&xarray);
4076:   }
4077:   VecDestroy(&x);
4078:   return 0;
4079: }

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

4084:   Input Parameter:
4085: . dm - The DM

4087:   Output Parameter:
4088: . section - The PetscSection

4090:   Options Database Keys:
4091: . -dm_petscsection_view - View the Section created by the DM

4093:   Level: advanced

4095:   Notes:
4096:   Use DMGetLocalSection() in new code.

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

4100: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
4101: @*/
4102: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4103: {
4104:   DMGetLocalSection(dm,section);
4105:   return 0;
4106: }

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

4111:   Input Parameter:
4112: . dm - The DM

4114:   Output Parameter:
4115: . section - The PetscSection

4117:   Options Database Keys:
4118: . -dm_petscsection_view - View the Section created by the DM

4120:   Level: intermediate

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

4124: .seealso: DMSetLocalSection(), DMGetGlobalSection()
4125: @*/
4126: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4127: {
4130:   if (!dm->localSection && dm->ops->createlocalsection) {
4131:     PetscInt d;

4133:     if (dm->setfromoptionscalled) {
4134:       PetscObject       obj = (PetscObject) dm;
4135:       PetscViewer       viewer;
4136:       PetscViewerFormat format;
4137:       PetscBool         flg;

4139:       PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4140:       if (flg) PetscViewerPushFormat(viewer, format);
4141:       for (d = 0; d < dm->Nds; ++d) {
4142:         PetscDSSetFromOptions(dm->probs[d].ds);
4143:         if (flg) PetscDSView(dm->probs[d].ds, viewer);
4144:       }
4145:       if (flg) {
4146:         PetscViewerFlush(viewer);
4147:         PetscViewerPopFormat(viewer);
4148:         PetscViewerDestroy(&viewer);
4149:       }
4150:     }
4151:     (*dm->ops->createlocalsection)(dm);
4152:     if (dm->localSection) PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");
4153:   }
4154:   *section = dm->localSection;
4155:   return 0;
4156: }

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

4161:   Input Parameters:
4162: + dm - The DM
4163: - section - The PetscSection

4165:   Level: advanced

4167:   Notes:
4168:   Use DMSetLocalSection() in new code.

4170:   Any existing Section will be destroyed

4172: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
4173: @*/
4174: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4175: {
4176:   DMSetLocalSection(dm,section);
4177:   return 0;
4178: }

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

4183:   Input Parameters:
4184: + dm - The DM
4185: - section - The PetscSection

4187:   Level: intermediate

4189:   Note: Any existing Section will be destroyed

4191: .seealso: DMGetLocalSection(), DMSetGlobalSection()
4192: @*/
4193: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4194: {
4195:   PetscInt       numFields = 0;
4196:   PetscInt       f;

4200:   PetscObjectReference((PetscObject)section);
4201:   PetscSectionDestroy(&dm->localSection);
4202:   dm->localSection = section;
4203:   if (section) PetscSectionGetNumFields(dm->localSection, &numFields);
4204:   if (numFields) {
4205:     DMSetNumFields(dm, numFields);
4206:     for (f = 0; f < numFields; ++f) {
4207:       PetscObject disc;
4208:       const char *name;

4210:       PetscSectionGetFieldName(dm->localSection, f, &name);
4211:       DMGetField(dm, f, NULL, &disc);
4212:       PetscObjectSetName(disc, name);
4213:     }
4214:   }
4215:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4216:   PetscSectionDestroy(&dm->globalSection);
4217:   return 0;
4218: }

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

4223:   not collective

4225:   Input Parameter:
4226: . dm - The DM

4228:   Output Parameters:
4229: + 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.
4230: . 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.
4231: - bias - Vector containing bias to be added to constrained dofs

4233:   Level: advanced

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

4237: .seealso: DMSetDefaultConstraints()
4238: @*/
4239: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4240: {
4242:   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) (*dm->ops->createdefaultconstraints)(dm);
4243:   if (section) *section = dm->defaultConstraint.section;
4244:   if (mat) *mat = dm->defaultConstraint.mat;
4245:   if (bias) *bias = dm->defaultConstraint.bias;
4246:   return 0;
4247: }

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

4252:   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 + bias, l[s[i]] = c[i], where the scatter s is defined by the PetscSection returned by DMGetDefaultConstraints().

4254:   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.  Any bias, if specified, is ignored when accumulating.

4256:   collective on dm

4258:   Input Parameters:
4259: + dm - The DM
4260: . 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).
4261: . 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).
4262: - bias - A bias vector to be added to constrained values in the local vector.  NULL indicates no bias.  Must have a local communicator (PETSC_COMM_SELF or derivative).

4264:   Level: advanced

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

4268: .seealso: DMGetDefaultConstraints()
4269: @*/
4270: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4271: {
4272:   PetscMPIInt result;

4275:   if (section) {
4277:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
4279:   }
4280:   if (mat) {
4282:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
4284:   }
4285:   if (bias) {
4287:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)bias),&result);
4289:   }
4290:   PetscObjectReference((PetscObject)section);
4291:   PetscSectionDestroy(&dm->defaultConstraint.section);
4292:   dm->defaultConstraint.section = section;
4293:   PetscObjectReference((PetscObject)mat);
4294:   MatDestroy(&dm->defaultConstraint.mat);
4295:   dm->defaultConstraint.mat = mat;
4296:   PetscObjectReference((PetscObject)bias);
4297:   VecDestroy(&dm->defaultConstraint.bias);
4298:   dm->defaultConstraint.bias = bias;
4299:   return 0;
4300: }

4302: #if defined(PETSC_USE_DEBUG)
4303: /*
4304:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

4306:   Input Parameters:
4307: + dm - The DM
4308: . localSection - PetscSection describing the local data layout
4309: - globalSection - PetscSection describing the global data layout

4311:   Level: intermediate

4313: .seealso: DMGetSectionSF(), DMSetSectionSF()
4314: */
4315: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4316: {
4317:   MPI_Comm        comm;
4318:   PetscLayout     layout;
4319:   const PetscInt *ranges;
4320:   PetscInt        pStart, pEnd, p, nroots;
4321:   PetscMPIInt     size, rank;
4322:   PetscBool       valid = PETSC_TRUE, gvalid;

4324:   PetscObjectGetComm((PetscObject)dm,&comm);
4326:   MPI_Comm_size(comm, &size);
4327:   MPI_Comm_rank(comm, &rank);
4328:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4329:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4330:   PetscLayoutCreate(comm, &layout);
4331:   PetscLayoutSetBlockSize(layout, 1);
4332:   PetscLayoutSetLocalSize(layout, nroots);
4333:   PetscLayoutSetUp(layout);
4334:   PetscLayoutGetRanges(layout, &ranges);
4335:   for (p = pStart; p < pEnd; ++p) {
4336:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

4338:     PetscSectionGetDof(localSection, p, &dof);
4339:     PetscSectionGetOffset(localSection, p, &off);
4340:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4341:     PetscSectionGetDof(globalSection, p, &gdof);
4342:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4343:     PetscSectionGetOffset(globalSection, p, &goff);
4344:     if (!gdof) continue; /* Censored point */
4345:     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;}
4346:     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;}
4347:     if (gdof < 0) {
4348:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
4349:       for (d = 0; d < gsize; ++d) {
4350:         PetscInt offset = -(goff+1) + d, r;

4352:         PetscFindInt(offset,size+1,ranges,&r);
4353:         if (r < 0) r = -(r+2);
4354:         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;}
4355:       }
4356:     }
4357:   }
4358:   PetscLayoutDestroy(&layout);
4359:   PetscSynchronizedFlush(comm, NULL);
4360:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4361:   if (!gvalid) {
4362:     DMView(dm, NULL);
4363:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4364:   }
4365:   return 0;
4366: }
4367: #endif

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

4372:   Collective on dm

4374:   Input Parameter:
4375: . dm - The DM

4377:   Output Parameter:
4378: . section - The PetscSection

4380:   Level: intermediate

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

4384: .seealso: DMSetLocalSection(), DMGetLocalSection()
4385: @*/
4386: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4387: {
4390:   if (!dm->globalSection) {
4391:     PetscSection s;

4393:     DMGetLocalSection(dm, &s);
4396:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4397:     PetscLayoutDestroy(&dm->map);
4398:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4399:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4400:   }
4401:   *section = dm->globalSection;
4402:   return 0;
4403: }

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

4408:   Input Parameters:
4409: + dm - The DM
4410: - section - The PetscSection, or NULL

4412:   Level: intermediate

4414:   Note: Any existing Section will be destroyed

4416: .seealso: DMGetGlobalSection(), DMSetLocalSection()
4417: @*/
4418: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4419: {
4422:   PetscObjectReference((PetscObject)section);
4423:   PetscSectionDestroy(&dm->globalSection);
4424:   dm->globalSection = section;
4425: #if defined(PETSC_USE_DEBUG)
4426:   if (section) DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);
4427: #endif
4428:   return 0;
4429: }

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

4435:   Input Parameter:
4436: . dm - The DM

4438:   Output Parameter:
4439: . sf - The PetscSF

4441:   Level: intermediate

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

4445: .seealso: DMSetSectionSF(), DMCreateSectionSF()
4446: @*/
4447: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4448: {
4449:   PetscInt       nroots;

4453:   if (!dm->sectionSF) {
4454:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
4455:   }
4456:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4457:   if (nroots < 0) {
4458:     PetscSection section, gSection;

4460:     DMGetLocalSection(dm, &section);
4461:     if (section) {
4462:       DMGetGlobalSection(dm, &gSection);
4463:       DMCreateSectionSF(dm, section, gSection);
4464:     } else {
4465:       *sf = NULL;
4466:       return 0;
4467:     }
4468:   }
4469:   *sf = dm->sectionSF;
4470:   return 0;
4471: }

4473: /*@
4474:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

4476:   Input Parameters:
4477: + dm - The DM
4478: - sf - The PetscSF

4480:   Level: intermediate

4482:   Note: Any previous SF is destroyed

4484: .seealso: DMGetSectionSF(), DMCreateSectionSF()
4485: @*/
4486: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4487: {
4490:   PetscObjectReference((PetscObject) sf);
4491:   PetscSFDestroy(&dm->sectionSF);
4492:   dm->sectionSF = sf;
4493:   return 0;
4494: }

4496: /*@C
4497:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
4498:   describing the data layout.

4500:   Input Parameters:
4501: + dm - The DM
4502: . localSection - PetscSection describing the local data layout
4503: - globalSection - PetscSection describing the global data layout

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

4507:   Level: developer

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

4513: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
4514: @*/
4515: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4516: {
4518:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4519:   return 0;
4520: }

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

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

4528:   Output Parameter:
4529: . sf - The PetscSF

4531:   Level: intermediate

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

4535: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4536: @*/
4537: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4538: {
4541:   *sf = dm->sf;
4542:   return 0;
4543: }

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

4548:   Input Parameters:
4549: + dm - The DM
4550: - sf - The PetscSF

4552:   Level: intermediate

4554: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4555: @*/
4556: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4557: {
4560:   PetscObjectReference((PetscObject) sf);
4561:   PetscSFDestroy(&dm->sf);
4562:   dm->sf = sf;
4563:   return 0;
4564: }

4566: /*@
4567:   DMGetNaturalSF - Get the PetscSF encoding the map back to the original mesh ordering

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: DMSetNaturalSF(), DMSetUseNatural(), DMGetUseNatural(), DMPlexCreateGlobalToNaturalSF(), DMPlexDistribute()
4580: @*/
4581: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4582: {
4585:   *sf = dm->sfNatural;
4586:   return 0;
4587: }

4589: /*@
4590:   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering

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

4596:   Level: intermediate

4598: .seealso: DMGetNaturalSF(), DMSetUseNatural(), DMGetUseNatural(), DMPlexCreateGlobalToNaturalSF(), DMPlexDistribute()
4599: @*/
4600: PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4601: {
4604:   PetscObjectReference((PetscObject) sf);
4605:   PetscSFDestroy(&dm->sfNatural);
4606:   dm->sfNatural = sf;
4607:   return 0;
4608: }

4610: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4611: {
4612:   PetscClassId   id;

4614:   PetscObjectGetClassId(disc, &id);
4615:   if (id == PETSCFE_CLASSID) {
4616:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4617:   } else if (id == PETSCFV_CLASSID) {
4618:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4619:   } else {
4620:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4621:   }
4622:   return 0;
4623: }

4625: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4626: {
4627:   RegionField   *tmpr;
4628:   PetscInt       Nf = dm->Nf, f;

4630:   if (Nf >= NfNew) return 0;
4631:   PetscMalloc1(NfNew, &tmpr);
4632:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4633:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4634:   PetscFree(dm->fields);
4635:   dm->Nf     = NfNew;
4636:   dm->fields = tmpr;
4637:   return 0;
4638: }

4640: /*@
4641:   DMClearFields - Remove all fields from the DM

4643:   Logically collective on dm

4645:   Input Parameter:
4646: . dm - The DM

4648:   Level: intermediate

4650: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4651: @*/
4652: PetscErrorCode DMClearFields(DM dm)
4653: {
4654:   PetscInt       f;

4657:   for (f = 0; f < dm->Nf; ++f) {
4658:     PetscObjectDestroy(&dm->fields[f].disc);
4659:     DMLabelDestroy(&dm->fields[f].label);
4660:   }
4661:   PetscFree(dm->fields);
4662:   dm->fields = NULL;
4663:   dm->Nf     = 0;
4664:   return 0;
4665: }

4667: /*@
4668:   DMGetNumFields - Get the number of fields in the DM

4670:   Not collective

4672:   Input Parameter:
4673: . dm - The DM

4675:   Output Parameter:
4676: . Nf - The number of fields

4678:   Level: intermediate

4680: .seealso: DMSetNumFields(), DMSetField()
4681: @*/
4682: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4683: {
4686:   *numFields = dm->Nf;
4687:   return 0;
4688: }

4690: /*@
4691:   DMSetNumFields - Set the number of fields in the DM

4693:   Logically collective on dm

4695:   Input Parameters:
4696: + dm - The DM
4697: - Nf - The number of fields

4699:   Level: intermediate

4701: .seealso: DMGetNumFields(), DMSetField()
4702: @*/
4703: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4704: {
4705:   PetscInt       Nf, f;

4708:   DMGetNumFields(dm, &Nf);
4709:   for (f = Nf; f < numFields; ++f) {
4710:     PetscContainer obj;

4712:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
4713:     DMAddField(dm, NULL, (PetscObject) obj);
4714:     PetscContainerDestroy(&obj);
4715:   }
4716:   return 0;
4717: }

4719: /*@
4720:   DMGetField - Return the discretization object for a given DM field

4722:   Not collective

4724:   Input Parameters:
4725: + dm - The DM
4726: - f  - The field number

4728:   Output Parameters:
4729: + label - The label indicating the support of the field, or NULL for the entire mesh
4730: - field - The discretization object

4732:   Level: intermediate

4734: .seealso: DMAddField(), DMSetField()
4735: @*/
4736: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4737: {
4741:   if (label) *label = dm->fields[f].label;
4742:   if (field) *field = dm->fields[f].disc;
4743:   return 0;
4744: }

4746: /* Does not clear the DS */
4747: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4748: {
4749:   DMFieldEnlarge_Static(dm, f+1);
4750:   DMLabelDestroy(&dm->fields[f].label);
4751:   PetscObjectDestroy(&dm->fields[f].disc);
4752:   dm->fields[f].label = label;
4753:   dm->fields[f].disc  = field;
4754:   PetscObjectReference((PetscObject) label);
4755:   PetscObjectReference((PetscObject) field);
4756:   return 0;
4757: }

4759: /*@
4760:   DMSetField - Set the discretization object for a given DM field

4762:   Logically collective on dm

4764:   Input Parameters:
4765: + dm    - The DM
4766: . f     - The field number
4767: . label - The label indicating the support of the field, or NULL for the entire mesh
4768: - field - The discretization object

4770:   Level: intermediate

4772: .seealso: DMAddField(), DMGetField()
4773: @*/
4774: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4775: {
4780:   DMSetField_Internal(dm, f, label, field);
4781:   DMSetDefaultAdjacency_Private(dm, f, field);
4782:   DMClearDS(dm);
4783:   return 0;
4784: }

4786: /*@
4787:   DMAddField - Add the discretization object for the given DM field

4789:   Logically collective on dm

4791:   Input Parameters:
4792: + dm    - The DM
4793: . label - The label indicating the support of the field, or NULL for the entire mesh
4794: - field - The discretization object

4796:   Level: intermediate

4798: .seealso: DMSetField(), DMGetField()
4799: @*/
4800: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4801: {
4802:   PetscInt       Nf = dm->Nf;

4807:   DMFieldEnlarge_Static(dm, Nf+1);
4808:   dm->fields[Nf].label = label;
4809:   dm->fields[Nf].disc  = field;
4810:   PetscObjectReference((PetscObject) label);
4811:   PetscObjectReference((PetscObject) field);
4812:   DMSetDefaultAdjacency_Private(dm, Nf, field);
4813:   DMClearDS(dm);
4814:   return 0;
4815: }

4817: /*@
4818:   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells

4820:   Logically collective on dm

4822:   Input Parameters:
4823: + dm          - The DM
4824: . f           - The field index
4825: - avoidTensor - The flag to avoid defining the field on tensor cells

4827:   Level: intermediate

4829: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4830: @*/
4831: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4832: {
4834:   dm->fields[f].avoidTensor = avoidTensor;
4835:   return 0;
4836: }

4838: /*@
4839:   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells

4841:   Logically collective on dm

4843:   Input Parameters:
4844: + dm          - The DM
4845: - f           - The field index

4847:   Output Parameter:
4848: . avoidTensor - The flag to avoid defining the field on tensor cells

4850:   Level: intermediate

4852: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4853: @*/
4854: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4855: {
4857:   *avoidTensor = dm->fields[f].avoidTensor;
4858:   return 0;
4859: }

4861: /*@
4862:   DMCopyFields - Copy the discretizations for the DM into another DM

4864:   Collective on dm

4866:   Input Parameter:
4867: . dm - The DM

4869:   Output Parameter:
4870: . newdm - The DM

4872:   Level: advanced

4874: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4875: @*/
4876: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4877: {
4878:   PetscInt       Nf, f;

4880:   if (dm == newdm) return 0;
4881:   DMGetNumFields(dm, &Nf);
4882:   DMClearFields(newdm);
4883:   for (f = 0; f < Nf; ++f) {
4884:     DMLabel     label;
4885:     PetscObject field;
4886:     PetscBool   useCone, useClosure;

4888:     DMGetField(dm, f, &label, &field);
4889:     DMSetField(newdm, f, label, field);
4890:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4891:     DMSetAdjacency(newdm, f, useCone, useClosure);
4892:   }
4893:   return 0;
4894: }

4896: /*@
4897:   DMGetAdjacency - Returns the flags for determining variable influence

4899:   Not collective

4901:   Input Parameters:
4902: + dm - The DM object
4903: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4905:   Output Parameters:
4906: + useCone    - Flag for variable influence starting with the cone operation
4907: - useClosure - Flag for variable influence using transitive closure

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

4915:   Level: developer

4917: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4918: @*/
4919: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4920: {
4924:   if (f < 0) {
4925:     if (useCone)    *useCone    = dm->adjacency[0];
4926:     if (useClosure) *useClosure = dm->adjacency[1];
4927:   } else {
4928:     PetscInt       Nf;

4930:     DMGetNumFields(dm, &Nf);
4932:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4933:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4934:   }
4935:   return 0;
4936: }

4938: /*@
4939:   DMSetAdjacency - Set the flags for determining variable influence

4941:   Not collective

4943:   Input Parameters:
4944: + dm         - The DM object
4945: . f          - The field number
4946: . useCone    - Flag for variable influence starting with the cone operation
4947: - useClosure - Flag for variable influence using transitive closure

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

4955:   Level: developer

4957: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4958: @*/
4959: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4960: {
4962:   if (f < 0) {
4963:     dm->adjacency[0] = useCone;
4964:     dm->adjacency[1] = useClosure;
4965:   } else {
4966:     PetscInt       Nf;

4968:     DMGetNumFields(dm, &Nf);
4970:     dm->fields[f].adjacency[0] = useCone;
4971:     dm->fields[f].adjacency[1] = useClosure;
4972:   }
4973:   return 0;
4974: }

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

4979:   Not collective

4981:   Input Parameter:
4982: . dm - The DM object

4984:   Output Parameters:
4985: + useCone    - Flag for variable influence starting with the cone operation
4986: - useClosure - Flag for variable influence using transitive closure

4988:   Notes:
4989: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4990: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4991: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

4993:   Level: developer

4995: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4996: @*/
4997: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4998: {
4999:   PetscInt       Nf;

5004:   DMGetNumFields(dm, &Nf);
5005:   if (!Nf) {
5006:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5007:   } else {
5008:     DMGetAdjacency(dm, 0, useCone, useClosure);
5009:   }
5010:   return 0;
5011: }

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

5016:   Not collective

5018:   Input Parameters:
5019: + dm         - The DM object
5020: . useCone    - Flag for variable influence starting with the cone operation
5021: - useClosure - Flag for variable influence using transitive closure

5023:   Notes:
5024: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5025: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5026: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5028:   Level: developer

5030: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5031: @*/
5032: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5033: {
5034:   PetscInt       Nf;

5037:   DMGetNumFields(dm, &Nf);
5038:   if (!Nf) {
5039:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5040:   } else {
5041:     DMSetAdjacency(dm, 0, useCone, useClosure);
5042:   }
5043:   return 0;
5044: }

5046: /* Complete labels that are being used for FEM BC */
5047: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
5048: {
5049:   PetscObject    obj;
5050:   PetscClassId   id;
5051:   PetscInt       Nbd, bd;
5052:   PetscBool      isFE      = PETSC_FALSE;
5053:   PetscBool      duplicate = PETSC_FALSE;

5055:   DMGetField(dm, field, NULL, &obj);
5056:   PetscObjectGetClassId(obj, &id);
5057:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5058:   if (isFE && label) {
5059:     /* Only want to modify label once */
5060:     PetscDSGetNumBoundary(ds, &Nbd);
5061:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5062:       DMLabel l;

5064:       PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
5065:       duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
5066:       if (duplicate) break;
5067:     }
5068:     if (!duplicate) {
5069:       DM plex;

5071:       DMConvert(dm, DMPLEX, &plex);
5072:       if (plex) DMPlexLabelComplete(plex, label);
5073:       DMDestroy(&plex);
5074:     }
5075:   }
5076:   return 0;
5077: }

5079: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5080: {
5081:   DMSpace       *tmpd;
5082:   PetscInt       Nds = dm->Nds, s;

5084:   if (Nds >= NdsNew) return 0;
5085:   PetscMalloc1(NdsNew, &tmpd);
5086:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5087:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5088:   PetscFree(dm->probs);
5089:   dm->Nds   = NdsNew;
5090:   dm->probs = tmpd;
5091:   return 0;
5092: }

5094: /*@
5095:   DMGetNumDS - Get the number of discrete systems in the DM

5097:   Not collective

5099:   Input Parameter:
5100: . dm - The DM

5102:   Output Parameter:
5103: . Nds - The number of PetscDS objects

5105:   Level: intermediate

5107: .seealso: DMGetDS(), DMGetCellDS()
5108: @*/
5109: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5110: {
5113:   *Nds = dm->Nds;
5114:   return 0;
5115: }

5117: /*@
5118:   DMClearDS - Remove all discrete systems from the DM

5120:   Logically collective on dm

5122:   Input Parameter:
5123: . dm - The DM

5125:   Level: intermediate

5127: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5128: @*/
5129: PetscErrorCode DMClearDS(DM dm)
5130: {
5131:   PetscInt       s;

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

5145: /*@
5146:   DMGetDS - Get the default PetscDS

5148:   Not collective

5150:   Input Parameter:
5151: . dm    - The DM

5153:   Output Parameter:
5154: . prob - The default PetscDS

5156:   Level: intermediate

5158: .seealso: DMGetCellDS(), DMGetRegionDS()
5159: @*/
5160: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5161: {
5165:   if (dm->Nds <= 0) {
5166:     PetscDS ds;

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

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

5179:   Not collective

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

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

5188:   Level: developer

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

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:
5229:   If a non-NULL label is given, but there is no PetscDS on that specific label,
5230:   the PetscDS for the full domain (if present) is returned. Returns with
5231:   fields=NULL and prob=NULL if there is no PetscDS for the full domain.

5233:   Level: advanced

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

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

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

5258:   Collective on dm

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

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

5269:   Level: advanced

5271: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5272: @*/
5273: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5274: {
5275:   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;

5325:   DMGetNumDS(dm, &Nds);
5327:   if (label) {
5329:     *label = dm->probs[num].label;
5330:   }
5331:   if (fields) {
5333:     *fields = dm->probs[num].fields;
5334:   }
5335:   if (ds) {
5337:     *ds = dm->probs[num].ds;
5338:   }
5339:   return 0;
5340: }

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

5345:   Not collective

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

5354:   Level: advanced

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

5364:   DMGetNumDS(dm, &Nds);
5366:   PetscObjectReference((PetscObject) label);
5367:   DMLabelDestroy(&dm->probs[num].label);
5368:   dm->probs[num].label = label;
5369:   if (fields) {
5371:     PetscObjectReference((PetscObject) fields);
5372:     ISDestroy(&dm->probs[num].fields);
5373:     dm->probs[num].fields = fields;
5374:   }
5375:   if (ds) {
5377:     PetscObjectReference((PetscObject) ds);
5378:     PetscDSDestroy(&dm->probs[num].ds);
5379:     dm->probs[num].ds = ds;
5380:   }
5381:   return 0;
5382: }

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

5387:   Not collective

5389:   Input Parameters:
5390: + dm  - The DM
5391: - ds  - The PetscDS defined on the given region

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

5396:   Level: advanced

5398: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5399: @*/
5400: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5401: {
5402:   PetscInt       Nds, n;

5407:   DMGetNumDS(dm, &Nds);
5408:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5409:   if (n >= Nds) *num = -1;
5410:   else          *num = n;
5411:   return 0;
5412: }

5414: /*@C
5415:   DMCreateFEDefault - Create a PetscFE based on the celltype for the mesh

5417:   Not collective

5419:   Input Parameters:
5420: + dm     - The DM
5421: . Nc     - The number of components for the field
5422: . prefix - The options prefix for the output PetscFE, or NULL
5423: - qorder - The quadrature order or PETSC_DETERMINE to use PetscSpace polynomial degree

5425:   Output Parameter:
5426: . fem - The PetscFE

5428:   Note: This is a convenience method that just calls PetscFECreateByCell() underneath.

5430:   Level: intermediate

5432: .seealso: PetscFECreateByCell(), DMAddField(), DMCreateDS(), DMGetCellDS(), DMGetRegionDS()
5433: @*/
5434: PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5435: {
5436:   DMPolytopeType ct;
5437:   PetscInt       dim, cStart;

5444:   DMGetDimension(dm, &dim);
5445:   DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5446:   DMPlexGetCellType(dm, cStart, &ct);
5447:   PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem);
5448:   return 0;
5449: }

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

5454:   Collective on dm

5456:   Input Parameter:
5457: . dm - The DM

5459:   Options Database Keys:
5460: . -dm_petscds_view - View all the PetscDS objects in this DM

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

5464:   Level: intermediate

5466: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5467: @*/
5468: PetscErrorCode DMCreateDS(DM dm)
5469: {
5470:   MPI_Comm       comm;
5471:   PetscDS        dsDef;
5472:   DMLabel       *labelSet;
5473:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5474:   PetscBool      doSetup = PETSC_TRUE, flg;

5477:   if (!dm->fields) return 0;
5478:   PetscObjectGetComm((PetscObject) dm, &comm);
5479:   DMGetCoordinateDim(dm, &dE);
5480:   /* Determine how many regions we have */
5481:   PetscMalloc1(Nf, &labelSet);
5482:   Nl   = 0;
5483:   Ndef = 0;
5484:   for (f = 0; f < Nf; ++f) {
5485:     DMLabel  label = dm->fields[f].label;
5486:     PetscInt l;

5488: #ifdef PETSC_HAVE_LIBCEED
5489:     /* Move CEED context to discretizations */
5490:     {
5491:       PetscClassId id;

5493:       PetscObjectGetClassId(dm->fields[f].disc, &id);
5494:       if (id == PETSCFE_CLASSID) {
5495:         Ceed ceed;

5497:         DMGetCeed(dm, &ceed);
5498:         PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
5499:       }
5500:     }
5501: #endif
5502:     if (!label) {++Ndef; continue;}
5503:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5504:     if (l < Nl) continue;
5505:     labelSet[Nl++] = label;
5506:   }
5507:   /* Create default DS if there are no labels to intersect with */
5508:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5509:   if (!dsDef && Ndef && !Nl) {
5510:     IS        fields;
5511:     PetscInt *fld, nf;

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

5522:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5523:     DMSetRegionDS(dm, NULL, fields, dsDef);
5524:     PetscDSDestroy(&dsDef);
5525:     ISDestroy(&fields);
5526:   }
5527:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5528:   if (dsDef) PetscDSSetCoordinateDimension(dsDef, dE);
5529:   /* Intersect labels with default fields */
5530:   if (Ndef && Nl) {
5531:     DM              plex;
5532:     DMLabel         cellLabel;
5533:     IS              fieldIS, allcellIS, defcellIS = NULL;
5534:     PetscInt       *fields;
5535:     const PetscInt *cells;
5536:     PetscInt        depth, nf = 0, n, c;

5538:     DMConvert(dm, DMPLEX, &plex);
5539:     DMPlexGetDepth(plex, &depth);
5540:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5541:     if (!allcellIS) DMGetStratumIS(plex, "depth", depth, &allcellIS);
5542:     /* TODO This looks like it only works for one label */
5543:     for (l = 0; l < Nl; ++l) {
5544:       DMLabel label = labelSet[l];
5545:       IS      pointIS;

5547:       ISDestroy(&defcellIS);
5548:       DMLabelGetStratumIS(label, 1, &pointIS);
5549:       ISDifference(allcellIS, pointIS, &defcellIS);
5550:       ISDestroy(&pointIS);
5551:     }
5552:     ISDestroy(&allcellIS);

5554:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5555:     ISGetLocalSize(defcellIS, &n);
5556:     ISGetIndices(defcellIS, &cells);
5557:     for (c = 0; c < n; ++c) DMLabelSetValue(cellLabel, cells[c], 1);
5558:     ISRestoreIndices(defcellIS, &cells);
5559:     ISDestroy(&defcellIS);
5560:     DMPlexLabelComplete(plex, cellLabel);

5562:     PetscMalloc1(Ndef, &fields);
5563:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5564:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5565:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
5566:     ISSetType(fieldIS, ISGENERAL);
5567:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5569:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5570:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5571:     PetscDSSetCoordinateDimension(dsDef, dE);
5572:     DMLabelDestroy(&cellLabel);
5573:     PetscDSDestroy(&dsDef);
5574:     ISDestroy(&fieldIS);
5575:     DMDestroy(&plex);
5576:   }
5577:   /* Create label DSes
5578:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5579:   */
5580:   /* TODO Should check that labels are disjoint */
5581:   for (l = 0; l < Nl; ++l) {
5582:     DMLabel   label = labelSet[l];
5583:     PetscDS   ds;
5584:     IS        fields;
5585:     PetscInt *fld, nf;

5587:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5588:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5589:     PetscMalloc1(nf, &fld);
5590:     for (f = 0, nf  = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5591:     ISCreate(PETSC_COMM_SELF, &fields);
5592:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
5593:     ISSetType(fields, ISGENERAL);
5594:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5595:     DMSetRegionDS(dm, label, fields, ds);
5596:     ISDestroy(&fields);
5597:     PetscDSSetCoordinateDimension(ds, dE);
5598:     {
5599:       DMPolytopeType ct;
5600:       PetscInt       lStart, lEnd;
5601:       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;

5603:       DMLabelGetBounds(label, &lStart, &lEnd);
5604:       if (lStart >= 0) {
5605:         DMPlexGetCellType(dm, lStart, &ct);
5606:         switch (ct) {
5607:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5608:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5609:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5610:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5611:             isCohesiveLocal = PETSC_TRUE;break;
5612:           default: break;
5613:         }
5614:       }
5615:       MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm);
5616:       for (f = 0, nf  = 0; f < Nf; ++f) {
5617:         if (label == dm->fields[f].label || !dm->fields[f].label) {
5618:           if (label == dm->fields[f].label) {
5619:             PetscDSSetDiscretization(ds, nf, NULL);
5620:             PetscDSSetCohesive(ds, nf, isCohesive);
5621:           }
5622:           ++nf;
5623:         }
5624:       }
5625:     }
5626:     PetscDSDestroy(&ds);
5627:   }
5628:   PetscFree(labelSet);
5629:   /* Set fields in DSes */
5630:   for (s = 0; s < dm->Nds; ++s) {
5631:     PetscDS         ds     = dm->probs[s].ds;
5632:     IS              fields = dm->probs[s].fields;
5633:     const PetscInt *fld;
5634:     PetscInt        nf, dsnf;
5635:     PetscBool       isCohesive;

5637:     PetscDSGetNumFields(ds, &dsnf);
5638:     PetscDSIsCohesive(ds, &isCohesive);
5639:     ISGetLocalSize(fields, &nf);
5640:     ISGetIndices(fields, &fld);
5641:     for (f = 0; f < nf; ++f) {
5642:       PetscObject  disc  = dm->fields[fld[f]].disc;
5643:       PetscBool    isCohesiveField;
5644:       PetscClassId id;

5646:       /* Handle DS with no fields */
5647:       if (dsnf) PetscDSGetCohesive(ds, f, &isCohesiveField);
5648:       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5649:       if (isCohesive && !isCohesiveField) PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);
5650:       PetscDSSetDiscretization(ds, f, disc);
5651:       /* We allow people to have placeholder fields and construct the Section by hand */
5652:       PetscObjectGetClassId(disc, &id);
5653:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5654:     }
5655:     ISRestoreIndices(fields, &fld);
5656:   }
5657:   /* Allow k-jet tabulation */
5658:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5659:   if (flg) {
5660:     for (s = 0; s < dm->Nds; ++s) {
5661:       PetscDS  ds = dm->probs[s].ds;
5662:       PetscInt Nf, f;

5664:       PetscDSGetNumFields(ds, &Nf);
5665:       for (f = 0; f < Nf; ++f) PetscDSSetJetDegree(ds, f, k);
5666:     }
5667:   }
5668:   /* Setup DSes */
5669:   if (doSetup) {
5670:     for (s = 0; s < dm->Nds; ++s) PetscDSSetUp(dm->probs[s].ds);
5671:   }
5672:   return 0;
5673: }

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

5678:   Collective on DM

5680:   Input Parameters:
5681: + dm   - The DM
5682: - time - The time

5684:   Output Parameters:
5685: + u    - The vector will be filled with exact solution values, or NULL
5686: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5688:   Note: The user must call PetscDSSetExactSolution() beforehand

5690:   Level: developer

5692: .seealso: PetscDSSetExactSolution()
5693: @*/
5694: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5695: {
5696:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5697:   void            **ectxs;
5698:   PetscInt          Nf, Nds, s;

5703:   DMGetNumFields(dm, &Nf);
5704:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5705:   DMGetNumDS(dm, &Nds);
5706:   for (s = 0; s < Nds; ++s) {
5707:     PetscDS         ds;
5708:     DMLabel         label;
5709:     IS              fieldIS;
5710:     const PetscInt *fields, id = 1;
5711:     PetscInt        dsNf, f;

5713:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5714:     PetscDSGetNumFields(ds, &dsNf);
5715:     ISGetIndices(fieldIS, &fields);
5716:     PetscArrayzero(exacts, Nf);
5717:     PetscArrayzero(ectxs, Nf);
5718:     if (u) {
5719:       for (f = 0; f < dsNf; ++f) {
5720:         const PetscInt field = fields[f];
5721:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5722:       }
5723:       ISRestoreIndices(fieldIS, &fields);
5724:       if (label) {
5725:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5726:       } else {
5727:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5728:       }
5729:     }
5730:     if (u_t) {
5731:       PetscArrayzero(exacts, Nf);
5732:       PetscArrayzero(ectxs, Nf);
5733:       for (f = 0; f < dsNf; ++f) {
5734:         const PetscInt field = fields[f];
5735:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5736:       }
5737:       ISRestoreIndices(fieldIS, &fields);
5738:       if (label) {
5739:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5740:       } else {
5741:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5742:       }
5743:     }
5744:   }
5745:   if (u) {
5746:     PetscObjectSetName((PetscObject) u, "Exact Solution");
5747:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
5748:   }
5749:   if (u_t) {
5750:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
5751:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
5752:   }
5753:   PetscFree2(exacts, ectxs);
5754:   return 0;
5755: }

5757: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5758: {
5759:   PetscDS        dsNew;
5760:   DSBoundary     b;
5761:   PetscInt       cdim, Nf, f;
5762:   PetscBool      isCohesive;
5763:   void          *ctx;

5765:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
5766:   PetscDSCopyConstants(ds, dsNew);
5767:   PetscDSCopyExactSolutions(ds, dsNew);
5768:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5769:   PetscDSCopyEquations(ds, dsNew);
5770:   PetscDSGetNumFields(ds, &Nf);
5771:   for (f = 0; f < Nf; ++f) {
5772:     PetscDSGetContext(ds, f, &ctx);
5773:     PetscDSSetContext(dsNew, f, ctx);
5774:     PetscDSGetCohesive(ds, f, &isCohesive);
5775:     PetscDSSetCohesive(dsNew, f, isCohesive);
5776:   }
5777:   if (Nf) {
5778:     PetscDSGetCoordinateDimension(ds, &cdim);
5779:     PetscDSSetCoordinateDimension(dsNew, cdim);
5780:   }
5781:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5782:   for (b = dsNew->boundary; b; b = b->next) {
5783:     DMGetLabel(dm, b->lname, &b->label);
5784:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5786:   }

5788:   DMSetRegionDS(dm, label, fields, dsNew);
5789:   PetscDSDestroy(&dsNew);
5790:   return 0;
5791: }

5793: /*@
5794:   DMCopyDS - Copy the discrete systems for the DM into another DM

5796:   Collective on dm

5798:   Input Parameter:
5799: . dm - The DM

5801:   Output Parameter:
5802: . newdm - The DM

5804:   Level: advanced

5806: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5807: @*/
5808: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5809: {
5810:   PetscInt       Nds, s;

5812:   if (dm == newdm) return 0;
5813:   DMGetNumDS(dm, &Nds);
5814:   DMClearDS(newdm);
5815:   for (s = 0; s < Nds; ++s) {
5816:     DMLabel  label;
5817:     IS       fields;
5818:     PetscDS  ds, newds;
5819:     PetscInt Nbd, bd;

5821:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5822:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5823:     DMTransferDS_Internal(newdm, label, fields, ds);
5824:     /* Commplete new labels in the new DS */
5825:     DMGetRegionDS(newdm, label, NULL, &newds);
5826:     PetscDSGetNumBoundary(newds, &Nbd);
5827:     for (bd = 0; bd < Nbd; ++bd) {
5828:       PetscWeakForm wf;
5829:       DMLabel       label;
5830:       PetscInt      field;

5832:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5833:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
5834:       PetscWeakFormReplaceLabel(wf, label);
5835:     }
5836:   }
5837:   return 0;
5838: }

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

5843:   Collective on dm

5845:   Input Parameter:
5846: . dm - The DM

5848:   Output Parameter:
5849: . newdm - The DM

5851:   Level: advanced

5853: .seealso: DMCopyFields(), DMCopyDS()
5854: @*/
5855: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5856: {
5857:   DMCopyFields(dm, newdm);
5858:   DMCopyDS(dm, newdm);
5859:   return 0;
5860: }

5862: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5863: {
5864:   DM dm_coord,dmc_coord;
5865:   Vec coords,ccoords;
5866:   Mat inject;
5867:   DMGetCoordinateDM(dm,&dm_coord);
5868:   DMGetCoordinateDM(dmc,&dmc_coord);
5869:   DMGetCoordinates(dm,&coords);
5870:   DMGetCoordinates(dmc,&ccoords);
5871:   if (coords && !ccoords) {
5872:     DMCreateGlobalVector(dmc_coord,&ccoords);
5873:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5874:     DMCreateInjection(dmc_coord,dm_coord,&inject);
5875:     MatRestrict(inject,coords,ccoords);
5876:     MatDestroy(&inject);
5877:     DMSetCoordinates(dmc,ccoords);
5878:     VecDestroy(&ccoords);
5879:   }
5880:   return 0;
5881: }

5883: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5884: {
5885:   DM dm_coord,subdm_coord;
5886:   Vec coords,ccoords,clcoords;
5887:   VecScatter *scat_i,*scat_g;
5888:   DMGetCoordinateDM(dm,&dm_coord);
5889:   DMGetCoordinateDM(subdm,&subdm_coord);
5890:   DMGetCoordinates(dm,&coords);
5891:   DMGetCoordinates(subdm,&ccoords);
5892:   if (coords && !ccoords) {
5893:     DMCreateGlobalVector(subdm_coord,&ccoords);
5894:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
5895:     DMCreateLocalVector(subdm_coord,&clcoords);
5896:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
5897:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
5898:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5899:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
5900:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5901:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
5902:     DMSetCoordinates(subdm,ccoords);
5903:     DMSetCoordinatesLocal(subdm,clcoords);
5904:     VecScatterDestroy(&scat_i[0]);
5905:     VecScatterDestroy(&scat_g[0]);
5906:     VecDestroy(&ccoords);
5907:     VecDestroy(&clcoords);
5908:     PetscFree(scat_i);
5909:     PetscFree(scat_g);
5910:   }
5911:   return 0;
5912: }

5914: /*@
5915:   DMGetDimension - Return the topological dimension of the DM

5917:   Not collective

5919:   Input Parameter:
5920: . dm - The DM

5922:   Output Parameter:
5923: . dim - The topological dimension

5925:   Level: beginner

5927: .seealso: DMSetDimension(), DMCreate()
5928: @*/
5929: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5930: {
5933:   *dim = dm->dim;
5934:   return 0;
5935: }

5937: /*@
5938:   DMSetDimension - Set the topological dimension of the DM

5940:   Collective on dm

5942:   Input Parameters:
5943: + dm - The DM
5944: - dim - The topological dimension

5946:   Level: beginner

5948: .seealso: DMGetDimension(), DMCreate()
5949: @*/
5950: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5951: {
5952:   PetscDS        ds;
5953:   PetscInt       Nds, n;

5957:   dm->dim = dim;
5958:   if (dm->dim >= 0) {
5959:     DMGetNumDS(dm, &Nds);
5960:     for (n = 0; n < Nds; ++n) {
5961:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
5962:       if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
5963:     }
5964:   }
5965:   return 0;
5966: }

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

5971:   Collective on dm

5973:   Input Parameters:
5974: + dm - the DM
5975: - dim - the dimension

5977:   Output Parameters:
5978: + pStart - The first point of the given dimension
5979: - pEnd - The first point following points of the given dimension

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

5986:   Level: intermediate

5988: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5989: @*/
5990: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5991: {
5992:   PetscInt       d;

5995:   DMGetDimension(dm, &d);
5998:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
5999:   return 0;
6000: }

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

6005:   Collective on dm

6007:   Input Parameters:
6008: + dm - the DM
6009: - c - coordinate vector

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

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

6016:   Level: intermediate

6018: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6019: @*/
6020: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6021: {
6024:   PetscObjectReference((PetscObject) c);
6025:   VecDestroy(&dm->coordinates);
6026:   dm->coordinates = c;
6027:   VecDestroy(&dm->coordinatesLocal);
6028:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
6029:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
6030:   return 0;
6031: }

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

6036:   Not collective

6038:    Input Parameters:
6039: +  dm - the DM
6040: -  c - coordinate vector

6042:   Notes:
6043:   The coordinates of ghost points can be set using DMSetCoordinates()
6044:   followed by DMGetCoordinatesLocal(). This is intended to enable the
6045:   setting of ghost coordinates outside of the domain.

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

6049:   Level: intermediate

6051: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
6052: @*/
6053: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6054: {
6057:   PetscObjectReference((PetscObject) c);
6058:   VecDestroy(&dm->coordinatesLocal);

6060:   dm->coordinatesLocal = c;

6062:   VecDestroy(&dm->coordinates);
6063:   return 0;
6064: }

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

6069:   Collective on dm

6071:   Input Parameter:
6072: . dm - the DM

6074:   Output Parameter:
6075: . c - global coordinate vector

6077:   Note:
6078:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6079:   destroyed the array will no longer be valid.

6081:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

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

6086:   Level: intermediate

6088: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
6089: @*/
6090: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6091: {
6094:   if (!dm->coordinates && dm->coordinatesLocal) {
6095:     DM        cdm = NULL;
6096:     PetscBool localized;

6098:     DMGetCoordinateDM(dm, &cdm);
6099:     DMCreateGlobalVector(cdm, &dm->coordinates);
6100:     DMGetCoordinatesLocalized(dm, &localized);
6101:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6102:     if (localized) {
6103:       PetscInt cdim;

6105:       DMGetCoordinateDim(dm, &cdim);
6106:       VecSetBlockSize(dm->coordinates, cdim);
6107:     }
6108:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
6109:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6110:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
6111:   }
6112:   *c = dm->coordinates;
6113:   return 0;
6114: }

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

6119:   Collective on dm

6121:   Input Parameter:
6122: . dm - the DM

6124:   Level: advanced

6126: .seealso: DMGetCoordinatesLocalNoncollective()
6127: @*/
6128: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6129: {
6131:   if (!dm->coordinatesLocal && dm->coordinates) {
6132:     DM        cdm = NULL;
6133:     PetscBool localized;

6135:     DMGetCoordinateDM(dm, &cdm);
6136:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
6137:     DMGetCoordinatesLocalized(dm, &localized);
6138:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6139:     if (localized) {
6140:       PetscInt cdim;

6142:       DMGetCoordinateDim(dm, &cdim);
6143:       VecSetBlockSize(dm->coordinates, cdim);
6144:     }
6145:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
6146:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6147:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
6148:   }
6149:   return 0;
6150: }

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

6155:   Collective on dm

6157:   Input Parameter:
6158: . dm - the DM

6160:   Output Parameter:
6161: . c - coordinate vector

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

6166:   Each process has the local and ghost coordinates

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

6171:   Level: intermediate

6173: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6174: @*/
6175: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6176: {
6179:   DMGetCoordinatesLocalSetUp(dm);
6180:   *c = dm->coordinatesLocal;
6181:   return 0;
6182: }

6184: /*@
6185:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

6187:   Not collective

6189:   Input Parameter:
6190: . dm - the DM

6192:   Output Parameter:
6193: . c - coordinate vector

6195:   Level: advanced

6197: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6198: @*/
6199: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6200: {
6204:   *c = dm->coordinatesLocal;
6205:   return 0;
6206: }

6208: /*@
6209:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

6211:   Not collective

6213:   Input Parameters:
6214: + dm - the DM
6215: - p - the IS of points whose coordinates will be returned

6217:   Output Parameters:
6218: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6219: - pCoord - the Vec with coordinates of points in p

6221:   Note:
6222:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

6224:   This creates a new vector, so the user SHOULD destroy this vector

6226:   Each process has the local and ghost coordinates

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

6231:   Level: advanced

6233: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6234: @*/
6235: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6236: {
6237:   PetscSection        cs, newcs;
6238:   Vec                 coords;
6239:   const PetscScalar   *arr;
6240:   PetscScalar         *newarr=NULL;
6241:   PetscInt            n;

6249:   cs = dm->coordinateDM->localSection;
6250:   coords = dm->coordinatesLocal;
6251:   VecGetArrayRead(coords, &arr);
6252:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
6253:   VecRestoreArrayRead(coords, &arr);
6254:   if (pCoord) {
6255:     PetscSectionGetStorageSize(newcs, &n);
6256:     /* set array in two steps to mimic PETSC_OWN_POINTER */
6257:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
6258:     VecReplaceArray(*pCoord, newarr);
6259:   } else {
6260:     PetscFree(newarr);
6261:   }
6262:   if (pCoordSection) {*pCoordSection = newcs;}
6263:   else               PetscSectionDestroy(&newcs);
6264:   return 0;
6265: }

6267: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6268: {
6271:   if (!dm->coordinateField) {
6272:     if (dm->ops->createcoordinatefield) {
6273:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
6274:     }
6275:   }
6276:   *field = dm->coordinateField;
6277:   return 0;
6278: }

6280: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6281: {
6284:   PetscObjectReference((PetscObject)field);
6285:   DMFieldDestroy(&dm->coordinateField);
6286:   dm->coordinateField = field;
6287:   return 0;
6288: }

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

6293:   Collective on dm

6295:   Input Parameter:
6296: . dm - the DM

6298:   Output Parameter:
6299: . cdm - coordinate DM

6301:   Level: intermediate

6303: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6304: @*/
6305: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6306: {
6309:   if (!dm->coordinateDM) {
6310:     DM cdm;

6313:     (*dm->ops->createcoordinatedm)(dm, &cdm);
6314:     PetscObjectSetName((PetscObject)cdm, "coordinateDM");
6315:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6316:      * until the call to CreateCoordinateDM) */
6317:     DMDestroy(&dm->coordinateDM);
6318:     dm->coordinateDM = cdm;
6319:   }
6320:   *cdm = dm->coordinateDM;
6321:   return 0;
6322: }

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

6327:   Logically Collective on dm

6329:   Input Parameters:
6330: + dm - the DM
6331: - cdm - coordinate DM

6333:   Level: intermediate

6335: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6336: @*/
6337: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6338: {
6341:   PetscObjectReference((PetscObject)cdm);
6342:   DMDestroy(&dm->coordinateDM);
6343:   dm->coordinateDM = cdm;
6344:   return 0;
6345: }

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

6350:   Not Collective

6352:   Input Parameter:
6353: . dm - The DM object

6355:   Output Parameter:
6356: . dim - The embedding dimension

6358:   Level: intermediate

6360: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6361: @*/
6362: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6363: {
6366:   if (dm->dimEmbed == PETSC_DEFAULT) {
6367:     dm->dimEmbed = dm->dim;
6368:   }
6369:   *dim = dm->dimEmbed;
6370:   return 0;
6371: }

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

6376:   Not Collective

6378:   Input Parameters:
6379: + dm  - The DM object
6380: - dim - The embedding dimension

6382:   Level: intermediate

6384: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6385: @*/
6386: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6387: {
6388:   PetscDS        ds;
6389:   PetscInt       Nds, n;

6392:   dm->dimEmbed = dim;
6393:   if (dm->dim >= 0) {
6394:     DMGetNumDS(dm, &Nds);
6395:     for (n = 0; n < Nds; ++n) {
6396:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6397:       PetscDSSetCoordinateDimension(ds, dim);
6398:     }
6399:   }
6400:   return 0;
6401: }

6403: /*@
6404:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

6406:   Collective on dm

6408:   Input Parameter:
6409: . dm - The DM object

6411:   Output Parameter:
6412: . section - The PetscSection object

6414:   Level: intermediate

6416: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6417: @*/
6418: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6419: {
6420:   DM             cdm;

6424:   DMGetCoordinateDM(dm, &cdm);
6425:   DMGetLocalSection(cdm, section);
6426:   return 0;
6427: }

6429: /*@
6430:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

6432:   Not Collective

6434:   Input Parameters:
6435: + dm      - The DM object
6436: . dim     - The embedding dimension, or PETSC_DETERMINE
6437: - section - The PetscSection object

6439:   Level: intermediate

6441: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6442: @*/
6443: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6444: {
6445:   DM             cdm;

6449:   DMGetCoordinateDM(dm, &cdm);
6450:   DMSetLocalSection(cdm, section);
6451:   if (dim == PETSC_DETERMINE) {
6452:     PetscInt d = PETSC_DEFAULT;
6453:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

6455:     PetscSectionGetChart(section, &pStart, &pEnd);
6456:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
6457:     pStart = PetscMax(vStart, pStart);
6458:     pEnd   = PetscMin(vEnd, pEnd);
6459:     for (v = pStart; v < pEnd; ++v) {
6460:       PetscSectionGetDof(section, v, &dd);
6461:       if (dd) {d = dd; break;}
6462:     }
6463:     if (d >= 0) DMSetCoordinateDim(dm, d);
6464:   }
6465:   return 0;
6466: }

6468: /*@
6469:   DMProjectCoordinates - Project coordinates to a different space

6471:   Input Parameters:
6472: + dm      - The DM object
6473: - disc    - The new coordinate discretization or NULL to ensure a coordinate discretization exists

6475:   Level: intermediate

6477: .seealso: DMGetCoordinateField()
6478: @*/
6479: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6480: {
6481:   PetscFE        discOld;
6482:   PetscClassId   classid;
6483:   DM             cdmOld,cdmNew;
6484:   Vec            coordsOld,coordsNew;
6485:   Mat            matInterp;
6486:   PetscBool      same_space = PETSC_TRUE;


6491:   DMGetCoordinateDM(dm, &cdmOld);
6492:   /* Check current discretization is compatible */
6493:   DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
6494:   PetscObjectGetClassId((PetscObject)discOld, &classid);
6495:   if (classid != PETSCFE_CLASSID) {
6496:     if (classid == PETSC_CONTAINER_CLASSID) {
6497:       PetscFE        feLinear;
6498:       DMPolytopeType ct;
6499:       PetscInt       dim, dE, cStart, cEnd;
6500:       PetscBool      simplex;

6502:       /* Assume linear vertex coordinates */
6503:       DMGetDimension(dm, &dim);
6504:       DMGetCoordinateDim(dm, &dE);
6505:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
6506:       if (cEnd > cStart) {
6507:         DMPlexGetCellType(dm, cStart, &ct);
6508:         switch (ct) {
6509:           case DM_POLYTOPE_TRI_PRISM:
6510:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
6511:             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6512:           default: break;
6513:         }
6514:       }
6515:       DMPlexIsSimplex(dm, &simplex);
6516:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
6517:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
6518:       PetscFEDestroy(&feLinear);
6519:       DMCreateDS(cdmOld);
6520:       DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
6521:     } else {
6522:       const char *discname;

6524:       PetscObjectGetType((PetscObject)discOld, &discname);
6525:       SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6526:     }
6527:   }
6528:   if (!disc) return 0;
6529:   { // Check if the new space is the same as the old modulo quadrature
6530:     PetscDualSpace dsOld, ds;
6531:     PetscFEGetDualSpace(discOld, &dsOld);
6532:     PetscFEGetDualSpace(disc, &ds);
6533:     PetscDualSpaceEqual(dsOld, ds, &same_space);
6534:   }
6535:   /* Make a fresh clone of the coordinate DM */
6536:   DMClone(cdmOld, &cdmNew);
6537:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
6538:   DMCreateDS(cdmNew);
6539:   DMGetCoordinates(dm, &coordsOld);
6540:   if (same_space) {
6541:     PetscObjectReference((PetscObject)coordsOld);
6542:     coordsNew = coordsOld;
6543:   } else { // Project the coordinate vector from old to new space
6544:     DMCreateGlobalVector(cdmNew, &coordsNew);
6545:     DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
6546:     MatInterpolate(matInterp, coordsOld, coordsNew);
6547:     MatDestroy(&matInterp);
6548:   }
6549:   /* Set new coordinate structures */
6550:   DMSetCoordinateField(dm, NULL);
6551:   DMSetCoordinateDM(dm, cdmNew);
6552:   DMSetCoordinates(dm, coordsNew);
6553:   VecDestroy(&coordsNew);
6554:   DMDestroy(&cdmNew);
6555:   return 0;
6556: }

6558: /*@C
6559:   DMGetPeriodicity - Get the description of mesh periodicity

6561:   Input Parameter:
6562: . dm      - The DM object

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

6570:   Level: developer

6572: .seealso: DMGetPeriodicity()
6573: @*/
6574: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6575: {
6577:   if (per)     *per     = dm->periodic;
6578:   if (L)       *L       = dm->L;
6579:   if (maxCell) *maxCell = dm->maxCell;
6580:   if (bd)      *bd      = dm->bdtype;
6581:   return 0;
6582: }

6584: /*@C
6585:   DMSetPeriodicity - Set the description of mesh periodicity

6587:   Input Parameters:
6588: + dm      - The DM object
6589: . per     - Whether the DM is periodic or not.
6590: . 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.
6591: . L       - If we assume the mesh is a torus, this is the length of each coordinate
6592: - bd      - This describes the type of periodicity in each topological dimension

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

6596:   Level: developer

6598: .seealso: DMGetPeriodicity()
6599: @*/
6600: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6601: {
6602:   PetscInt       dim, d;

6609:   DMGetDimension(dm, &dim);
6610:   if (maxCell) {
6611:     if (!dm->maxCell) PetscMalloc1(dim, &dm->maxCell);
6612:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6613:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6614:     PetscFree(dm->maxCell);
6615:   }

6617:   if (L) {
6618:     if (!dm->L) PetscMalloc1(dim, &dm->L);
6619:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6620:   }
6621:   if (bd) {
6622:     if (!dm->bdtype) PetscMalloc1(dim, &dm->bdtype);
6623:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6624:   }
6625:   dm->periodic = per;
6626:   return 0;
6627: }

6629: /*@
6630:   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.

6632:   Input Parameters:
6633: + dm     - The DM
6634: . in     - The input coordinate point (dim numbers)
6635: - endpoint - Include the endpoint L_i

6637:   Output Parameter:
6638: . out - The localized coordinate point

6640:   Level: developer

6642: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6643: @*/
6644: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6645: {
6646:   PetscInt       dim, d;

6648:   DMGetCoordinateDim(dm, &dim);
6649:   if (!dm->maxCell) {
6650:     for (d = 0; d < dim; ++d) out[d] = in[d];
6651:   } else {
6652:     if (endpoint) {
6653:       for (d = 0; d < dim; ++d) {
6654:         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)) {
6655:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6656:         } else {
6657:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6658:         }
6659:       }
6660:     } else {
6661:       for (d = 0; d < dim; ++d) {
6662:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6663:       }
6664:     }
6665:   }
6666:   return 0;
6667: }

6669: /*
6670:   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.

6672:   Input Parameters:
6673: + dm     - The DM
6674: . dim    - The spatial dimension
6675: . anchor - The anchor point, the input point can be no more than maxCell away from it
6676: - in     - The input coordinate point (dim numbers)

6678:   Output Parameter:
6679: . out - The localized coordinate point

6681:   Level: developer

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

6685: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6686: */
6687: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6688: {
6689:   PetscInt d;

6691:   if (!dm->maxCell) {
6692:     for (d = 0; d < dim; ++d) out[d] = in[d];
6693:   } else {
6694:     for (d = 0; d < dim; ++d) {
6695:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6696:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6697:       } else {
6698:         out[d] = in[d];
6699:       }
6700:     }
6701:   }
6702:   return 0;
6703: }

6705: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6706: {
6707:   PetscInt d;

6709:   if (!dm->maxCell) {
6710:     for (d = 0; d < dim; ++d) out[d] = in[d];
6711:   } else {
6712:     for (d = 0; d < dim; ++d) {
6713:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6714:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6715:       } else {
6716:         out[d] = in[d];
6717:       }
6718:     }
6719:   }
6720:   return 0;
6721: }

6723: /*
6724:   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.

6726:   Input Parameters:
6727: + dm     - The DM
6728: . dim    - The spatial dimension
6729: . anchor - The anchor point, the input point can be no more than maxCell away from it
6730: . in     - The input coordinate delta (dim numbers)
6731: - out    - The input coordinate point (dim numbers)

6733:   Output Parameter:
6734: . out    - The localized coordinate in + out

6736:   Level: developer

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

6740: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6741: */
6742: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6743: {
6744:   PetscInt d;

6746:   if (!dm->maxCell) {
6747:     for (d = 0; d < dim; ++d) out[d] += in[d];
6748:   } else {
6749:     for (d = 0; d < dim; ++d) {
6750:       const PetscReal maxC = dm->maxCell[d];

6752:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6753:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

6755:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6756:           SETERRQ(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]));
6757:         out[d] += newCoord;
6758:       } else {
6759:         out[d] += in[d];
6760:       }
6761:     }
6762:   }
6763:   return 0;
6764: }

6766: /*@
6767:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

6769:   Not collective

6771:   Input Parameter:
6772: . dm - The DM

6774:   Output Parameter:
6775:   areLocalized - True if localized

6777:   Level: developer

6779: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6780: @*/
6781: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6782: {
6783:   DM             cdm;
6784:   PetscSection   coordSection;
6785:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
6786:   PetscBool      isPlex, alreadyLocalized;

6790:   *areLocalized = PETSC_FALSE;

6792:   /* We need some generic way of refering to cells/vertices */
6793:   DMGetCoordinateDM(dm, &cdm);
6794:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
6795:   if (!isPlex) return 0;
6796:   DMPlexGetDepth(cdm, &depth);
6797:   if (!depth) return 0;

6799:   DMGetCoordinateSection(dm, &coordSection);
6800:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
6801:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
6802:   alreadyLocalized = PETSC_FALSE;
6803:   for (c = cStart; c < cEnd; ++c) {
6804:     if (c < sStart || c >= sEnd) continue;
6805:     PetscSectionGetDof(coordSection, c, &dof);
6806:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6807:   }
6808:   *areLocalized = alreadyLocalized;
6809:   return 0;
6810: }

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

6815:   Collective on dm

6817:   Input Parameter:
6818: . dm - The DM

6820:   Output Parameter:
6821:   areLocalized - True if localized

6823:   Level: developer

6825: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6826: @*/
6827: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6828: {
6829:   PetscBool      localized;

6833:   DMGetCoordinatesLocalizedLocal(dm,&localized);
6834:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
6835:   return 0;
6836: }

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

6841:   Collective on dm

6843:   Input Parameter:
6844: . dm - The DM

6846:   Level: developer

6848: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6849: @*/
6850: PetscErrorCode DMLocalizeCoordinates(DM dm)
6851: {
6852:   DM             cdm;
6853:   PetscSection   coordSection, cSection;
6854:   Vec            coordinates,  cVec;
6855:   PetscScalar   *coords, *coords2, *anchor, *localized;
6856:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6857:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6858:   PetscInt       maxHeight = 0, h;
6859:   PetscInt       *pStart = NULL, *pEnd = NULL;

6862:   if (!dm->periodic) return 0;
6863:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
6864:   if (alreadyLocalized) return 0;

6866:   /* We need some generic way of refering to cells/vertices */
6867:   DMGetCoordinateDM(dm, &cdm);
6868:   {
6869:     PetscBool isplex;

6871:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
6872:     if (isplex) {
6873:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
6874:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
6875:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6876:       pEnd = &pStart[maxHeight + 1];
6877:       newStart = vStart;
6878:       newEnd   = vEnd;
6879:       for (h = 0; h <= maxHeight; h++) {
6880:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
6881:         newStart = PetscMin(newStart,pStart[h]);
6882:         newEnd   = PetscMax(newEnd,pEnd[h]);
6883:       }
6884:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6885:   }
6886:   DMGetCoordinatesLocal(dm, &coordinates);
6888:   DMGetCoordinateSection(dm, &coordSection);
6889:   VecGetBlockSize(coordinates, &bs);
6890:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

6892:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
6893:   PetscSectionSetNumFields(cSection, 1);
6894:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
6895:   PetscSectionSetFieldComponents(cSection, 0, Nc);
6896:   PetscSectionSetChart(cSection, newStart, newEnd);

6898:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6899:   localized = &anchor[bs];
6900:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6901:   for (h = 0; h <= maxHeight; h++) {
6902:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6904:     for (c = cStart; c < cEnd; ++c) {
6905:       PetscScalar *cellCoords = NULL;
6906:       PetscInt     b;

6908:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6909:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6910:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6911:       for (d = 0; d < dof/bs; ++d) {
6912:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
6913:         for (b = 0; b < bs; b++) {
6914:           if (cellCoords[d*bs + b] != localized[b]) break;
6915:         }
6916:         if (b < bs) break;
6917:       }
6918:       if (d < dof/bs) {
6919:         if (c >= sStart && c < sEnd) {
6920:           PetscInt cdof;

6922:           PetscSectionGetDof(coordSection, c, &cdof);
6923:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6924:         }
6925:         PetscSectionSetDof(cSection, c, dof);
6926:         PetscSectionSetFieldDof(cSection, c, 0, dof);
6927:       }
6928:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6929:     }
6930:   }
6931:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
6932:   if (alreadyLocalizedGlobal) {
6933:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6934:     PetscSectionDestroy(&cSection);
6935:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6936:     return 0;
6937:   }
6938:   for (v = vStart; v < vEnd; ++v) {
6939:     PetscSectionGetDof(coordSection, v, &dof);
6940:     PetscSectionSetDof(cSection, v, dof);
6941:     PetscSectionSetFieldDof(cSection, v, 0, dof);
6942:   }
6943:   PetscSectionSetUp(cSection);
6944:   PetscSectionGetStorageSize(cSection, &coordSize);
6945:   VecCreate(PETSC_COMM_SELF, &cVec);
6946:   PetscObjectSetName((PetscObject)cVec,"coordinates");
6947:   VecSetBlockSize(cVec, bs);
6948:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
6949:   VecSetType(cVec, VECSTANDARD);
6950:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
6951:   VecGetArray(cVec, &coords2);
6952:   for (v = vStart; v < vEnd; ++v) {
6953:     PetscSectionGetDof(coordSection, v, &dof);
6954:     PetscSectionGetOffset(coordSection, v, &off);
6955:     PetscSectionGetOffset(cSection,     v, &off2);
6956:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6957:   }
6958:   for (h = 0; h <= maxHeight; h++) {
6959:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

6961:     for (c = cStart; c < cEnd; ++c) {
6962:       PetscScalar *cellCoords = NULL;
6963:       PetscInt     b, cdof;

6965:       PetscSectionGetDof(cSection,c,&cdof);
6966:       if (!cdof) continue;
6967:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6968:       PetscSectionGetOffset(cSection, c, &off2);
6969:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6970:       for (d = 0; d < dof/bs; ++d) DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);
6971:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
6972:     }
6973:   }
6974:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
6975:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
6976:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
6977:   VecRestoreArray(cVec, &coords2);
6978:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
6979:   DMSetCoordinatesLocal(dm, cVec);
6980:   VecDestroy(&cVec);
6981:   PetscSectionDestroy(&cSection);
6982:   return 0;
6983: }

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

6988:   Collective on v (see explanation below)

6990:   Input Parameters:
6991: + dm - The DM
6992: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

6994:   Input/Output Parameters:
6995: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6996: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
6997:            on output, the PetscSF containing the ranks and local indices of the containing points

6999:   Level: developer

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

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

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

7010: $    const PetscSFNode *cells;
7011: $    PetscInt           nFound;
7012: $    const PetscInt    *found;
7013: $
7014: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

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

7019: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
7020: @*/
7021: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7022: {
7026:   if (*cellSF) {
7027:     PetscMPIInt result;

7030:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
7032:   } else {
7033:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
7034:   }
7036:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
7037:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
7038:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
7039:   return 0;
7040: }

7042: /*@
7043:   DMGetOutputDM - Retrieve the DM associated with the layout for output

7045:   Collective on dm

7047:   Input Parameter:
7048: . dm - The original DM

7050:   Output Parameter:
7051: . odm - The DM which provides the layout for output

7053:   Level: intermediate

7055: .seealso: VecView(), DMGetGlobalSection()
7056: @*/
7057: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7058: {
7059:   PetscSection   section;
7060:   PetscBool      hasConstraints, ghasConstraints;

7064:   DMGetLocalSection(dm, &section);
7065:   PetscSectionHasConstraints(section, &hasConstraints);
7066:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
7067:   if (!ghasConstraints) {
7068:     *odm = dm;
7069:     return 0;
7070:   }
7071:   if (!dm->dmBC) {
7072:     PetscSection newSection, gsection;
7073:     PetscSF      sf;

7075:     DMClone(dm, &dm->dmBC);
7076:     DMCopyDisc(dm, dm->dmBC);
7077:     PetscSectionClone(section, &newSection);
7078:     DMSetLocalSection(dm->dmBC, newSection);
7079:     PetscSectionDestroy(&newSection);
7080:     DMGetPointSF(dm->dmBC, &sf);
7081:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
7082:     DMSetGlobalSection(dm->dmBC, gsection);
7083:     PetscSectionDestroy(&gsection);
7084:   }
7085:   *odm = dm->dmBC;
7086:   return 0;
7087: }

7089: /*@
7090:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

7092:   Input Parameter:
7093: . dm - The original DM

7095:   Output Parameters:
7096: + num - The output sequence number
7097: - val - The output sequence value

7099:   Level: intermediate

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

7104: .seealso: VecView()
7105: @*/
7106: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7107: {
7111:   return 0;
7112: }

7114: /*@
7115:   DMSetOutputSequenceNumber - Set the sequence number/value for output

7117:   Input Parameters:
7118: + dm - The original DM
7119: . num - The output sequence number
7120: - val - The output sequence value

7122:   Level: intermediate

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

7127: .seealso: VecView()
7128: @*/
7129: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7130: {
7132:   dm->outputSequenceNum = num;
7133:   dm->outputSequenceVal = val;
7134:   return 0;
7135: }

7137: /*@C
7138:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

7140:   Input Parameters:
7141: + dm   - The original DM
7142: . name - The sequence name
7143: - num  - The output sequence number

7145:   Output Parameter:
7146: . val  - The output sequence value

7148:   Level: intermediate

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

7153: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7154: @*/
7155: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7156: {
7157:   PetscBool      ishdf5;

7162:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
7163:   if (ishdf5) {
7164: #if defined(PETSC_HAVE_HDF5)
7165:     PetscScalar value;

7167:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
7168:     *val = PetscRealPart(value);
7169: #endif
7170:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7171:   return 0;
7172: }

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

7177:   Not collective

7179:   Input Parameter:
7180: . dm - The DM

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

7185:   Level: beginner

7187: .seealso: DMSetUseNatural(), DMCreate()
7188: @*/
7189: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7190: {
7193:   *useNatural = dm->useNatural;
7194:   return 0;
7195: }

7197: /*@
7198:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

7200:   Collective on dm

7202:   Input Parameters:
7203: + dm - The DM
7204: - useNatural - The flag to build the mapping to a natural order during distribution

7206:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

7208:   Level: beginner

7210: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7211: @*/
7212: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7213: {
7216:   dm->useNatural = useNatural;
7217:   return 0;
7218: }

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

7223:   Not Collective

7225:   Input Parameters:
7226: + dm   - The DM object
7227: - name - The label name

7229:   Level: intermediate

7231: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7232: @*/
7233: PetscErrorCode DMCreateLabel(DM dm, const char name[])
7234: {
7235:   PetscBool      flg;
7236:   DMLabel        label;

7240:   DMHasLabel(dm, name, &flg);
7241:   if (!flg) {
7242:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7243:     DMAddLabel(dm, label);
7244:     DMLabelDestroy(&label);
7245:   }
7246:   return 0;
7247: }

7249: /*@C
7250:   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists, move it to this index.

7252:   Not Collective

7254:   Input Parameters:
7255: + dm   - The DM object
7256: . l    - The index for the label
7257: - name - The label name

7259:   Level: intermediate

7261: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7262: @*/
7263: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7264: {
7265:   DMLabelLink    orig, prev = NULL;
7266:   DMLabel        label;
7267:   PetscInt       Nl, m;
7268:   PetscBool      flg, match;
7269:   const char    *lname;

7273:   DMHasLabel(dm, name, &flg);
7274:   if (!flg) {
7275:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
7276:     DMAddLabel(dm, label);
7277:     DMLabelDestroy(&label);
7278:   }
7279:   DMGetNumLabels(dm, &Nl);
7281:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7282:     PetscObjectGetName((PetscObject) orig->label, &lname);
7283:     PetscStrcmp(name, lname, &match);
7284:     if (match) break;
7285:   }
7286:   if (m == l) return 0;
7287:   if (!m) dm->labels = orig->next;
7288:   else    prev->next = orig->next;
7289:   if (!l) {
7290:     orig->next = dm->labels;
7291:     dm->labels = orig;
7292:   } else {
7293:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7294:     orig->next = prev->next;
7295:     prev->next = orig;
7296:   }
7297:   return 0;
7298: }

7300: /*@C
7301:   DMGetLabelValue - Get the value in a DMLabel for the given point, with -1 as the default

7303:   Not Collective

7305:   Input Parameters:
7306: + dm   - The DM object
7307: . name - The label name
7308: - point - The mesh point

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

7313:   Level: beginner

7315: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7316: @*/
7317: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7318: {
7319:   DMLabel        label;

7323:   DMGetLabel(dm, name, &label);
7325:   DMLabelGetValue(label, point, value);
7326:   return 0;
7327: }

7329: /*@C
7330:   DMSetLabelValue - Add a point to a DMLabel with given value

7332:   Not Collective

7334:   Input Parameters:
7335: + dm   - The DM object
7336: . name - The label name
7337: . point - The mesh point
7338: - value - The label value for this point

7340:   Output Parameter:

7342:   Level: beginner

7344: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7345: @*/
7346: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7347: {
7348:   DMLabel        label;

7352:   DMGetLabel(dm, name, &label);
7353:   if (!label) {
7354:     DMCreateLabel(dm, name);
7355:     DMGetLabel(dm, name, &label);
7356:   }
7357:   DMLabelSetValue(label, point, value);
7358:   return 0;
7359: }

7361: /*@C
7362:   DMClearLabelValue - Remove a point from a DMLabel with given value

7364:   Not Collective

7366:   Input Parameters:
7367: + dm   - The DM object
7368: . name - The label name
7369: . point - The mesh point
7370: - value - The label value for this point

7372:   Output Parameter:

7374:   Level: beginner

7376: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7377: @*/
7378: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7379: {
7380:   DMLabel        label;

7384:   DMGetLabel(dm, name, &label);
7385:   if (!label) return 0;
7386:   DMLabelClearValue(label, point, value);
7387:   return 0;
7388: }

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

7393:   Not Collective

7395:   Input Parameters:
7396: + dm   - The DM object
7397: - name - The label name

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

7402:   Level: beginner

7404: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7405: @*/
7406: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7407: {
7408:   DMLabel        label;

7413:   DMGetLabel(dm, name, &label);
7414:   *size = 0;
7415:   if (!label) return 0;
7416:   DMLabelGetNumValues(label, size);
7417:   return 0;
7418: }

7420: /*@C
7421:   DMGetLabelIdIS - Get the integer ids in a label

7423:   Not Collective

7425:   Input Parameters:
7426: + mesh - The DM object
7427: - name - The label name

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

7432:   Level: beginner

7434: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7435: @*/
7436: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7437: {
7438:   DMLabel        label;

7443:   DMGetLabel(dm, name, &label);
7444:   *ids = NULL;
7445:   if (label) {
7446:     DMLabelGetValueIS(label, ids);
7447:   } else {
7448:     /* returning an empty IS */
7449:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
7450:   }
7451:   return 0;
7452: }

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

7457:   Not Collective

7459:   Input Parameters:
7460: + dm - The DM object
7461: . name - The label name
7462: - value - The stratum value

7464:   Output Parameter:
7465: . size - The stratum size

7467:   Level: beginner

7469: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7470: @*/
7471: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7472: {
7473:   DMLabel        label;

7478:   DMGetLabel(dm, name, &label);
7479:   *size = 0;
7480:   if (!label) return 0;
7481:   DMLabelGetStratumSize(label, value, size);
7482:   return 0;
7483: }

7485: /*@C
7486:   DMGetStratumIS - Get the points in a label stratum

7488:   Not Collective

7490:   Input Parameters:
7491: + dm - The DM object
7492: . name - The label name
7493: - value - The stratum value

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

7498:   Level: beginner

7500: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7501: @*/
7502: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7503: {
7504:   DMLabel        label;

7509:   DMGetLabel(dm, name, &label);
7510:   *points = NULL;
7511:   if (!label) return 0;
7512:   DMLabelGetStratumIS(label, value, points);
7513:   return 0;
7514: }

7516: /*@C
7517:   DMSetStratumIS - Set the points in a label stratum

7519:   Not Collective

7521:   Input Parameters:
7522: + dm - The DM object
7523: . name - The label name
7524: . value - The stratum value
7525: - points - The stratum points

7527:   Level: beginner

7529: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7530: @*/
7531: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7532: {
7533:   DMLabel        label;

7538:   DMGetLabel(dm, name, &label);
7539:   if (!label) return 0;
7540:   DMLabelSetStratumIS(label, value, points);
7541:   return 0;
7542: }

7544: /*@C
7545:   DMClearLabelStratum - Remove all points from a stratum from a DMLabel

7547:   Not Collective

7549:   Input Parameters:
7550: + dm   - The DM object
7551: . name - The label name
7552: - value - The label value for this point

7554:   Output Parameter:

7556:   Level: beginner

7558: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7559: @*/
7560: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7561: {
7562:   DMLabel        label;

7566:   DMGetLabel(dm, name, &label);
7567:   if (!label) return 0;
7568:   DMLabelClearStratum(label, value);
7569:   return 0;
7570: }

7572: /*@
7573:   DMGetNumLabels - Return the number of labels defined by the mesh

7575:   Not Collective

7577:   Input Parameter:
7578: . dm   - The DM object

7580:   Output Parameter:
7581: . numLabels - the number of Labels

7583:   Level: intermediate

7585: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7586: @*/
7587: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7588: {
7589:   DMLabelLink next = dm->labels;
7590:   PetscInt  n    = 0;

7594:   while (next) {++n; next = next->next;}
7595:   *numLabels = n;
7596:   return 0;
7597: }

7599: /*@C
7600:   DMGetLabelName - Return the name of nth label

7602:   Not Collective

7604:   Input Parameters:
7605: + dm - The DM object
7606: - n  - the label number

7608:   Output Parameter:
7609: . name - the label name

7611:   Level: intermediate

7613: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7614: @*/
7615: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7616: {
7617:   DMLabelLink    next = dm->labels;
7618:   PetscInt       l    = 0;

7622:   while (next) {
7623:     if (l == n) {
7624:       PetscObjectGetName((PetscObject) next->label, name);
7625:       return 0;
7626:     }
7627:     ++l;
7628:     next = next->next;
7629:   }
7630:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7631: }

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

7636:   Not Collective

7638:   Input Parameters:
7639: + dm   - The DM object
7640: - name - The label name

7642:   Output Parameter:
7643: . hasLabel - PETSC_TRUE if the label is present

7645:   Level: intermediate

7647: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7648: @*/
7649: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7650: {
7651:   DMLabelLink    next = dm->labels;
7652:   const char    *lname;

7657:   *hasLabel = PETSC_FALSE;
7658:   while (next) {
7659:     PetscObjectGetName((PetscObject) next->label, &lname);
7660:     PetscStrcmp(name, lname, hasLabel);
7661:     if (*hasLabel) break;
7662:     next = next->next;
7663:   }
7664:   return 0;
7665: }

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

7670:   Not Collective

7672:   Input Parameters:
7673: + dm   - The DM object
7674: - name - The label name

7676:   Output Parameter:
7677: . label - The DMLabel, or NULL if the label is absent

7679:   Note: Some of the default labels in a DMPlex will be
7680: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7681: $ "celltype"    - Holds the topological type of each cell
7682: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7683: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7684: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7685: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7687:   Level: intermediate

7689: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7690: @*/
7691: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7692: {
7693:   DMLabelLink    next = dm->labels;
7694:   PetscBool      hasLabel;
7695:   const char    *lname;

7700:   *label = NULL;
7701:   while (next) {
7702:     PetscObjectGetName((PetscObject) next->label, &lname);
7703:     PetscStrcmp(name, lname, &hasLabel);
7704:     if (hasLabel) {
7705:       *label = next->label;
7706:       break;
7707:     }
7708:     next = next->next;
7709:   }
7710:   return 0;
7711: }

7713: /*@C
7714:   DMGetLabelByNum - Return the nth label

7716:   Not Collective

7718:   Input Parameters:
7719: + dm - The DM object
7720: - n  - the label number

7722:   Output Parameter:
7723: . label - the label

7725:   Level: intermediate

7727: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7728: @*/
7729: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7730: {
7731:   DMLabelLink next = dm->labels;
7732:   PetscInt    l    = 0;

7736:   while (next) {
7737:     if (l == n) {
7738:       *label = next->label;
7739:       return 0;
7740:     }
7741:     ++l;
7742:     next = next->next;
7743:   }
7744:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7745: }

7747: /*@C
7748:   DMAddLabel - Add the label to this mesh

7750:   Not Collective

7752:   Input Parameters:
7753: + dm   - The DM object
7754: - label - The DMLabel

7756:   Level: developer

7758: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7759: @*/
7760: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7761: {
7762:   DMLabelLink    l, *p, tmpLabel;
7763:   PetscBool      hasLabel;
7764:   const char    *lname;
7765:   PetscBool      flg;

7768:   PetscObjectGetName((PetscObject) label, &lname);
7769:   DMHasLabel(dm, lname, &hasLabel);
7771:   PetscCalloc1(1, &tmpLabel);
7772:   tmpLabel->label  = label;
7773:   tmpLabel->output = PETSC_TRUE;
7774:   for (p=&dm->labels; (l=*p); p=&l->next) {}
7775:   *p = tmpLabel;
7776:   PetscObjectReference((PetscObject)label);
7777:   PetscStrcmp(lname, "depth", &flg);
7778:   if (flg) dm->depthLabel = label;
7779:   PetscStrcmp(lname, "celltype", &flg);
7780:   if (flg) dm->celltypeLabel = label;
7781:   return 0;
7782: }

7784: /*@C
7785:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

7787:   Not Collective

7789:   Input Parameters:
7790: + dm    - The DM object
7791: - label - The DMLabel, having the same name, to substitute

7793:   Note: Some of the default labels in a DMPlex will be
7794: $ "depth"       - Holds the depth (co-dimension) of each mesh point
7795: $ "celltype"    - Holds the topological type of each cell
7796: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7797: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7798: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7799: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

7801:   Level: intermediate

7803: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
7804: @*/
7805: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7806: {
7807:   DMLabelLink    next = dm->labels;
7808:   PetscBool      hasLabel, flg;
7809:   const char    *name, *lname;

7813:   PetscObjectGetName((PetscObject) label, &name);
7814:   while (next) {
7815:     PetscObjectGetName((PetscObject) next->label, &lname);
7816:     PetscStrcmp(name, lname, &hasLabel);
7817:     if (hasLabel) {
7818:       PetscObjectReference((PetscObject) label);
7819:       PetscStrcmp(lname, "depth", &flg);
7820:       if (flg) dm->depthLabel = label;
7821:       PetscStrcmp(lname, "celltype", &flg);
7822:       if (flg) dm->celltypeLabel = label;
7823:       DMLabelDestroy(&next->label);
7824:       next->label = label;
7825:       break;
7826:     }
7827:     next = next->next;
7828:   }
7829:   return 0;
7830: }

7832: /*@C
7833:   DMRemoveLabel - Remove the label given by name from this mesh

7835:   Not Collective

7837:   Input Parameters:
7838: + dm   - The DM object
7839: - name - The label name

7841:   Output Parameter:
7842: . label - The DMLabel, or NULL if the label is absent

7844:   Level: developer

7846:   Notes:
7847:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7848:   DMLabelDestroy() on the label.

7850:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7851:   call DMLabelDestroy(). Instead, the label is returned and the user is
7852:   responsible of calling DMLabelDestroy() at some point.

7854: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7855: @*/
7856: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7857: {
7858:   DMLabelLink    link, *pnext;
7859:   PetscBool      hasLabel;
7860:   const char    *lname;

7864:   if (label) {
7866:     *label = NULL;
7867:   }
7868:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7869:     PetscObjectGetName((PetscObject) link->label, &lname);
7870:     PetscStrcmp(name, lname, &hasLabel);
7871:     if (hasLabel) {
7872:       *pnext = link->next; /* Remove from list */
7873:       PetscStrcmp(name, "depth", &hasLabel);
7874:       if (hasLabel) dm->depthLabel = NULL;
7875:       PetscStrcmp(name, "celltype", &hasLabel);
7876:       if (hasLabel) dm->celltypeLabel = NULL;
7877:       if (label) *label = link->label;
7878:       else       DMLabelDestroy(&link->label);
7879:       PetscFree(link);
7880:       break;
7881:     }
7882:   }
7883:   return 0;
7884: }

7886: /*@
7887:   DMRemoveLabelBySelf - Remove the label from this mesh

7889:   Not Collective

7891:   Input Parameters:
7892: + dm   - The DM object
7893: . label - The DMLabel to be removed from the DM
7894: - failNotFound - Should it fail if the label is not found in the DM?

7896:   Level: developer

7898:   Notes:
7899:   Only exactly the same instance is removed if found, name match is ignored.
7900:   If the DM has an exclusive reference to the label, it gets destroyed and
7901:   *label nullified.

7903: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7904: @*/
7905: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7906: {
7907:   DMLabelLink    link, *pnext;
7908:   PetscBool      hasLabel = PETSC_FALSE;

7912:   if (!*label && !failNotFound) return 0;
7915:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7916:     if (*label == link->label) {
7917:       hasLabel = PETSC_TRUE;
7918:       *pnext = link->next; /* Remove from list */
7919:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7920:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7921:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7922:       DMLabelDestroy(&link->label);
7923:       PetscFree(link);
7924:       break;
7925:     }
7926:   }
7928:   return 0;
7929: }

7931: /*@C
7932:   DMGetLabelOutput - Get the output flag for a given label

7934:   Not Collective

7936:   Input Parameters:
7937: + dm   - The DM object
7938: - name - The label name

7940:   Output Parameter:
7941: . output - The flag for output

7943:   Level: developer

7945: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7946: @*/
7947: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7948: {
7949:   DMLabelLink    next = dm->labels;
7950:   const char    *lname;

7955:   while (next) {
7956:     PetscBool flg;

7958:     PetscObjectGetName((PetscObject) next->label, &lname);
7959:     PetscStrcmp(name, lname, &flg);
7960:     if (flg) {*output = next->output; return 0;}
7961:     next = next->next;
7962:   }
7963:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7964: }

7966: /*@C
7967:   DMSetLabelOutput - Set the output flag for a given label

7969:   Not Collective

7971:   Input Parameters:
7972: + dm     - The DM object
7973: . name   - The label name
7974: - output - The flag for output

7976:   Level: developer

7978: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7979: @*/
7980: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7981: {
7982:   DMLabelLink    next = dm->labels;
7983:   const char    *lname;

7987:   while (next) {
7988:     PetscBool flg;

7990:     PetscObjectGetName((PetscObject) next->label, &lname);
7991:     PetscStrcmp(name, lname, &flg);
7992:     if (flg) {next->output = output; return 0;}
7993:     next = next->next;
7994:   }
7995:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7996: }

7998: /*@
7999:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

8001:   Collective on dmA

8003:   Input Parameters:
8004: + dmA - The DM object with initial labels
8005: . dmB - The DM object to which labels are copied
8006: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8007: . all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8008: - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode)

8010:   Level: intermediate

8012:   Notes:
8013:   This is typically used when interpolating or otherwise adding to a mesh, or testing.

8015: .seealso: DMAddLabel(), DMCopyLabelsMode
8016: @*/
8017: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
8018: {
8019:   DMLabel        label, labelNew, labelOld;
8020:   const char    *name;
8021:   PetscBool      flg;
8022:   DMLabelLink    link;

8029:   if (dmA == dmB) return 0;
8030:   for (link=dmA->labels; link; link=link->next) {
8031:     label=link->label;
8032:     PetscObjectGetName((PetscObject)label, &name);
8033:     if (!all) {
8034:       PetscStrcmp(name, "depth", &flg);
8035:       if (flg) continue;
8036:       PetscStrcmp(name, "dim", &flg);
8037:       if (flg) continue;
8038:       PetscStrcmp(name, "celltype", &flg);
8039:       if (flg) continue;
8040:     }
8041:     DMGetLabel(dmB, name, &labelOld);
8042:     if (labelOld) {
8043:       switch (emode) {
8044:         case DM_COPY_LABELS_KEEP:
8045:           continue;
8046:         case DM_COPY_LABELS_REPLACE:
8047:           DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
8048:           break;
8049:         case DM_COPY_LABELS_FAIL:
8050:           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
8051:         default:
8052:           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
8053:       }
8054:     }
8055:     if (mode==PETSC_COPY_VALUES) {
8056:       DMLabelDuplicate(label, &labelNew);
8057:     } else {
8058:       labelNew = label;
8059:     }
8060:     DMAddLabel(dmB, labelNew);
8061:     if (mode==PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
8062:   }
8063:   return 0;
8064: }

8066: /*@C
8067:   DMCompareLabels - Compare labels of two DMPlex meshes

8069:   Collective

8071:   Input Parameters:
8072: + dm0 - First DM object
8073: - dm1 - Second DM object

8075:   Output Parameters
8076: + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
8077: - message - (Optional) Message describing the difference, or NULL if there is no difference

8079:   Level: intermediate

8081:   Notes:
8082:   The output flag equal is the same on all processes.
8083:   If it is passed as NULL and difference is found, an error is thrown on all processes.
8084:   Make sure to pass NULL on all processes.

8086:   The output message is set independently on each rank.
8087:   It is set to NULL if no difference was found on the current rank. It must be freed by user.
8088:   If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner.
8089:   Make sure to pass NULL on all processes.

8091:   Labels are matched by name. If the number of labels and their names are equal,
8092:   DMLabelCompare() is used to compare each pair of labels with the same name.

8094:   Fortran Notes:
8095:   This function is currently not available from Fortran.

8097: .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare()
8098: @*/
8099: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
8100: {
8101:   PetscInt        n, i;
8102:   char            msg[PETSC_MAX_PATH_LEN] = "";
8103:   PetscBool       eq;
8104:   MPI_Comm        comm;
8105:   PetscMPIInt     rank;

8112:   PetscObjectGetComm((PetscObject)dm0, &comm);
8113:   MPI_Comm_rank(comm, &rank);
8114:   {
8115:     PetscInt n1;

8117:     DMGetNumLabels(dm0, &n);
8118:     DMGetNumLabels(dm1, &n1);
8119:     eq = (PetscBool) (n == n1);
8120:     if (!eq) {
8121:       PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %D != %D = Number of labels in dm1", n, n1);
8122:     }
8123:     MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
8124:     if (!eq) goto finish;
8125:   }
8126:   for (i=0; i<n; i++) {
8127:     DMLabel     l0, l1;
8128:     const char *name;
8129:     char       *msgInner;

8131:     /* Ignore label order */
8132:     DMGetLabelByNum(dm0, i, &l0);
8133:     PetscObjectGetName((PetscObject)l0, &name);
8134:     DMGetLabel(dm1, name, &l1);
8135:     if (!l1) {
8136:       PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%D in dm0) not found in dm1", name, i);
8137:       eq = PETSC_FALSE;
8138:       break;
8139:     }
8140:     DMLabelCompare(comm, l0, l1, &eq, &msgInner);
8141:     PetscStrncpy(msg, msgInner, sizeof(msg));
8142:     PetscFree(msgInner);
8143:     if (!eq) break;
8144:   }
8145:   MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
8146: finish:
8147:   /* If message output arg not set, print to stderr */
8148:   if (message) {
8149:     *message = NULL;
8150:     if (msg[0]) {
8151:       PetscStrallocpy(msg, message);
8152:     }
8153:   } else {
8154:     if (msg[0]) {
8155:       PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
8156:     }
8157:     PetscSynchronizedFlush(comm, PETSC_STDERR);
8158:   }
8159:   /* If same output arg not ser and labels are not equal, throw error */
8160:   if (equal) *equal = eq;
8162:   return 0;
8163: }

8165: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8166: {
8168:   if (!*label) {
8169:     DMCreateLabel(dm, name);
8170:     DMGetLabel(dm, name, label);
8171:   }
8172:   DMLabelSetValue(*label, point, value);
8173:   return 0;
8174: }

8176: /*
8177:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8178:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8179:   (label, id) pair in the DM.

8181:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8182:   each label.
8183: */
8184: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8185: {
8186:   DMUniversalLabel ul;
8187:   PetscBool       *active;
8188:   PetscInt         pStart, pEnd, p, Nl, l, m;

8190:   PetscMalloc1(1, &ul);
8191:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
8192:   DMGetNumLabels(dm, &Nl);
8193:   PetscCalloc1(Nl, &active);
8194:   ul->Nl = 0;
8195:   for (l = 0; l < Nl; ++l) {
8196:     PetscBool   isdepth, iscelltype;
8197:     const char *name;

8199:     DMGetLabelName(dm, l, &name);
8200:     PetscStrncmp(name, "depth", 6, &isdepth);
8201:     PetscStrncmp(name, "celltype", 9, &iscelltype);
8202:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8203:     if (active[l]) ++ul->Nl;
8204:   }
8205:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
8206:   ul->Nv = 0;
8207:   for (l = 0, m = 0; l < Nl; ++l) {
8208:     DMLabel     label;
8209:     PetscInt    nv;
8210:     const char *name;

8212:     if (!active[l]) continue;
8213:     DMGetLabelName(dm, l, &name);
8214:     DMGetLabelByNum(dm, l, &label);
8215:     DMLabelGetNumValues(label, &nv);
8216:     PetscStrallocpy(name, &ul->names[m]);
8217:     ul->indices[m]   = l;
8218:     ul->Nv          += nv;
8219:     ul->offsets[m+1] = nv;
8220:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8221:     ++m;
8222:   }
8223:   for (l = 1; l <= ul->Nl; ++l) {
8224:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8225:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8226:   }
8227:   for (l = 0; l < ul->Nl; ++l) {
8228:     PetscInt b;

8230:     ul->masks[l] = 0;
8231:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8232:   }
8233:   PetscMalloc1(ul->Nv, &ul->values);
8234:   for (l = 0, m = 0; l < Nl; ++l) {
8235:     DMLabel         label;
8236:     IS              valueIS;
8237:     const PetscInt *varr;
8238:     PetscInt        nv, v;

8240:     if (!active[l]) continue;
8241:     DMGetLabelByNum(dm, l, &label);
8242:     DMLabelGetNumValues(label, &nv);
8243:     DMLabelGetValueIS(label, &valueIS);
8244:     ISGetIndices(valueIS, &varr);
8245:     for (v = 0; v < nv; ++v) {
8246:       ul->values[ul->offsets[m]+v] = varr[v];
8247:     }
8248:     ISRestoreIndices(valueIS, &varr);
8249:     ISDestroy(&valueIS);
8250:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
8251:     ++m;
8252:   }
8253:   DMPlexGetChart(dm, &pStart, &pEnd);
8254:   for (p = pStart; p < pEnd; ++p) {
8255:     PetscInt  uval = 0;
8256:     PetscBool marked = PETSC_FALSE;

8258:     for (l = 0, m = 0; l < Nl; ++l) {
8259:       DMLabel  label;
8260:       PetscInt val, defval, loc, nv;

8262:       if (!active[l]) continue;
8263:       DMGetLabelByNum(dm, l, &label);
8264:       DMLabelGetValue(label, p, &val);
8265:       DMLabelGetDefaultValue(label, &defval);
8266:       if (val == defval) {++m; continue;}
8267:       nv = ul->offsets[m+1]-ul->offsets[m];
8268:       marked = PETSC_TRUE;
8269:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
8271:       uval += (loc+1) << ul->bits[m];
8272:       ++m;
8273:     }
8274:     if (marked) DMLabelSetValue(ul->label, p, uval);
8275:   }
8276:   PetscFree(active);
8277:   *universal = ul;
8278:   return 0;
8279: }

8281: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8282: {
8283:   PetscInt       l;

8285:   for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
8286:   DMLabelDestroy(&(*universal)->label);
8287:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
8288:   PetscFree((*universal)->values);
8289:   PetscFree(*universal);
8290:   *universal = NULL;
8291:   return 0;
8292: }

8294: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8295: {
8297:   *ulabel = ul->label;
8298:   return 0;
8299: }

8301: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8302: {
8303:   PetscInt       Nl = ul->Nl, l;

8306:   for (l = 0; l < Nl; ++l) {
8307:     if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
8308:     else               DMCreateLabel(dm, ul->names[l]);
8309:   }
8310:   if (preserveOrder) {
8311:     for (l = 0; l < ul->Nl; ++l) {
8312:       const char *name;
8313:       PetscBool   match;

8315:       DMGetLabelName(dm, ul->indices[l], &name);
8316:       PetscStrcmp(name, ul->names[l], &match);
8318:     }
8319:   }
8320:   return 0;
8321: }

8323: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8324: {
8325:   PetscInt       l;

8327:   for (l = 0; l < ul->Nl; ++l) {
8328:     DMLabel  label;
8329:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

8331:     if (lval) {
8332:       if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
8333:       else          DMGetLabel(dm, ul->names[l], &label);
8334:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
8335:     }
8336:   }
8337:   return 0;
8338: }

8340: /*@
8341:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

8343:   Input Parameter:
8344: . dm - The DM object

8346:   Output Parameter:
8347: . cdm - The coarse DM

8349:   Level: intermediate

8351: .seealso: DMSetCoarseDM()
8352: @*/
8353: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8354: {
8357:   *cdm = dm->coarseMesh;
8358:   return 0;
8359: }

8361: /*@
8362:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

8364:   Input Parameters:
8365: + dm - The DM object
8366: - cdm - The coarse DM

8368:   Level: intermediate

8370: .seealso: DMGetCoarseDM()
8371: @*/
8372: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8373: {
8376:   PetscObjectReference((PetscObject)cdm);
8377:   DMDestroy(&dm->coarseMesh);
8378:   dm->coarseMesh = cdm;
8379:   return 0;
8380: }

8382: /*@
8383:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

8385:   Input Parameter:
8386: . dm - The DM object

8388:   Output Parameter:
8389: . fdm - The fine DM

8391:   Level: intermediate

8393: .seealso: DMSetFineDM()
8394: @*/
8395: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8396: {
8399:   *fdm = dm->fineMesh;
8400:   return 0;
8401: }

8403: /*@
8404:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

8406:   Input Parameters:
8407: + dm - The DM object
8408: - fdm - The fine DM

8410:   Level: intermediate

8412: .seealso: DMGetFineDM()
8413: @*/
8414: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8415: {
8418:   PetscObjectReference((PetscObject)fdm);
8419:   DMDestroy(&dm->fineMesh);
8420:   dm->fineMesh = fdm;
8421:   return 0;
8422: }

8424: /*=== DMBoundary code ===*/

8426: /*@C
8427:   DMAddBoundary - Add a boundary condition to the model

8429:   Collective on dm

8431:   Input Parameters:
8432: + dm       - The DM, with a PetscDS that matches the problem being constrained
8433: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8434: . name     - The BC name
8435: . label    - The label defining constrained points
8436: . Nv       - The number of DMLabel values for constrained points
8437: . values   - An array of values for constrained points
8438: . field    - The field to constrain
8439: . Nc       - The number of constrained field components (0 will constrain all fields)
8440: . comps    - An array of constrained component numbers
8441: . bcFunc   - A pointwise function giving boundary values
8442: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8443: - ctx      - An optional user context for bcFunc

8445:   Output Parameter:
8446: . bd          - (Optional) Boundary number

8448:   Options Database Keys:
8449: + -bc_<boundary name> <num> - Overrides the boundary ids
8450: - -bc_<boundary name>_comp <num> - Overrides the boundary components

8452:   Note:
8453:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

8455: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

8457:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

8459: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8460: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8461: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8462: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

8464: + dim - the spatial dimension
8465: . Nf - the number of fields
8466: . uOff - the offset into u[] and u_t[] for each field
8467: . uOff_x - the offset into u_x[] for each field
8468: . u - each field evaluated at the current point
8469: . u_t - the time derivative of each field evaluated at the current point
8470: . u_x - the gradient of each field evaluated at the current point
8471: . aOff - the offset into a[] and a_t[] for each auxiliary field
8472: . aOff_x - the offset into a_x[] for each auxiliary field
8473: . a - each auxiliary field evaluated at the current point
8474: . a_t - the time derivative of each auxiliary field evaluated at the current point
8475: . a_x - the gradient of auxiliary each field evaluated at the current point
8476: . t - current time
8477: . x - coordinates of the current point
8478: . numConstants - number of constant parameters
8479: . constants - constant parameters
8480: - bcval - output values at the current point

8482:   Level: intermediate

8484: .seealso: DSGetBoundary(), PetscDSAddBoundary()
8485: @*/
8486: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
8487: {
8488:   PetscDS        ds;

8496:   DMGetDS(dm, &ds);
8497:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
8498:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
8499:   return 0;
8500: }

8502: /* TODO Remove this since now the structures are the same */
8503: static PetscErrorCode DMPopulateBoundary(DM dm)
8504: {
8505:   PetscDS        ds;
8506:   DMBoundary    *lastnext;
8507:   DSBoundary     dsbound;

8509:   DMGetDS(dm, &ds);
8510:   dsbound = ds->boundary;
8511:   if (dm->boundary) {
8512:     DMBoundary next = dm->boundary;

8514:     /* quick check to see if the PetscDS has changed */
8515:     if (next->dsboundary == dsbound) return 0;
8516:     /* the PetscDS has changed: tear down and rebuild */
8517:     while (next) {
8518:       DMBoundary b = next;

8520:       next = b->next;
8521:       PetscFree(b);
8522:     }
8523:     dm->boundary = NULL;
8524:   }

8526:   lastnext = &(dm->boundary);
8527:   while (dsbound) {
8528:     DMBoundary dmbound;

8530:     PetscNew(&dmbound);
8531:     dmbound->dsboundary = dsbound;
8532:     dmbound->label      = dsbound->label;
8533:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8534:     *lastnext = dmbound;
8535:     lastnext = &(dmbound->next);
8536:     dsbound = dsbound->next;
8537:   }
8538:   return 0;
8539: }

8541: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8542: {
8543:   DMBoundary     b;

8547:   *isBd = PETSC_FALSE;
8548:   DMPopulateBoundary(dm);
8549:   b = dm->boundary;
8550:   while (b && !(*isBd)) {
8551:     DMLabel    label = b->label;
8552:     DSBoundary dsb   = b->dsboundary;
8553:     PetscInt   i;

8555:     if (label) {
8556:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
8557:     }
8558:     b = b->next;
8559:   }
8560:   return 0;
8561: }

8563: /*@C
8564:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

8566:   Collective on DM

8568:   Input Parameters:
8569: + dm      - The DM
8570: . time    - The time
8571: . funcs   - The coordinate functions to evaluate, one per field
8572: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8573: - mode    - The insertion mode for values

8575:   Output Parameter:
8576: . X - vector

8578:    Calling sequence of func:
8579: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8581: +  dim - The spatial dimension
8582: .  time - The time at which to sample
8583: .  x   - The coordinates
8584: .  Nc  - The number of components
8585: .  u   - The output field values
8586: -  ctx - optional user-defined function context

8588:   Level: developer

8590: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8591: @*/
8592: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8593: {
8594:   Vec            localX;

8597:   DMGetLocalVector(dm, &localX);
8598:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
8599:   DMLocalToGlobalBegin(dm, localX, mode, X);
8600:   DMLocalToGlobalEnd(dm, localX, mode, X);
8601:   DMRestoreLocalVector(dm, &localX);
8602:   return 0;
8603: }

8605: /*@C
8606:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

8608:   Not collective

8610:   Input Parameters:
8611: + dm      - The DM
8612: . time    - The time
8613: . funcs   - The coordinate functions to evaluate, one per field
8614: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8615: - mode    - The insertion mode for values

8617:   Output Parameter:
8618: . localX - vector

8620:    Calling sequence of func:
8621: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8623: +  dim - The spatial dimension
8624: .  x   - The coordinates
8625: .  Nc  - The number of components
8626: .  u   - The output field values
8627: -  ctx - optional user-defined function context

8629:   Level: developer

8631: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8632: @*/
8633: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8634: {
8638:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
8639:   return 0;
8640: }

8642: /*@C
8643:   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.

8645:   Collective on DM

8647:   Input Parameters:
8648: + dm      - The DM
8649: . time    - The time
8650: . label   - The DMLabel selecting the portion of the mesh for projection
8651: . funcs   - The coordinate functions to evaluate, one per field
8652: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8653: - mode    - The insertion mode for values

8655:   Output Parameter:
8656: . X - vector

8658:    Calling sequence of func:
8659: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8661: +  dim - The spatial dimension
8662: .  x   - The coordinates
8663: .  Nc  - The number of components
8664: .  u   - The output field values
8665: -  ctx - optional user-defined function context

8667:   Level: developer

8669: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8670: @*/
8671: 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)
8672: {
8673:   Vec            localX;

8676:   DMGetLocalVector(dm, &localX);
8677:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8678:   DMLocalToGlobalBegin(dm, localX, mode, X);
8679:   DMLocalToGlobalEnd(dm, localX, mode, X);
8680:   DMRestoreLocalVector(dm, &localX);
8681:   return 0;
8682: }

8684: /*@C
8685:   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.

8687:   Not collective

8689:   Input Parameters:
8690: + dm      - The DM
8691: . time    - The time
8692: . label   - The DMLabel selecting the portion of the mesh for projection
8693: . funcs   - The coordinate functions to evaluate, one per field
8694: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8695: - mode    - The insertion mode for values

8697:   Output Parameter:
8698: . localX - vector

8700:    Calling sequence of func:
8701: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

8703: +  dim - The spatial dimension
8704: .  x   - The coordinates
8705: .  Nc  - The number of components
8706: .  u   - The output field values
8707: -  ctx - optional user-defined function context

8709:   Level: developer

8711: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8712: @*/
8713: 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)
8714: {
8718:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8719:   return 0;
8720: }

8722: /*@C
8723:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

8725:   Not collective

8727:   Input Parameters:
8728: + dm      - The DM
8729: . time    - The time
8730: . localU  - The input field vector
8731: . funcs   - The functions to evaluate, one per field
8732: - mode    - The insertion mode for values

8734:   Output Parameter:
8735: . localX  - The output vector

8737:    Calling sequence of func:
8738: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8739: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8740: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8741: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8743: +  dim          - The spatial dimension
8744: .  Nf           - The number of input fields
8745: .  NfAux        - The number of input auxiliary fields
8746: .  uOff         - The offset of each field in u[]
8747: .  uOff_x       - The offset of each field in u_x[]
8748: .  u            - The field values at this point in space
8749: .  u_t          - The field time derivative at this point in space (or NULL)
8750: .  u_x          - The field derivatives at this point in space
8751: .  aOff         - The offset of each auxiliary field in u[]
8752: .  aOff_x       - The offset of each auxiliary field in u_x[]
8753: .  a            - The auxiliary field values at this point in space
8754: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8755: .  a_x          - The auxiliary field derivatives at this point in space
8756: .  t            - The current time
8757: .  x            - The coordinates of this point
8758: .  numConstants - The number of constants
8759: .  constants    - The value of each constant
8760: -  f            - The value of the function at this point in space

8762:   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.
8763:   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
8764:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8765:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8767:   Level: intermediate

8769: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8770: @*/
8771: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8772:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8773:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8774:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8775:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8776:                                    InsertMode mode, Vec localX)
8777: {
8782:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
8783:   return 0;
8784: }

8786: /*@C
8787:   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.

8789:   Not collective

8791:   Input Parameters:
8792: + dm      - The DM
8793: . time    - The time
8794: . label   - The DMLabel marking the portion of the domain to output
8795: . numIds  - The number of label ids to use
8796: . ids     - The label ids to use for marking
8797: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8798: . comps   - The components to set in the output, or NULL for all components
8799: . localU  - The input field vector
8800: . funcs   - The functions to evaluate, one per field
8801: - mode    - The insertion mode for values

8803:   Output Parameter:
8804: . localX  - The output vector

8806:    Calling sequence of func:
8807: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8808: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8809: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8810: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8812: +  dim          - The spatial dimension
8813: .  Nf           - The number of input fields
8814: .  NfAux        - The number of input auxiliary fields
8815: .  uOff         - The offset of each field in u[]
8816: .  uOff_x       - The offset of each field in u_x[]
8817: .  u            - The field values at this point in space
8818: .  u_t          - The field time derivative at this point in space (or NULL)
8819: .  u_x          - The field derivatives at this point in space
8820: .  aOff         - The offset of each auxiliary field in u[]
8821: .  aOff_x       - The offset of each auxiliary field in u_x[]
8822: .  a            - The auxiliary field values at this point in space
8823: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8824: .  a_x          - The auxiliary field derivatives at this point in space
8825: .  t            - The current time
8826: .  x            - The coordinates of this point
8827: .  numConstants - The number of constants
8828: .  constants    - The value of each constant
8829: -  f            - The value of the function at this point in space

8831:   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.
8832:   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
8833:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8834:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8836:   Level: intermediate

8838: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8839: @*/
8840: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8841:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8842:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8843:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8844:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8845:                                         InsertMode mode, Vec localX)
8846: {
8851:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8852:   return 0;
8853: }

8855: /*@C
8856:   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.

8858:   Not collective

8860:   Input Parameters:
8861: + dm      - The DM
8862: . time    - The time
8863: . label   - The DMLabel marking the portion of the domain boundary to output
8864: . numIds  - The number of label ids to use
8865: . ids     - The label ids to use for marking
8866: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8867: . comps   - The components to set in the output, or NULL for all components
8868: . localU  - The input field vector
8869: . funcs   - The functions to evaluate, one per field
8870: - mode    - The insertion mode for values

8872:   Output Parameter:
8873: . localX  - The output vector

8875:    Calling sequence of func:
8876: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8877: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8878: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8879: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8881: +  dim          - The spatial dimension
8882: .  Nf           - The number of input fields
8883: .  NfAux        - The number of input auxiliary fields
8884: .  uOff         - The offset of each field in u[]
8885: .  uOff_x       - The offset of each field in u_x[]
8886: .  u            - The field values at this point in space
8887: .  u_t          - The field time derivative at this point in space (or NULL)
8888: .  u_x          - The field derivatives at this point in space
8889: .  aOff         - The offset of each auxiliary field in u[]
8890: .  aOff_x       - The offset of each auxiliary field in u_x[]
8891: .  a            - The auxiliary field values at this point in space
8892: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8893: .  a_x          - The auxiliary field derivatives at this point in space
8894: .  t            - The current time
8895: .  x            - The coordinates of this point
8896: .  n            - The face normal
8897: .  numConstants - The number of constants
8898: .  constants    - The value of each constant
8899: -  f            - The value of the function at this point in space

8901:   Note:
8902:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8903:   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
8904:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8905:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8907:   Level: intermediate

8909: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8910: @*/
8911: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8912:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8913:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8914:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8915:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8916:                                           InsertMode mode, Vec localX)
8917: {
8922:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8923:   return 0;
8924: }

8926: /*@C
8927:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8929:   Input Parameters:
8930: + dm    - The DM
8931: . time  - The time
8932: . funcs - The functions to evaluate for each field component
8933: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8934: - X     - The coefficient vector u_h, a global vector

8936:   Output Parameter:
8937: . diff - The diff ||u - u_h||_2

8939:   Level: developer

8941: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8942: @*/
8943: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8944: {
8948:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
8949:   return 0;
8950: }

8952: /*@C
8953:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8955:   Collective on dm

8957:   Input Parameters:
8958: + dm    - The DM
8959: , time  - The time
8960: . funcs - The gradient functions to evaluate for each field component
8961: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8962: . X     - The coefficient vector u_h, a global vector
8963: - n     - The vector to project along

8965:   Output Parameter:
8966: . diff - The diff ||(grad u - grad u_h) . n||_2

8968:   Level: developer

8970: .seealso: DMProjectFunction(), DMComputeL2Diff()
8971: @*/
8972: 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)
8973: {
8977:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
8978:   return 0;
8979: }

8981: /*@C
8982:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8984:   Collective on dm

8986:   Input Parameters:
8987: + dm    - The DM
8988: . time  - The time
8989: . funcs - The functions to evaluate for each field component
8990: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8991: - X     - The coefficient vector u_h, a global vector

8993:   Output Parameter:
8994: . diff - The array of differences, ||u^f - u^f_h||_2

8996:   Level: developer

8998: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8999: @*/
9000: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9001: {
9005:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
9006:   return 0;
9007: }

9009: /*@C
9010:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

9012:  Not Collective

9014:  Input Parameter:
9015: .  dm    - The DM

9017:  Output Parameters:
9018: +  nranks - the number of neighbours
9019: -  ranks - the neighbors ranks

9021:  Notes:
9022:  Do not free the array, it is freed when the DM is destroyed.

9024:  Level: beginner

9026:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9027: @*/
9028: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9029: {
9032:   (dm->ops->getneighbors)(dm,nranks,ranks);
9033:   return 0;
9034: }

9036: #include <petsc/private/matimpl.h>

9038: /*
9039:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9040:     This has be a different function because it requires DM which is not defined in the Mat library
9041: */
9042: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9043: {
9044:   if (coloring->ctype == IS_COLORING_LOCAL) {
9045:     Vec x1local;
9046:     DM  dm;
9047:     MatGetDM(J,&dm);
9049:     DMGetLocalVector(dm,&x1local);
9050:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
9051:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
9052:     x1   = x1local;
9053:   }
9054:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
9055:   if (coloring->ctype == IS_COLORING_LOCAL) {
9056:     DM  dm;
9057:     MatGetDM(J,&dm);
9058:     DMRestoreLocalVector(dm,&x1);
9059:   }
9060:   return 0;
9061: }

9063: /*@
9064:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

9066:     Input Parameter:
9067: .    coloring - the MatFDColoring object

9069:     Developer Notes:
9070:     this routine exists because the PETSc Mat library does not know about the DM objects

9072:     Level: advanced

9074: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9075: @*/
9076: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9077: {
9078:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9079:   return 0;
9080: }

9082: /*@
9083:     DMGetCompatibility - determine if two DMs are compatible

9085:     Collective

9087:     Input Parameters:
9088: +    dm1 - the first DM
9089: -    dm2 - the second DM

9091:     Output Parameters:
9092: +    compatible - whether or not the two DMs are compatible
9093: -    set - whether or not the compatible value was set

9095:     Notes:
9096:     Two DMs are deemed compatible if they represent the same parallel decomposition
9097:     of the same topology. This implies that the section (field data) on one
9098:     "makes sense" with respect to the topology and parallel decomposition of the other.
9099:     Loosely speaking, compatible DMs represent the same domain and parallel
9100:     decomposition, but hold different data.

9102:     Typically, one would confirm compatibility if intending to simultaneously iterate
9103:     over a pair of vectors obtained from different DMs.

9105:     For example, two DMDA objects are compatible if they have the same local
9106:     and global sizes and the same stencil width. They can have different numbers
9107:     of degrees of freedom per node. Thus, one could use the node numbering from
9108:     either DM in bounds for a loop over vectors derived from either DM.

9110:     Consider the operation of summing data living on a 2-dof DMDA to data living
9111:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9112: .vb
9113:   ...
9114:   DMGetCompatibility(da1,da2,&compatible,&set);
9115:   if (set && compatible)  {
9116:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
9117:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
9118:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
9119:     for (j=y; j<y+n; ++j) {
9120:       for (i=x; i<x+m, ++i) {
9121:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9122:       }
9123:     }
9124:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
9125:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
9126:   } else {
9127:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9128:   }
9129:   ...
9130: .ve

9132:     Checking compatibility might be expensive for a given implementation of DM,
9133:     or might be impossible to unambiguously confirm or deny. For this reason,
9134:     this function may decline to determine compatibility, and hence users should
9135:     always check the "set" output parameter.

9137:     A DM is always compatible with itself.

9139:     In the current implementation, DMs which live on "unequal" communicators
9140:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9141:     incompatible.

9143:     This function is labeled "Collective," as information about all subdomains
9144:     is required on each rank. However, in DM implementations which store all this
9145:     information locally, this function may be merely "Logically Collective".

9147:     Developer Notes:
9148:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9149:     iff B is compatible with A. Thus, this function checks the implementations
9150:     of both dm and dmc (if they are of different types), attempting to determine
9151:     compatibility. It is left to DM implementers to ensure that symmetry is
9152:     preserved. The simplest way to do this is, when implementing type-specific
9153:     logic for this function, is to check for existing logic in the implementation
9154:     of other DM types and let *set = PETSC_FALSE if found.

9156:     Level: advanced

9158: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9159: @*/

9161: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9162: {
9163:   PetscMPIInt    compareResult;
9164:   DMType         type,type2;
9165:   PetscBool      sameType;


9170:   /* Declare a DM compatible with itself */
9171:   if (dm1 == dm2) {
9172:     *set = PETSC_TRUE;
9173:     *compatible = PETSC_TRUE;
9174:     return 0;
9175:   }

9177:   /* Declare a DM incompatible with a DM that lives on an "unequal"
9178:      communicator. Note that this does not preclude compatibility with
9179:      DMs living on "congruent" or "similar" communicators, but this must be
9180:      determined by the implementation-specific logic */
9181:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
9182:   if (compareResult == MPI_UNEQUAL) {
9183:     *set = PETSC_TRUE;
9184:     *compatible = PETSC_FALSE;
9185:     return 0;
9186:   }

9188:   /* Pass to the implementation-specific routine, if one exists. */
9189:   if (dm1->ops->getcompatibility) {
9190:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
9191:     if (*set) return 0;
9192:   }

9194:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9195:      with an implementation of this function from dm2 */
9196:   DMGetType(dm1,&type);
9197:   DMGetType(dm2,&type2);
9198:   PetscStrcmp(type,type2,&sameType);
9199:   if (!sameType && dm2->ops->getcompatibility) {
9200:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
9201:   } else {
9202:     *set = PETSC_FALSE;
9203:   }
9204:   return 0;
9205: }

9207: /*@C
9208:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

9210:   Logically Collective on DM

9212:   Input Parameters:
9213: + DM - the DM
9214: . f - the monitor function
9215: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9216: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

9218:   Options Database Keys:
9219: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9220:                             does not cancel those set via the options database.

9222:   Notes:
9223:   Several different monitoring routines may be set by calling
9224:   DMMonitorSet() multiple times; all will be called in the
9225:   order in which they were set.

9227:   Fortran Notes:
9228:   Only a single monitor function can be set for each DM object

9230:   Level: intermediate

9232: .seealso: DMMonitorCancel()
9233: @*/
9234: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9235: {
9236:   PetscInt       m;

9239:   for (m = 0; m < dm->numbermonitors; ++m) {
9240:     PetscBool identical;

9242:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
9243:     if (identical) return 0;
9244:   }
9246:   dm->monitor[dm->numbermonitors]          = f;
9247:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9248:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9249:   return 0;
9250: }

9252: /*@
9253:   DMMonitorCancel - Clears all the monitor functions for a DM object.

9255:   Logically Collective on DM

9257:   Input Parameter:
9258: . dm - the DM

9260:   Options Database Key:
9261: . -dm_monitor_cancel - cancels all monitors that have been hardwired
9262:   into a code by calls to DMonitorSet(), but does not cancel those
9263:   set via the options database

9265:   Notes:
9266:   There is no way to clear one specific monitor from a DM object.

9268:   Level: intermediate

9270: .seealso: DMMonitorSet()
9271: @*/
9272: PetscErrorCode DMMonitorCancel(DM dm)
9273: {
9274:   PetscInt       m;

9277:   for (m = 0; m < dm->numbermonitors; ++m) {
9278:     if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
9279:   }
9280:   dm->numbermonitors = 0;
9281:   return 0;
9282: }

9284: /*@C
9285:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

9287:   Collective on DM

9289:   Input Parameters:
9290: + dm   - DM object you wish to monitor
9291: . name - the monitor type one is seeking
9292: . help - message indicating what monitoring is done
9293: . manual - manual page for the monitor
9294: . monitor - the monitor function
9295: - 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

9297:   Output Parameter:
9298: . flg - Flag set if the monitor was created

9300:   Level: developer

9302: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9303:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9304:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9305:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9306:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9307:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9308:           PetscOptionsFList(), PetscOptionsEList()
9309: @*/
9310: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9311: {
9312:   PetscViewer       viewer;
9313:   PetscViewerFormat format;

9316:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
9317:   if (*flg) {
9318:     PetscViewerAndFormat *vf;

9320:     PetscViewerAndFormatCreate(viewer, format, &vf);
9321:     PetscObjectDereference((PetscObject) viewer);
9322:     if (monitorsetup) (*monitorsetup)(dm, vf);
9323:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
9324:   }
9325:   return 0;
9326: }

9328: /*@
9329:    DMMonitor - runs the user provided monitor routines, if they exist

9331:    Collective on DM

9333:    Input Parameters:
9334: .  dm - The DM

9336:    Level: developer

9338: .seealso: DMMonitorSet()
9339: @*/
9340: PetscErrorCode DMMonitor(DM dm)
9341: {
9342:   PetscInt       m;

9344:   if (!dm) return 0;
9346:   for (m = 0; m < dm->numbermonitors; ++m) {
9347:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
9348:   }
9349:   return 0;
9350: }

9352: /*@
9353:   DMComputeError - Computes the error assuming the user has given exact solution functions

9355:   Collective on DM

9357:   Input Parameters:
9358: + dm     - The DM
9359: - sol    - The solution vector

9361:   Input/Output Parameter:
9362: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9363:            contains the error in each field

9365:   Output Parameter:
9366: . errorVec - A vector to hold the cellwise error (may be NULL)

9368:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

9370:   Level: developer

9372: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
9373: @*/
9374: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9375: {
9376:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9377:   void            **ctxs;
9378:   PetscReal         time;
9379:   PetscInt          Nf, f, Nds, s;

9381:   DMGetNumFields(dm, &Nf);
9382:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
9383:   DMGetNumDS(dm, &Nds);
9384:   for (s = 0; s < Nds; ++s) {
9385:     PetscDS         ds;
9386:     DMLabel         label;
9387:     IS              fieldIS;
9388:     const PetscInt *fields;
9389:     PetscInt        dsNf;

9391:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
9392:     PetscDSGetNumFields(ds, &dsNf);
9393:     if (fieldIS) ISGetIndices(fieldIS, &fields);
9394:     for (f = 0; f < dsNf; ++f) {
9395:       const PetscInt field = fields[f];
9396:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
9397:     }
9398:     if (fieldIS) ISRestoreIndices(fieldIS, &fields);
9399:   }
9400:   for (f = 0; f < Nf; ++f) {
9402:   }
9403:   DMGetOutputSequenceNumber(dm, NULL, &time);
9404:   if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
9405:   if (errorVec) {
9406:     DM             edm;
9407:     DMPolytopeType ct;
9408:     PetscBool      simplex;
9409:     PetscInt       dim, cStart, Nf;

9411:     DMClone(dm, &edm);
9412:     DMGetDimension(edm, &dim);
9413:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
9414:     DMPlexGetCellType(dm, cStart, &ct);
9415:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9416:     DMGetNumFields(dm, &Nf);
9417:     for (f = 0; f < Nf; ++f) {
9418:       PetscFE         fe, efe;
9419:       PetscQuadrature q;
9420:       const char     *name;

9422:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
9423:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
9424:       PetscObjectGetName((PetscObject) fe, &name);
9425:       PetscObjectSetName((PetscObject) efe, name);
9426:       PetscFEGetQuadrature(fe, &q);
9427:       PetscFESetQuadrature(efe, q);
9428:       DMSetField(edm, f, NULL, (PetscObject) efe);
9429:       PetscFEDestroy(&efe);
9430:     }
9431:     DMCreateDS(edm);

9433:     DMCreateGlobalVector(edm, errorVec);
9434:     PetscObjectSetName((PetscObject) *errorVec, "Error");
9435:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
9436:     DMDestroy(&edm);
9437:   }
9438:   PetscFree2(exactSol, ctxs);
9439:   return 0;
9440: }

9442: /*@
9443:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

9445:   Not collective

9447:   Input Parameter:
9448: . dm     - The DM

9450:   Output Parameter:
9451: . numAux - The number of auxiliary data vectors

9453:   Level: advanced

9455: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
9456: @*/
9457: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9458: {
9460:   PetscHMapAuxGetSize(dm->auxData, numAux);
9461:   return 0;
9462: }

9464: /*@
9465:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part

9467:   Not collective

9469:   Input Parameters:
9470: + dm     - The DM
9471: . label  - The DMLabel
9472: . value  - The label value indicating the region
9473: - part   - The equation part, or 0 if unused

9475:   Output Parameter:
9476: . aux    - The Vec holding auxiliary field data

9478:   Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.

9480:   Level: advanced

9482: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
9483: @*/
9484: PetscErrorCode DMGetAuxiliaryVec(DM dm,