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_WINDOWS_COMPILERS)
 15: #include <petsc/private/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_CreateMassMatrix, 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",
 25:                                          "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown",  "invalid",       "DMPolytopeType", "DM_POLYTOPE_", NULL};
 26: const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};

 28: /*@
 29:   DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
 30:   algebraic solvers, time integrators, and optimization algorithms.

 32:   Collective

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

 37:   Output Parameter:
 38: . dm - The `DM` object

 40:   Level: beginner

 42:   Notes:
 43:   See `DMType` for a brief summary of available `DM`.

 45:   The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
 46:   error when you try to use the dm.

 48: .seealso: `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
 49: @*/
 50: PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
 51: {
 52:   DM      v;
 53:   PetscDS ds;

 56:   *dm = NULL;
 57:   DMInitializePackage();

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

 61:   ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;

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

103:   *dm = v;
104:   return 0;
105: }

107: /*@
108:   DMClone - Creates a `DM` object with the same topology as the original.

110:   Collective

112:   Input Parameter:
113: . dm - The original `DM` object

115:   Output Parameter:
116: . newdm  - The new `DM` object

118:   Level: beginner

120:   Notes:
121:   For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
122:   `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
123:   share the `PetscSection` of the original `DM`.

125:   The clone is considered set up if the original has been set up.

127:   Use `DMConvert()` for a general way to create new `DM` from a given `DM`

129: .seealso: `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMSetType()`, `DMConvert()`
130: @*/
131: PetscErrorCode DMClone(DM dm, DM *newdm)
132: {
133:   PetscSF  sf;
134:   Vec      coords;
135:   void    *ctx;
136:   PetscInt dim, cdim, i;

140:   DMCreate(PetscObjectComm((PetscObject)dm), newdm);
141:   DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL);
142:   (*newdm)->leveldown     = dm->leveldown;
143:   (*newdm)->levelup       = dm->levelup;
144:   (*newdm)->prealloc_only = dm->prealloc_only;
145:   PetscFree((*newdm)->vectype);
146:   PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype);
147:   PetscFree((*newdm)->mattype);
148:   PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype);
149:   DMGetDimension(dm, &dim);
150:   DMSetDimension(*newdm, dim);
151:   PetscTryTypeMethod(dm, clone, newdm);
152:   (*newdm)->setupcalled = dm->setupcalled;
153:   DMGetPointSF(dm, &sf);
154:   DMSetPointSF(*newdm, sf);
155:   DMGetApplicationContext(dm, &ctx);
156:   DMSetApplicationContext(*newdm, ctx);
157:   for (i = 0; i < 2; ++i) {
158:     if (dm->coordinates[i].dm) {
159:       DM           ncdm;
160:       PetscSection cs;
161:       PetscInt     pEnd = -1, pEndMax = -1;

163:       DMGetLocalSection(dm->coordinates[i].dm, &cs);
164:       if (cs) PetscSectionGetChart(cs, NULL, &pEnd);
165:       MPI_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
166:       if (pEndMax >= 0) {
167:         DMClone(dm->coordinates[i].dm, &ncdm);
168:         DMCopyDisc(dm->coordinates[i].dm, ncdm);
169:         DMSetLocalSection(ncdm, cs);
170:         if (i) DMSetCellCoordinateDM(*newdm, ncdm);
171:         else DMSetCoordinateDM(*newdm, ncdm);
172:         DMDestroy(&ncdm);
173:       }
174:     }
175:   }
176:   DMGetCoordinateDim(dm, &cdim);
177:   DMSetCoordinateDim(*newdm, cdim);
178:   DMGetCoordinatesLocal(dm, &coords);
179:   if (coords) {
180:     DMSetCoordinatesLocal(*newdm, coords);
181:   } else {
182:     DMGetCoordinates(dm, &coords);
183:     if (coords) DMSetCoordinates(*newdm, coords);
184:   }
185:   DMGetCellCoordinatesLocal(dm, &coords);
186:   if (coords) {
187:     DMSetCellCoordinatesLocal(*newdm, coords);
188:   } else {
189:     DMGetCellCoordinates(dm, &coords);
190:     if (coords) DMSetCellCoordinates(*newdm, coords);
191:   }
192:   {
193:     const PetscReal *maxCell, *Lstart, *L;

195:     DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
196:     DMSetPeriodicity(*newdm, maxCell, Lstart, L);
197:   }
198:   {
199:     PetscBool useCone, useClosure;

201:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
202:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
203:   }
204:   return 0;
205: }

207: /*@C
208:        DMSetVecType - Sets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`

210:    Logically Collective on da

212:    Input Parameters:
213: +  da - initial distributed array
214: -  ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`

216:    Options Database:
217: .   -dm_vec_type ctype - the type of vector to create

219:    Level: intermediate

221: .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
222:           `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
223: @*/
224: PetscErrorCode DMSetVecType(DM da, VecType ctype)
225: {
227:   PetscFree(da->vectype);
228:   PetscStrallocpy(ctype, (char **)&da->vectype);
229:   return 0;
230: }

232: /*@C
233:        DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`

235:    Logically Collective on da

237:    Input Parameter:
238: .  da - initial distributed array

240:    Output Parameter:
241: .  ctype - the vector type

243:    Level: intermediate

245: .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
246: @*/
247: PetscErrorCode DMGetVecType(DM da, VecType *ctype)
248: {
250:   *ctype = da->vectype;
251:   return 0;
252: }

254: /*@
255:   VecGetDM - Gets the `DM` defining the data layout of the vector

257:   Not collective

259:   Input Parameter:
260: . v - The `Vec`

262:   Output Parameter:
263: . dm - The `DM`

265:   Level: intermediate

267:   Note:
268:   A `Vec` may not have a `DM` associated with it.

270: .seealso: `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
271: @*/
272: PetscErrorCode VecGetDM(Vec v, DM *dm)
273: {
276:   PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm);
277:   return 0;
278: }

280: /*@
281:   VecSetDM - Sets the `DM` defining the data layout of the vector.

283:   Not collective

285:   Input Parameters:
286: + v - The `Vec`
287: - dm - The `DM`

289:   Note:
290:   This is rarely used, generally one uses `DMGetLocalVector()` or  `DMGetGlobalVector()` to create a vector associated with a given `DM`

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

294:   Level: developer

296: .seealso: `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
297: @*/
298: PetscErrorCode VecSetDM(Vec v, DM dm)
299: {
302:   PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm);
303:   return 0;
304: }

306: /*@C
307:        DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`

309:    Logically Collective on dm

311:    Input Parameters:
312: +  dm - the `DM` context
313: -  ctype - the matrix type

315:    Options Database:
316: .   -dm_is_coloring_type - global or local

318:    Level: intermediate

320: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
321:           `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
322: @*/
323: PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
324: {
326:   dm->coloringtype = ctype;
327:   return 0;
328: }

330: /*@C
331:        DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`

333:    Logically Collective on dm

335:    Input Parameter:
336: .  dm - the `DM` context

338:    Output Parameter:
339: .  ctype - the matrix type

341:    Options Database:
342: .   -dm_is_coloring_type - global or local

344:    Level: intermediate

346: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
347:           `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
348: @*/
349: PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
350: {
352:   *ctype = dm->coloringtype;
353:   return 0;
354: }

356: /*@C
357:        DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`

359:    Logically Collective on dm

361:    Input Parameters:
362: +  dm - the `DM` context
363: -  ctype - the matrix type, for example `MATMPIAIJ`

365:    Options Database:
366: .   -dm_mat_type ctype - the type of the matrix to create, for example mpiaij

368:    Level: intermediate

370: .seealso: `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`, `DMSetMatType()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
371: @*/
372: PetscErrorCode DMSetMatType(DM dm, MatType ctype)
373: {
375:   PetscFree(dm->mattype);
376:   PetscStrallocpy(ctype, (char **)&dm->mattype);
377:   return 0;
378: }

380: /*@C
381:        DMGetMatType - Gets the type of matrix created with `DMCreateMatrix()`

383:    Logically Collective on dm

385:    Input Parameter:
386: .  dm - the `DM` context

388:    Output Parameter:
389: .  ctype - the matrix type

391:    Level: intermediate

393: .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`, `DMSetMatType()`, `DMGetMatType()`
394: @*/
395: PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
396: {
398:   *ctype = dm->mattype;
399:   return 0;
400: }

402: /*@
403:   MatGetDM - Gets the `DM` defining the data layout of the matrix

405:   Not collective

407:   Input Parameter:
408: . A - The `Mat`

410:   Output Parameter:
411: . dm - The `DM`

413:   Level: intermediate

415:   Note:
416:   A matrix may not have a `DM` associated with it

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

421: .seealso: `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
422: @*/
423: PetscErrorCode MatGetDM(Mat A, DM *dm)
424: {
427:   PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm);
428:   return 0;
429: }

431: /*@
432:   MatSetDM - Sets the `DM` defining the data layout of the matrix

434:   Not collective

436:   Input Parameters:
437: + A - The Mat
438: - dm - The DM

440:   Level: developer

442:   Note:
443:   This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`

445:   Developer Note:
446:   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
447:   the `Mat` through a `PetscObjectCompose()` operation

449: .seealso: `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
450: @*/
451: PetscErrorCode MatSetDM(Mat A, DM dm)
452: {
455:   PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm);
456:   return 0;
457: }

459: /*@C
460:    DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database

462:    Logically Collective on dm

464:    Input Parameters:
465: +  da - the `DM` context
466: -  prefix - the prefix to prepend

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

472:    Level: advanced

474: .seealso: `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
475: @*/
476: PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
477: {
479:   PetscObjectSetOptionsPrefix((PetscObject)dm, prefix);
480:   if (dm->sf) PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix);
481:   if (dm->sectionSF) PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix);
482:   return 0;
483: }

485: /*@C
486:    DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
487:    `DM` options in the options database.

489:    Logically Collective on dm

491:    Input Parameters:
492: +  dm - the `DM` context
493: -  prefix - the string to append to the current prefix

495:    Notes:
496:    If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
497:    A hyphen (-) must NOT be given at the beginning of the prefix name.
498:    The first character of all runtime options is AUTOMATICALLY the hyphen.

500:    Level: advanced

502: .seealso: `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
503: @*/
504: PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
505: {
507:   PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix);
508:   return 0;
509: }

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

515:    Not Collective

517:    Input Parameters:
518: .  dm - the `DM` context

520:    Output Parameters:
521: .  prefix - pointer to the prefix string used is returned

523:    Fortran Note:
524:     On the fortran side, the user should pass in a string 'prefix' of
525:    sufficient length to hold the prefix.

527:    Level: advanced

529: .seealso: `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
530: @*/
531: PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
532: {
534:   PetscObjectGetOptionsPrefix((PetscObject)dm, prefix);
535:   return 0;
536: }

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

542:   *ncrefct = 0;
543:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
544:     refct--;
545:     if (recurseCoarse) {
546:       PetscInt coarseCount;

548:       DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount);
549:       refct += coarseCount;
550:     }
551:   }
552:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
553:     refct--;
554:     if (recurseFine) {
555:       PetscInt fineCount;

557:       DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount);
558:       refct += fineCount;
559:     }
560:   }
561:   *ncrefct = refct;
562:   return 0;
563: }

565: /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
566: PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
567: {
568:   DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct);
569:   return 0;
570: }

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

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

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

590: PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
591: {
592:   c->dim = PETSC_DEFAULT;
593:   DMDestroy(&c->dm);
594:   VecDestroy(&c->x);
595:   VecDestroy(&c->xl);
596:   DMFieldDestroy(&c->field);
597:   return 0;
598: }

600: /*@C
601:     DMDestroy - Destroys a `DM`.

603:     Collective on dm

605:     Input Parameter:
606: .   dm - the `DM` object to destroy

608:     Level: developer

610: .seealso: `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
611: @*/
612: PetscErrorCode DMDestroy(DM *dm)
613: {
614:   PetscInt       cnt;
615:   DMNamedVecLink nlink, nnext;

617:   if (!*dm) return 0;

620:   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
621:   DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt);
622:   --((PetscObject)(*dm))->refct;
623:   if (--cnt > 0) {
624:     *dm = NULL;
625:     return 0;
626:   }
627:   if (((PetscObject)(*dm))->refct < 0) return 0;
628:   ((PetscObject)(*dm))->refct = 0;

630:   DMClearGlobalVectors(*dm);
631:   DMClearLocalVectors(*dm);

633:   nnext              = (*dm)->namedglobal;
634:   (*dm)->namedglobal = NULL;
635:   for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named vectors */
636:     nnext = nlink->next;
638:     PetscFree(nlink->name);
639:     VecDestroy(&nlink->X);
640:     PetscFree(nlink);
641:   }
642:   nnext             = (*dm)->namedlocal;
643:   (*dm)->namedlocal = NULL;
644:   for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named local vectors */
645:     nnext = nlink->next;
647:     PetscFree(nlink->name);
648:     VecDestroy(&nlink->X);
649:     PetscFree(nlink);
650:   }

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

714:       next = b->next;
715:       PetscFree(b);
716:     }
717:   }

719:   PetscObjectDestroy(&(*dm)->dmksp);
720:   PetscObjectDestroy(&(*dm)->dmsnes);
721:   PetscObjectDestroy(&(*dm)->dmts);

723:   if ((*dm)->ctx && (*dm)->ctxdestroy) (*(*dm)->ctxdestroy)(&(*dm)->ctx);
724:   MatFDColoringDestroy(&(*dm)->fd);
725:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
726:   PetscFree((*dm)->vectype);
727:   PetscFree((*dm)->mattype);

729:   PetscSectionDestroy(&(*dm)->localSection);
730:   PetscSectionDestroy(&(*dm)->globalSection);
731:   PetscLayoutDestroy(&(*dm)->map);
732:   PetscSectionDestroy(&(*dm)->defaultConstraint.section);
733:   MatDestroy(&(*dm)->defaultConstraint.mat);
734:   PetscSFDestroy(&(*dm)->sf);
735:   PetscSFDestroy(&(*dm)->sectionSF);
736:   if ((*dm)->useNatural) {
737:     if ((*dm)->sfNatural) PetscSFDestroy(&(*dm)->sfNatural);
738:     PetscObjectDereference((PetscObject)(*dm)->sfMigration);
739:   }
740:   {
741:     Vec     *auxData;
742:     PetscInt n, i, off = 0;

744:     PetscHMapAuxGetSize((*dm)->auxData, &n);
745:     PetscMalloc1(n, &auxData);
746:     PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
747:     for (i = 0; i < n; ++i) VecDestroy(&auxData[i]);
748:     PetscFree(auxData);
749:     PetscHMapAuxDestroy(&(*dm)->auxData);
750:   }
751:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) DMSetFineDM((*dm)->coarseMesh, NULL);

753:   DMDestroy(&(*dm)->coarseMesh);
754:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) DMSetCoarseDM((*dm)->fineMesh, NULL);
755:   DMDestroy(&(*dm)->fineMesh);
756:   PetscFree((*dm)->Lstart);
757:   PetscFree((*dm)->L);
758:   PetscFree((*dm)->maxCell);
759:   DMDestroyCoordinates_Private(&(*dm)->coordinates[0]);
760:   DMDestroyCoordinates_Private(&(*dm)->coordinates[1]);
761:   if ((*dm)->transformDestroy) (*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);
762:   DMDestroy(&(*dm)->transformDM);
763:   VecDestroy(&(*dm)->transform);

765:   DMClearDS(*dm);
766:   DMDestroy(&(*dm)->dmBC);
767:   /* if memory was published with SAWs then destroy it */
768:   PetscObjectSAWsViewOff((PetscObject)*dm);

770:   if ((*dm)->ops->destroy) (*(*dm)->ops->destroy)(*dm);
771:   DMMonitorCancel(*dm);
772: #ifdef PETSC_HAVE_LIBCEED
773:   CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
774:   CeedDestroy(&(*dm)->ceed);
775: #endif
776:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
777:   PetscHeaderDestroy(dm);
778:   return 0;
779: }

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

784:     Collective on dm

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

789:     Level: intermediate

791:     Note:
792:     This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`

794: .seealso: `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
795: @*/
796: PetscErrorCode DMSetUp(DM dm)
797: {
799:   if (dm->setupcalled) return 0;
800:   PetscTryTypeMethod(dm, setup);
801:   dm->setupcalled = PETSC_TRUE;
802:   return 0;
803: }

805: /*@
806:     DMSetFromOptions - sets parameters in a `DM` from the options database

808:     Collective on dm

810:     Input Parameter:
811: .   dm - the `DM` object to set options for

813:     Options Database:
814: +   -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
815: .   -dm_vec_type <type>  - type of vector to create inside `DM`
816: .   -dm_mat_type <type>  - type of matrix to create inside `DM`
817: .   -dm_is_coloring_type - <global or local>
818: -   -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`

820:     DMPLEX Specific creation options
821: + -dm_plex_filename <str>           - File containing a mesh
822: . -dm_plex_boundary_filename <str>  - File containing a mesh boundary
823: . -dm_plex_name <str>               - Name of the mesh in the file
824: . -dm_plex_shape <shape>            - The domain shape, such as `DM_SHAPE_BOX`, `DM_SHAPE_SPHERE`, etc.
825: . -dm_plex_cell <ct>                - Cell shape
826: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
827: . -dm_plex_dim <dim>                - Set the topological dimension
828: . -dm_plex_simplex <bool>           - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
829: . -dm_plex_interpolate <bool>       - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
830: . -dm_plex_scale <sc>               - Scale factor for mesh coordinates
831: . -dm_plex_box_faces <m,n,p>        - Number of faces along each dimension
832: . -dm_plex_box_lower <x,y,z>        - Specify lower-left-bottom coordinates for the box
833: . -dm_plex_box_upper <x,y,z>        - Specify upper-right-top coordinates for the box
834: . -dm_plex_box_bd <bx,by,bz>        - Specify the `DMBoundaryType `for each direction
835: . -dm_plex_sphere_radius <r>        - The sphere radius
836: . -dm_plex_ball_radius <r>          - Radius of the ball
837: . -dm_plex_cylinder_bd <bz>         - Boundary type in the z direction
838: . -dm_plex_cylinder_num_wedges <n>  - Number of wedges around the cylinder
839: . -dm_plex_reorder <order>          - Reorder the mesh using the specified algorithm
840: . -dm_refine_pre <n>                - The number of refinements before distribution
841: . -dm_refine_uniform_pre <bool>     - Flag for uniform refinement before distribution
842: . -dm_refine_volume_limit_pre <v>   - The maximum cell volume after refinement before distribution
843: . -dm_refine <n>                    - The number of refinements after distribution
844: . -dm_extrude <l>                   - Activate extrusion and specify the number of layers to extrude
845: . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
846: . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
847: . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
848: . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
849: . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
850: . -dm_plex_create_fv_ghost_cells    - Flag to create finite volume ghost cells on the boundary
851: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
852: . -dm_distribute <bool>             - Flag to redistribute a mesh among processes
853: . -dm_distribute_overlap <n>        - The size of the overlap halo
854: . -dm_plex_adj_cone <bool>          - Set adjacency direction
855: - -dm_plex_adj_closure <bool>       - Set adjacency size

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

866:     Level: intermediate

868: .seealso: `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
869:          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
870:          `DMSetOptionsPrefix()`, `DM`, `DMType`, `DMPLEX`, `DMDA`
871: @*/
872: PetscErrorCode DMSetFromOptions(DM dm)
873: {
874:   char      typeName[256];
875:   PetscBool flg;

878:   dm->setfromoptionscalled = PETSC_TRUE;
879:   if (dm->sf) PetscSFSetFromOptions(dm->sf);
880:   if (dm->sectionSF) PetscSFSetFromOptions(dm->sectionSF);
881:   PetscObjectOptionsBegin((PetscObject)dm);
882:   PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL);
883:   PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg);
884:   if (flg) DMSetVecType(dm, typeName);
885:   PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg);
886:   if (flg) DMSetMatType(dm, typeName);
887:   PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL);
888:   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);
889:   PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
890:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
891:   PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject);
892:   PetscOptionsEnd();
893:   return 0;
894: }

896: /*@C
897:    DMViewFromOptions - View a `DM` in a particular way based on a request in the options database

899:    Collective on dm

901:    Input Parameters:
902: +  dm - the `DM` object
903: .  obj - optional object that provides the prefix for the options database (if NULL then the prefix in obj is used)
904: -  optionname - option string that is used to activate viewing

906:    Level: intermediate

908:    Note:
909:    See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed

911: .seealso: `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`, `PetscObjectViewFromOptions()`
912: @*/
913: PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[])
914: {
916:   PetscObjectViewFromOptions((PetscObject)dm, obj, name);
917:   return 0;
918: }

920: /*@C
921:     DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
922:     save the `DM` in a binary file to be loaded later or create a visualization of the `DM`

924:     Collective on dm

926:     Input Parameters:
927: +   dm - the `DM` object to view
928: -   v - the viewer

930:     Notes:
931:     Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` one can save multiple `DMPLEX`
932:     meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
933:     before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.

935:     Level: beginner

937: .seealso: `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat`(), `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`

939: @*/
940: PetscErrorCode DMView(DM dm, PetscViewer v)
941: {
942:   PetscBool         isbinary;
943:   PetscMPIInt       size;
944:   PetscViewerFormat format;

947:   if (!v) PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v);
949:   /* Ideally, we would like to have this test on.
950:      However, it currently breaks socket viz via GLVis.
951:      During DMView(parallel_mesh,glvis_viewer), each
952:      process opens a sequential ASCII socket to visualize
953:      the local mesh, and PetscObjectView(dm,local_socket)
954:      is internally called inside VecView_GLVis, incurring
955:      in an error here */
957:   PetscViewerCheckWritable(v);

959:   PetscViewerGetFormat(v, &format);
960:   MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
961:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return 0;
962:   PetscObjectPrintClassNamePrefixType((PetscObject)dm, v);
963:   PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary);
964:   if (isbinary) {
965:     PetscInt classid = DM_FILE_CLASSID;
966:     char     type[256];

968:     PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT);
969:     PetscStrncpy(type, ((PetscObject)dm)->type_name, 256);
970:     PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR);
971:   }
972:   PetscTryTypeMethod(dm, view, v);
973:   return 0;
974: }

976: /*@
977:     DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
978:     that is it has no ghost locations.

980:     Collective on dm

982:     Input Parameter:
983: .   dm - the `DM` object

985:     Output Parameter:
986: .   vec - the global vector

988:     Level: beginner

990: .seealso: `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
991:          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
992: @*/
993: PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
994: {
997:   PetscUseTypeMethod(dm, createglobalvector, vec);
998:   if (PetscDefined(USE_DEBUG)) {
999:     DM vdm;

1001:     VecGetDM(*vec, &vdm);
1003:   }
1004:   return 0;
1005: }

1007: /*@
1008:     DMCreateLocalVector - Creates a local vector from a `DM` object.

1010:     Not Collective

1012:     Input Parameter:
1013: .   dm - the `DM` object

1015:     Output Parameter:
1016: .   vec - the local vector

1018:     Level: beginner

1020:     Notes:
1021:     A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.

1023:  .seealso: `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1024:          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1025: @*/
1026: PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1027: {
1030:   PetscUseTypeMethod(dm, createlocalvector, vec);
1031:   if (PetscDefined(USE_DEBUG)) {
1032:     DM vdm;

1034:     VecGetDM(*vec, &vdm);
1036:   }
1037:   return 0;
1038: }

1040: /*@
1041:    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.

1043:    Collective on dm

1045:    Input Parameter:
1046: .  dm - the `DM` that provides the mapping

1048:    Output Parameter:
1049: .  ltog - the mapping

1051:    Level: advanced

1053:    Notes:
1054:    The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`

1056:    Vectors obtained with  `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1057:    need to use this function with those objects.

1059:    This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.

1061: .seealso: `DMCreateLocalVector()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1062:           `DMCreateMatrix()`
1063: @*/
1064: PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1065: {
1066:   PetscInt bs = -1, bsLocal[2], bsMinMax[2];

1070:   if (!dm->ltogmap) {
1071:     PetscSection section, sectionGlobal;

1073:     DMGetLocalSection(dm, &section);
1074:     if (section) {
1075:       const PetscInt *cdofs;
1076:       PetscInt       *ltog;
1077:       PetscInt        pStart, pEnd, n, p, k, l;

1079:       DMGetGlobalSection(dm, &sectionGlobal);
1080:       PetscSectionGetChart(section, &pStart, &pEnd);
1081:       PetscSectionGetStorageSize(section, &n);
1082:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
1083:       for (p = pStart, l = 0; p < pEnd; ++p) {
1084:         PetscInt bdof, cdof, dof, off, c, cind;

1086:         /* Should probably use constrained dofs */
1087:         PetscSectionGetDof(section, p, &dof);
1088:         PetscSectionGetConstraintDof(section, p, &cdof);
1089:         PetscSectionGetConstraintIndices(section, p, &cdofs);
1090:         PetscSectionGetOffset(sectionGlobal, p, &off);
1091:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1092:         bdof = cdof && (dof - cdof) ? 1 : dof;
1093:         if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);

1095:         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1096:           if (cind < cdof && c == cdofs[cind]) {
1097:             ltog[l] = off < 0 ? off - c : -(off + c + 1);
1098:             cind++;
1099:           } else {
1100:             ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1101:           }
1102:         }
1103:       }
1104:       /* Must have same blocksize on all procs (some might have no points) */
1105:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs;
1106:       bsLocal[1] = bs;
1107:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax);
1108:       if (bsMinMax[0] != bsMinMax[1]) {
1109:         bs = 1;
1110:       } else {
1111:         bs = bsMinMax[0];
1112:       }
1113:       bs = bs < 0 ? 1 : bs;
1114:       /* Must reduce indices by blocksize */
1115:       if (bs > 1) {
1116:         for (l = 0, k = 0; l < n; l += bs, ++k) {
1117:           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1118:           ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1119:         }
1120:         n /= bs;
1121:       }
1122:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
1123:     } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1124:   }
1125:   *ltog = dm->ltogmap;
1126:   return 0;
1127: }

1129: /*@
1130:    DMGetBlockSize - Gets the inherent block size associated with a `DM`

1132:    Not Collective

1134:    Input Parameter:
1135: .  dm - the `DM` with block structure

1137:    Output Parameter:
1138: .  bs - the block size, 1 implies no exploitable block structure

1140:    Level: intermediate

1142:    Note:
1143:    This might be the number of degrees of freedom at each grid point for a structured grid.

1145:    Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1146:    rather different locations in the vectors may have a different block size.

1148: .seealso: `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1149: @*/
1150: PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1151: {
1155:   *bs = dm->bs;
1156:   return 0;
1157: }

1159: /*@C
1160:     DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1161:     `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.

1163:     Collective on dmc

1165:     Input Parameters:
1166: +   dmc - the `DM` object
1167: -   dmf - the second, finer `DM` object

1169:     Output Parameters:
1170: +  mat - the interpolation
1171: -  vec - the scaling (optional), see `DMCreateInterpolationScale()`

1173:     Level: developer

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

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

1182: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1183: @*/
1184: PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1185: {
1189:   PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0);
1190:   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1191:   PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0);
1192:   return 0;
1193: }

1195: /*@
1196:     DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is the transpose of the interpolation between the `DM`.
1197:     xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) restriction. In other words xcoarse is the coarse
1198:     representation of xfine.

1200:   Input Parameters:
1201: +      dac - `DM` that defines a coarse mesh
1202: .      daf - `DM` that defines a fine mesh
1203: -      mat - the restriction (or interpolation operator) from fine to coarse

1205:   Output Parameter:
1206: .    scale - the scaled vector

1208:   Level: advanced

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

1214: .seealso: `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, DMCreateRestriction()`, `DMCreateGlobalVector()`
1215: @*/
1216: PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1217: {
1218:   Vec         fine;
1219:   PetscScalar one = 1.0;
1220: #if defined(PETSC_HAVE_CUDA)
1221:   PetscBool bindingpropagates, isbound;
1222: #endif

1224:   DMCreateGlobalVector(daf, &fine);
1225:   DMCreateGlobalVector(dac, scale);
1226:   VecSet(fine, one);
1227: #if defined(PETSC_HAVE_CUDA)
1228:   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1229:    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1230:    * we'll need to do it for that case, too.*/
1231:   VecGetBindingPropagates(fine, &bindingpropagates);
1232:   if (bindingpropagates) {
1233:     MatSetBindingPropagates(mat, PETSC_TRUE);
1234:     VecBoundToCPU(fine, &isbound);
1235:     MatBindToCPU(mat, isbound);
1236:   }
1237: #endif
1238:   MatRestrict(mat, fine, *scale);
1239:   VecDestroy(&fine);
1240:   VecReciprocal(*scale);
1241:   return 0;
1242: }

1244: /*@
1245:     DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1246:     `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.

1248:     Collective on dmc

1250:     Input Parameters:
1251: +   dmc - the `DM` object
1252: -   dmf - the second, finer `DM` object

1254:     Output Parameter:
1255: .  mat - the restriction

1257:     Level: developer

1259:     Note:
1260:     This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1261:     matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.

1263: .seealso: `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1264: @*/
1265: PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1266: {
1270:   PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0);
1271:   PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1272:   PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0);
1273:   return 0;
1274: }

1276: /*@
1277:     DMCreateInjection - Gets injection matrix between two `DM` objects. This is an operator that applied to a vector obtained with
1278:     `DMCreateGlobalVector()` on the fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting the values
1279:     on the coarse grid points. This compares to the operator obtained by `DMCreateRestriction()` or the transpose of the operator obtained
1280:     by `DMCreateInterpolation()` that uses a "local weighted average" of the values around the coarse grid point as the coarse grid value.

1282:     Collective on dac

1284:     Input Parameters:
1285: +   dac - the `DM` object
1286: -   daf - the second, finer `DM` object

1288:     Output Parameter:
1289: .   mat - the injection

1291:     Level: developer

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

1297: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1298:           `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1299: @*/
1300: PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1301: {
1305:   PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0);
1306:   PetscUseTypeMethod(dac, createinjection, daf, mat);
1307:   PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0);
1308:   return 0;
1309: }

1311: /*@
1312:   DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1313:   a Galerkin finite element model on the `DM`

1315:   Collective on dac

1317:   Input Parameters:
1318: + dmc - the target `DM` object
1319: - dmf - the source `DM` object

1321:   Output Parameter:
1322: . mat - the mass matrix

1324:   Level: developer

1326:   Notes:
1327:   For `DMPLEX` the finite element model for the `DM` must have been already provided.

1329:   if dmc is dmf then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`

1331: .seealso: `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1332: @*/
1333: PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1334: {
1338:   PetscLogEventBegin(DM_CreateMassMatrix, 0, 0, 0, 0);
1339:   PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1340:   PetscLogEventEnd(DM_CreateMassMatrix, 0, 0, 0, 0);
1341:   return 0;
1342: }

1344: /*@
1345:   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`

1347:   Collective on dm

1349:   Input Parameter:
1350: . dm - the `DM` object

1352:   Output Parameter:
1353: . lm - the lumped mass matrix, which is a diagonal matrix, represented as a vector

1355:   Level: developer

1357:   Note:
1358:   See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.

1360: .seealso: `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1361: @*/
1362: PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *lm)
1363: {
1366:   PetscUseTypeMethod(dm, createmassmatrixlumped, lm);
1367:   return 0;
1368: }

1370: /*@
1371:     DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1372:     of a PDE on the `DM`.

1374:     Collective on dm

1376:     Input Parameters:
1377: +   dm - the `DM` object
1378: -   ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`

1380:     Output Parameter:
1381: .   coloring - the coloring

1383:     Notes:
1384:     Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1385:     matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).

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

1389:     Level: developer

1391: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1392: @*/
1393: PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1394: {
1397:   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1398:   return 0;
1399: }

1401: /*@
1402:     DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.

1404:     Collective on dm

1406:     Input Parameter:
1407: .   dm - the `DM` object

1409:     Output Parameter:
1410: .   mat - the empty Jacobian

1412:     Level: beginner

1414:     Options Database Keys:
1415: . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros

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

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

1424:     For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1425:     internally by PETSc.

1427:     For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1428:     `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute

1430: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1431: @*/
1432: PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1433: {
1436:   MatInitializePackage();
1437:   PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0);
1438:   PetscUseTypeMethod(dm, creatematrix, mat);
1439:   if (PetscDefined(USE_DEBUG)) {
1440:     DM mdm;

1442:     MatGetDM(*mat, &mdm);
1444:   }
1445:   /* Handle nullspace and near nullspace */
1446:   if (dm->Nf) {
1447:     MatNullSpace nullSpace;
1448:     PetscInt     Nf, f;

1450:     DMGetNumFields(dm, &Nf);
1451:     for (f = 0; f < Nf; ++f) {
1452:       if (dm->nullspaceConstructors[f]) {
1453:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
1454:         MatSetNullSpace(*mat, nullSpace);
1455:         MatNullSpaceDestroy(&nullSpace);
1456:         break;
1457:       }
1458:     }
1459:     for (f = 0; f < Nf; ++f) {
1460:       if (dm->nearnullspaceConstructors[f]) {
1461:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
1462:         MatSetNearNullSpace(*mat, nullSpace);
1463:         MatNullSpaceDestroy(&nullSpace);
1464:       }
1465:     }
1466:   }
1467:   PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0);
1468:   return 0;
1469: }

1471: /*@
1472:   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and `ISLocalToGlobalMapping` will be
1473:   properly set, but the data structures to store values in the matrices will not be preallocated. This is most useful to reduce initialization costs when
1474:   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` will be used.

1476:   Logically Collective on dm

1478:   Input Parameters:
1479: + dm - the `DM`
1480: - skip - `PETSC_TRUE` to skip preallocation

1482:   Level: developer

1484: .seealso: `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1485: @*/
1486: PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1487: {
1489:   dm->prealloc_skip = skip;
1490:   return 0;
1491: }

1493: /*@
1494:   DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1495:     preallocated but the nonzero structure and zero values will not be set.

1497:   Logically Collective on dm

1499:   Input Parameters:
1500: + dm - the `DM`
1501: - only - `PETSC_TRUE` if only want preallocation

1503:   Level: developer

1505:   Options Database Keys:
1506: . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros

1508: .seealso: `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1509: @*/
1510: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1511: {
1513:   dm->prealloc_only = only;
1514:   return 0;
1515: }

1517: /*@
1518:   DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created
1519:     but the array for numerical values will not be allocated.

1521:   Logically Collective on dm

1523:   Input Parameters:
1524: + dm - the `DM`
1525: - only - `PETSC_TRUE` if you only want matrix structure

1527:   Level: developer

1529: .seealso: `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1530: @*/
1531: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1532: {
1534:   dm->structure_only = only;
1535:   return 0;
1536: }

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

1541:   Not Collective

1543:   Input Parameters:
1544: + dm - the `DM` object
1545: . count - The minimum size
1546: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, or MPIU_INT)

1548:   Output Parameter:
1549: . array - the work array

1551:   Level: developer

1553:   Note:
1554:   A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`

1556:   The array may contain nonzero values

1558: .seealso: `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1559: @*/
1560: PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1561: {
1562:   DMWorkLink  link;
1563:   PetscMPIInt dsize;

1567:   if (dm->workin) {
1568:     link       = dm->workin;
1569:     dm->workin = dm->workin->next;
1570:   } else {
1571:     PetscNew(&link);
1572:   }
1573:   MPI_Type_size(dtype, &dsize);
1574:   if (((size_t)dsize * count) > link->bytes) {
1575:     PetscFree(link->mem);
1576:     PetscMalloc(dsize * count, &link->mem);
1577:     link->bytes = dsize * count;
1578:   }
1579:   link->next  = dm->workout;
1580:   dm->workout = link;
1581: #if defined(__MEMCHECK_H) && (defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin))
1582:   VALGRIND_MAKE_MEM_NOACCESS((char *)link->mem + (size_t)dsize * count, link->bytes - (size_t)dsize * count);
1583:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize * count);
1584: #endif
1585:   *(void **)mem = link->mem;
1586:   return 0;
1587: }

1589: /*@C
1590:   DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`

1592:   Not Collective

1594:   Input Parameters:
1595: + dm - the `DM` object
1596: . count - The minimum size
1597: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

1599:   Output Parameter:
1600: . array - the work array

1602:   Level: developer

1604:   Developer Notes:
1605:   count and dtype are ignored, they are only needed for `DMGetWorkArray()`

1607: .seealso: `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1608: @*/
1609: PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1610: {
1611:   DMWorkLink *p, link;

1615:   for (p = &dm->workout; (link = *p); p = &link->next) {
1616:     if (link->mem == *(void **)mem) {
1617:       *p            = link->next;
1618:       link->next    = dm->workin;
1619:       dm->workin    = link;
1620:       *(void **)mem = NULL;
1621:       return 0;
1622:     }
1623:   }
1624:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1625: }

1627: /*@C
1628:   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1629:   are joined or split, such as in `DMCreateSubDM()`

1631:   Logically collective on dm

1633:   Input Parameters:
1634: + dm     - The `DM`
1635: . field  - The field number for the nullspace
1636: - nullsp - A callback to create the nullspace

1638:   Calling sequence of nullsp:
1639: .vb
1640:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1641: .ve
1642: +  dm        - The present `DM`
1643: .  origField - The field number given above, in the original `DM`
1644: .  field     - The field number in dm
1645: -  nullSpace - The nullspace for the given field

1647:   Level: intermediate

1649:   Fortran Notes:
1650:   This function is not available from Fortran.

1652: .seealso: `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1653: @*/
1654: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1655: {
1658:   dm->nullspaceConstructors[field] = nullsp;
1659:   return 0;
1660: }

1662: /*@C
1663:   DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`

1665:   Not collective

1667:   Input Parameters:
1668: + dm     - The `DM`
1669: - field  - The field number for the nullspace

1671:   Output Parameter:
1672: . nullsp - A callback to create the nullspace

1674:   Calling sequence of nullsp:
1675: .vb
1676:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1677: .ve
1678: +  dm        - The present DM
1679: .  origField - The field number given above, in the original DM
1680: .  field     - The field number in dm
1681: -  nullSpace - The nullspace for the given field

1683:   Fortran Note:
1684:   This function is not available from Fortran.

1686:    Level: intermediate

1688: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1689: @*/
1690: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1691: {
1695:   *nullsp = dm->nullspaceConstructors[field];
1696:   return 0;
1697: }

1699: /*@C
1700:   DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`

1702:   Logically collective on dm

1704:   Input Parameters:
1705: + dm     - The `DM`
1706: . field  - The field number for the nullspace
1707: - nullsp - A callback to create the near-nullspace

1709:   Calling sequence of nullsp:
1710: .vb
1711:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1712: .ve
1713: +  dm        - The present `DM`
1714: .  origField - The field number given above, in the original `DM`
1715: .  field     - The field number in dm
1716: -  nullSpace - The nullspace for the given field

1718:   Fortran Note:
1719:   This function is not available from Fortran.

1721:    Level: intermediate

1723: .seealso: `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1724:           `MatNullSpace`
1725: @*/
1726: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1727: {
1730:   dm->nearnullspaceConstructors[field] = nullsp;
1731:   return 0;
1732: }

1734: /*@C
1735:   DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`

1737:   Not collective

1739:   Input Parameters:
1740: + dm     - The `DM`
1741: - field  - The field number for the nullspace

1743:   Output Parameter:
1744: . nullsp - A callback to create the near-nullspace

1746:   Calling sequence of nullsp:
1747: .vb
1748:     PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
1749: .ve
1750: +  dm        - The present `DM`
1751: .  origField - The field number given above, in the original `DM`
1752: .  field     - The field number in dm
1753: -  nullSpace - The nullspace for the given field

1755:   Fortran Note:
1756:   This function is not available from Fortran.

1758:    Level: intermediate

1760: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1761:           `MatNullSpace`, `DMCreateSuperDM()`
1762: @*/
1763: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1764: {
1768:   *nullsp = dm->nearnullspaceConstructors[field];
1769:   return 0;
1770: }

1772: /*@C
1773:   DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`

1775:   Not collective

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

1780:   Output Parameters:
1781: + numFields  - The number of fields (or NULL if not requested)
1782: . fieldNames - The number of each field (or NULL if not requested)
1783: - fields     - The global indices for each field (or NULL if not requested)

1785:   Level: intermediate

1787:   Note:
1788:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1789:   `PetscFree()`, every entry of fields should be destroyed with `ISDestroy()`, and both arrays should be freed with
1790:   `PetscFree()`.

1792:   Fortran Note:
1793:   Not available in Fortran.

1795:   Developer Note:
1796:   It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1797:   likely be removed.

1799: .seealso: `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1800:           `DMCreateFieldDecomposition()`
1801: @*/
1802: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1803: {
1804:   PetscSection section, sectionGlobal;

1807:   if (numFields) {
1809:     *numFields = 0;
1810:   }
1811:   if (fieldNames) {
1813:     *fieldNames = NULL;
1814:   }
1815:   if (fields) {
1817:     *fields = NULL;
1818:   }
1819:   DMGetLocalSection(dm, &section);
1820:   if (section) {
1821:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1822:     PetscInt  nF, f, pStart, pEnd, p;

1824:     DMGetGlobalSection(dm, &sectionGlobal);
1825:     PetscSectionGetNumFields(section, &nF);
1826:     PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices);
1827:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
1828:     for (f = 0; f < nF; ++f) {
1829:       fieldSizes[f] = 0;
1830:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
1831:     }
1832:     for (p = pStart; p < pEnd; ++p) {
1833:       PetscInt gdof;

1835:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1836:       if (gdof > 0) {
1837:         for (f = 0; f < nF; ++f) {
1838:           PetscInt fdof, fcdof, fpdof;

1840:           PetscSectionGetFieldDof(section, p, f, &fdof);
1841:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1842:           fpdof = fdof - fcdof;
1843:           if (fpdof && fpdof != fieldNc[f]) {
1844:             /* Layout does not admit a pointwise block size */
1845:             fieldNc[f] = 1;
1846:           }
1847:           fieldSizes[f] += fpdof;
1848:         }
1849:       }
1850:     }
1851:     for (f = 0; f < nF; ++f) {
1852:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
1853:       fieldSizes[f] = 0;
1854:     }
1855:     for (p = pStart; p < pEnd; ++p) {
1856:       PetscInt gdof, goff;

1858:       PetscSectionGetDof(sectionGlobal, p, &gdof);
1859:       if (gdof > 0) {
1860:         PetscSectionGetOffset(sectionGlobal, p, &goff);
1861:         for (f = 0; f < nF; ++f) {
1862:           PetscInt fdof, fcdof, fc;

1864:           PetscSectionGetFieldDof(section, p, f, &fdof);
1865:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
1866:           for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
1867:         }
1868:       }
1869:     }
1870:     if (numFields) *numFields = nF;
1871:     if (fieldNames) {
1872:       PetscMalloc1(nF, fieldNames);
1873:       for (f = 0; f < nF; ++f) {
1874:         const char *fieldName;

1876:         PetscSectionGetFieldName(section, f, &fieldName);
1877:         PetscStrallocpy(fieldName, (char **)&(*fieldNames)[f]);
1878:       }
1879:     }
1880:     if (fields) {
1881:       PetscMalloc1(nF, fields);
1882:       for (f = 0; f < nF; ++f) {
1883:         PetscInt bs, in[2], out[2];

1885:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
1886:         in[0] = -fieldNc[f];
1887:         in[1] = fieldNc[f];
1888:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
1889:         bs = (-out[0] == out[1]) ? out[1] : 1;
1890:         ISSetBlockSize((*fields)[f], bs);
1891:       }
1892:     }
1893:     PetscFree3(fieldSizes, fieldNc, fieldIndices);
1894:   } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
1895:   return 0;
1896: }

1898: /*@C
1899:   DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
1900:                           corresponding to different fields: each `IS` contains the global indices of the dofs of the
1901:                           corresponding field, defined by `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
1902:                           The same as `DMCreateFieldIS()` but also returns a `DM` for each field.

1904:   Not collective

1906:   Input Parameter:
1907: . dm - the `DM` object

1909:   Output Parameters:
1910: + len       - The number of fields (or NULL if not requested)
1911: . namelist  - The name for each field (or NULL if not requested)
1912: . islist    - The global indices for each field (or NULL if not requested)
1913: - dmlist    - The `DM`s for each field subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined)

1915:   Level: intermediate

1917:   Note:
1918:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1919:   `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`,
1920:   and all of the arrays should be freed with `PetscFree()`.

1922:   Fortran Note:
1923:   Not available in Fortran.

1925:   Developer Note:
1926:   It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.

1928: .seealso: `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
1929: @*/
1930: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1931: {
1933:   if (len) {
1935:     *len = 0;
1936:   }
1937:   if (namelist) {
1939:     *namelist = NULL;
1940:   }
1941:   if (islist) {
1943:     *islist = NULL;
1944:   }
1945:   if (dmlist) {
1947:     *dmlist = NULL;
1948:   }
1949:   /*
1950:    Is it a good idea to apply the following check across all impls?
1951:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1952:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1953:    */
1955:   if (!dm->ops->createfielddecomposition) {
1956:     PetscSection section;
1957:     PetscInt     numFields, f;

1959:     DMGetLocalSection(dm, &section);
1960:     if (section) PetscSectionGetNumFields(section, &numFields);
1961:     if (section && numFields && dm->ops->createsubdm) {
1962:       if (len) *len = numFields;
1963:       if (namelist) PetscMalloc1(numFields, namelist);
1964:       if (islist) PetscMalloc1(numFields, islist);
1965:       if (dmlist) PetscMalloc1(numFields, dmlist);
1966:       for (f = 0; f < numFields; ++f) {
1967:         const char *fieldName;

1969:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
1970:         if (namelist) {
1971:           PetscSectionGetFieldName(section, f, &fieldName);
1972:           PetscStrallocpy(fieldName, (char **)&(*namelist)[f]);
1973:         }
1974:       }
1975:     } else {
1976:       DMCreateFieldIS(dm, len, namelist, islist);
1977:       /* By default there are no DMs associated with subproblems. */
1978:       if (dmlist) *dmlist = NULL;
1979:     }
1980:   } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
1981:   return 0;
1982: }

1984: /*@C
1985:   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1986:                   The fields are defined by DMCreateFieldIS().

1988:   Not collective

1990:   Input Parameters:
1991: + dm        - The `DM `object
1992: . numFields - The number of fields to select
1993: - fields    - The field numbers of the selected fields

1995:   Output Parameters:
1996: + is - The global indices for all the degrees of freedom in the new sub `DM`
1997: - subdm - The `DM` for the subproblem

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

2002:   Level: intermediate

2004: .seealso: `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `DM`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2005: @*/
2006: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2007: {
2012:   PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2013:   return 0;
2014: }

2016: /*@C
2017:   DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in.

2019:   Not collective

2021:   Input Parameters:
2022: + dms - The `DM` objects
2023: - n - The number of `DM`s

2025:   Output Parameters:
2026: + is - The global indices for each of subproblem within the super `DM`, or NULL
2027: - superdm - The `DM` for the superproblem

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

2032:   Level: intermediate

2034: .seealso: `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2035: @*/
2036: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS **is, DM *superdm)
2037: {
2038:   PetscInt i;

2045:   if (n) {
2046:     DM dm = dms[0];
2047:     (*dm->ops->createsuperdm)(dms, n, is, superdm);
2048:   }
2049:   return 0;
2050: }

2052: /*@C
2053:   DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a problem into subproblems
2054:                           corresponding to restrictions to pairs of nested subdomains: each `IS` contains the global
2055:                           indices of the dofs of the corresponding subdomains with in the dofs of the original `DM`.
2056:                           The inner subdomains conceptually define a nonoverlapping covering, while outer subdomains can overlap.
2057:                           The optional list of `DM`s define a `DM` for each subproblem.

2059:   Not collective

2061:   Input Parameter:
2062: . dm - the `DM` object

2064:   Output Parameters:
2065: + n            - The number of subproblems in the domain decomposition (or NULL if not requested)
2066: . namelist    - The name for each subdomain (or NULL if not requested)
2067: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
2068: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
2069: - dmlist      - The `DM`s for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined)

2071:   Level: intermediate

2073:   Note:
2074:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
2075:   `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`,
2076:   and all of the arrays should be freed with `PetscFree()`.

2078:   Questions:
2079:   The dmlist is for the inner subdomains or the outer subdomains or all subdomains?

2081: .seealso: `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldDecomposition()`
2082: @*/
2083: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2084: {
2085:   DMSubDomainHookLink link;
2086:   PetscInt            i, l;

2089:   if (n) {
2091:     *n = 0;
2092:   }
2093:   if (namelist) {
2095:     *namelist = NULL;
2096:   }
2097:   if (innerislist) {
2099:     *innerislist = NULL;
2100:   }
2101:   if (outerislist) {
2103:     *outerislist = NULL;
2104:   }
2105:   if (dmlist) {
2107:     *dmlist = NULL;
2108:   }
2109:   /*
2110:    Is it a good idea to apply the following check across all impls?
2111:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2112:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2113:    */
2115:   if (dm->ops->createdomaindecomposition) {
2116:     PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2117:     /* copy subdomain hooks and context over to the subdomain DMs */
2118:     if (dmlist && *dmlist) {
2119:       for (i = 0; i < l; i++) {
2120:         for (link = dm->subdomainhook; link; link = link->next) {
2121:           if (link->ddhook) (*link->ddhook)(dm, (*dmlist)[i], link->ctx);
2122:         }
2123:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2124:       }
2125:     }
2126:     if (n) *n = l;
2127:   }
2128:   return 0;
2129: }

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

2134:   Not collective

2136:   Input Parameters:
2137: + dm - the `DM` object
2138: . n  - the number of subdomain scatters
2139: - subdms - the local subdomains

2141:   Output Parameters:
2142: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2143: . oscat - scatter from global vector to overlapping global vector entries on subdomain
2144: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

2146:   Note:
2147:     This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2148:   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
2149:   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2150:   solution and residual data.

2152:   Questions:
2153:   Can the subdms input be anything or are they exactly the `DM` obtained from `DMCreateDomainDecomposition()`?

2155:   Level: developer

2157: .seealso: `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2158: @*/
2159: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **gscat)
2160: {
2163:   PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2164:   return 0;
2165: }

2167: /*@
2168:   DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh

2170:   Collective on dm

2172:   Input Parameters:
2173: + dm   - the `DM` object
2174: - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)

2176:   Output Parameter:
2177: . dmf - the refined `D`M, or NULL

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

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

2185:   Level: developer

2187: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2188: @*/
2189: PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2190: {
2191:   DMRefineHookLink link;

2194:   PetscLogEventBegin(DM_Refine, dm, 0, 0, 0);
2195:   PetscUseTypeMethod(dm, refine, comm, dmf);
2196:   if (*dmf) {
2197:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2201:     (*dmf)->ctx       = dm->ctx;
2202:     (*dmf)->leveldown = dm->leveldown;
2203:     (*dmf)->levelup   = dm->levelup + 1;

2205:     DMSetMatType(*dmf, dm->mattype);
2206:     for (link = dm->refinehook; link; link = link->next) {
2207:       if (link->refinehook) (*link->refinehook)(dm, *dmf, link->ctx);
2208:     }
2209:   }
2210:   PetscLogEventEnd(DM_Refine, dm, 0, 0, 0);
2211:   return 0;
2212: }

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

2217:    Logically Collective on coarse

2219:    Input Parameters:
2220: +  coarse - `DM` on which to run a hook when interpolating to a finer level
2221: .  refinehook - function to run when setting up the finer level
2222: .  interphook - function to run to update data on finer levels (once per `SNESSolve`())
2223: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2228: +  coarse - coarse level `DM`
2229: .  fine - fine level `DM` to interpolate problem to
2230: -  ctx - optional user-defined function context

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

2235: +  coarse - coarse level `DM`
2236: .  interp - matrix interpolating a coarse-level solution to the finer grid
2237: .  fine - fine level `DM` to update
2238: -  ctx - optional user-defined function context

2240:    Level: advanced

2242:    Notes:
2243:    This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2244:    passed to fine grids while grid sequencing.

2246:    The actual interpolation is done when `DMInterpolate()` is called.

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

2250:    Fortran Note:
2251:    This function is not available from Fortran.

2253: .seealso: `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2254: @*/
2255: PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2256: {
2257:   DMRefineHookLink link, *p;

2260:   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2261:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return 0;
2262:   }
2263:   PetscNew(&link);
2264:   link->refinehook = refinehook;
2265:   link->interphook = interphook;
2266:   link->ctx        = ctx;
2267:   link->next       = NULL;
2268:   *p               = link;
2269:   return 0;
2270: }

2272: /*@C
2273:    DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2274:     a nonlinear problem to a finer grid

2276:    Logically Collective on coarse

2278:    Input Parameters:
2279: +  coarse - the `DM` on which to run a hook when restricting to a coarser level
2280: .  refinehook - function to run when setting up a finer level
2281: .  interphook - function to run to update data on finer levels
2282: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

2284:    Level: advanced

2286:    Note:
2287:    This function does nothing if the hook is not in the list.

2289:    Fortran Note:
2290:    This function is not available from Fortran.

2292: .seealso: `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2293: @*/
2294: PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2295: {
2296:   DMRefineHookLink link, *p;

2299:   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2300:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2301:       link = *p;
2302:       *p   = link->next;
2303:       PetscFree(link);
2304:       break;
2305:     }
2306:   }
2307:   return 0;
2308: }

2310: /*@
2311:    DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`

2313:    Collective if any hooks are

2315:    Input Parameters:
2316: +  coarse - coarser `DM` to use as a base
2317: .  interp - interpolation matrix, apply using `MatInterpolate()`
2318: -  fine - finer `DM` to update

2320:    Level: developer

2322:    Developer Note:
2323:    This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2324:    an API with consistent terminology.

2326: .seealso: `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2327: @*/
2328: PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2329: {
2330:   DMRefineHookLink link;

2332:   for (link = fine->refinehook; link; link = link->next) {
2333:     if (link->interphook) (*link->interphook)(coarse, interp, fine, link->ctx);
2334:   }
2335:   return 0;
2336: }

2338: /*@
2339:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2341:    Collective on dm

2343:    Input Parameters:
2344: +  coarse - coarse `DM`
2345: .  fine   - fine `DM`
2346: .  interp - (optional) the matrix computed by `DMCreateInterpolation()`.  Implementations may not need this, but if it
2347:             is available it can avoid some recomputation.  If it is provided, `MatInterpolate()` will be used if
2348:             the coarse `DM` does not have a specialized implementation.
2349: -  coarseSol - solution on the coarse mesh

2351:    Output Parameter:
2352: .  fineSol - the interpolation of coarseSol to the fine mesh

2354:    Level: developer

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

2362:    Developer Note:
2363:    This doesn't just interpolate "solutions" so its API name is questionable.

2365: .seealso: `DMInterpolate()`, `DMCreateInterpolation()`
2366: @*/
2367: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2368: {
2369:   PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;


2376:   PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol);
2377:   if (interpsol) {
2378:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
2379:   } else if (interp) {
2380:     MatInterpolate(interp, coarseSol, fineSol);
2381:   } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2382:   return 0;
2383: }

2385: /*@
2386:     DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.

2388:     Not Collective

2390:     Input Parameter:
2391: .   dm - the `DM` object

2393:     Output Parameter:
2394: .   level - number of refinements

2396:     Level: developer

2398:     Note:
2399:     This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.

2401: .seealso: `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2402: @*/
2403: PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2404: {
2406:   *level = dm->levelup;
2407:   return 0;
2408: }

2410: /*@
2411:     DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.

2413:     Not Collective

2415:     Input Parameters:
2416: +   dm - the `DM` object
2417: -   level - number of refinements

2419:     Level: advanced

2421:     Notes:
2422:     This value is used by `PCMG` to determine how many multigrid levels to use

2424:     The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.

2426: .seealso: `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2427: @*/
2428: PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2429: {
2431:   dm->levelup = level;
2432:   return 0;
2433: }

2435: /*@
2436:   DMExtrude - Extrude a `DM` object from a surface

2438:   Collective on dm

2440:   Input Parameters:
2441: + dm     - the `DM` object
2442: - layers - the number of extruded cell layers

2444:   Output Parameter:
2445: . dme - the extruded `DM`, or NULL

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

2450:   Level: developer

2452: .seealso: `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2453: @*/
2454: PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2455: {
2457:   PetscUseTypeMethod(dm, extrude, layers, dme);
2458:   if (*dme) {
2459:     (*dme)->ops->creatematrix = dm->ops->creatematrix;
2460:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme);
2461:     (*dme)->ctx = dm->ctx;
2462:     DMSetMatType(*dme, dm->mattype);
2463:   }
2464:   return 0;
2465: }

2467: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2468: {
2471:   *tdm = dm->transformDM;
2472:   return 0;
2473: }

2475: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2476: {
2479:   *tv = dm->transform;
2480:   return 0;
2481: }

2483: /*@
2484:   DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors

2486:   Input Parameter:
2487: . dm - The DM

2489:   Output Parameter:
2490: . flg - PETSC_TRUE if a basis transformation should be done

2492:   Level: developer

2494: .seealso: `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2495: @*/
2496: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2497: {
2498:   Vec tv;

2502:   DMGetBasisTransformVec_Internal(dm, &tv);
2503:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2504:   return 0;
2505: }

2507: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2508: {
2509:   PetscSection s, ts;
2510:   PetscScalar *ta;
2511:   PetscInt     cdim, pStart, pEnd, p, Nf, f, Nc, dof;

2513:   DMGetCoordinateDim(dm, &cdim);
2514:   DMGetLocalSection(dm, &s);
2515:   PetscSectionGetChart(s, &pStart, &pEnd);
2516:   PetscSectionGetNumFields(s, &Nf);
2517:   DMClone(dm, &dm->transformDM);
2518:   DMGetLocalSection(dm->transformDM, &ts);
2519:   PetscSectionSetNumFields(ts, Nf);
2520:   PetscSectionSetChart(ts, pStart, pEnd);
2521:   for (f = 0; f < Nf; ++f) {
2522:     PetscSectionGetFieldComponents(s, f, &Nc);
2523:     /* We could start to label fields by their transformation properties */
2524:     if (Nc != cdim) continue;
2525:     for (p = pStart; p < pEnd; ++p) {
2526:       PetscSectionGetFieldDof(s, p, f, &dof);
2527:       if (!dof) continue;
2528:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
2529:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
2530:     }
2531:   }
2532:   PetscSectionSetUp(ts);
2533:   DMCreateLocalVector(dm->transformDM, &dm->transform);
2534:   VecGetArray(dm->transform, &ta);
2535:   for (p = pStart; p < pEnd; ++p) {
2536:     for (f = 0; f < Nf; ++f) {
2537:       PetscSectionGetFieldDof(ts, p, f, &dof);
2538:       if (dof) {
2539:         PetscReal          x[3] = {0.0, 0.0, 0.0};
2540:         PetscScalar       *tva;
2541:         const PetscScalar *A;

2543:         /* TODO Get quadrature point for this dual basis vector for coordinate */
2544:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
2545:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva);
2546:         PetscArraycpy(tva, A, PetscSqr(cdim));
2547:       }
2548:     }
2549:   }
2550:   VecRestoreArray(dm->transform, &ta);
2551:   return 0;
2552: }

2554: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2555: {
2558:   newdm->transformCtx       = dm->transformCtx;
2559:   newdm->transformSetUp     = dm->transformSetUp;
2560:   newdm->transformDestroy   = NULL;
2561:   newdm->transformGetMatrix = dm->transformGetMatrix;
2562:   if (newdm->transformSetUp) DMConstructBasisTransform_Internal(newdm);
2563:   return 0;
2564: }

2566: /*@C
2567:    DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called

2569:    Logically Collective on dm

2571:    Input Parameters:
2572: +  dm - the `DM`
2573: .  beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2574: .  endhook - function to run after `DMGlobalToLocalEnd()` has completed
2575: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2580: +  dm - global DM
2581: .  g - global vector
2582: .  mode - mode
2583: .  l - local vector
2584: -  ctx - optional user-defined function context

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

2589: +  global - global DM
2590: -  ctx - optional user-defined function context

2592:    Level: advanced

2594:    Note:
2595:    The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.

2597: .seealso: `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2598: @*/
2599: PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx)
2600: {
2601:   DMGlobalToLocalHookLink link, *p;

2604:   for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2605:   PetscNew(&link);
2606:   link->beginhook = beginhook;
2607:   link->endhook   = endhook;
2608:   link->ctx       = ctx;
2609:   link->next      = NULL;
2610:   *p              = link;
2611:   return 0;
2612: }

2614: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2615: {
2616:   Mat          cMat;
2617:   Vec          cVec, cBias;
2618:   PetscSection section, cSec;
2619:   PetscInt     pStart, pEnd, p, dof;

2622:   DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias);
2623:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2624:     PetscInt nRows;

2626:     MatGetSize(cMat, &nRows, NULL);
2627:     if (nRows <= 0) return 0;
2628:     DMGetLocalSection(dm, &section);
2629:     MatCreateVecs(cMat, NULL, &cVec);
2630:     MatMult(cMat, l, cVec);
2631:     if (cBias) VecAXPY(cVec, 1., cBias);
2632:     PetscSectionGetChart(cSec, &pStart, &pEnd);
2633:     for (p = pStart; p < pEnd; p++) {
2634:       PetscSectionGetDof(cSec, p, &dof);
2635:       if (dof) {
2636:         PetscScalar *vals;
2637:         VecGetValuesSection(cVec, cSec, p, &vals);
2638:         VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES);
2639:       }
2640:     }
2641:     VecDestroy(&cVec);
2642:   }
2643:   return 0;
2644: }

2646: /*@
2647:     DMGlobalToLocal - update local vectors from global vector

2649:     Neighbor-wise Collective on dm

2651:     Input Parameters:
2652: +   dm - the `DM` object
2653: .   g - the global vector
2654: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2655: -   l - the local vector

2657:     Notes:
2658:     The communication involved in this update can be overlapped with computation by instead using
2659:     `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.

2661:     `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.

2663:     Level: beginner

2665: .seealso: `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2666:           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`,
2667:           `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2668: @*/
2669: PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2670: {
2671:   DMGlobalToLocalBegin(dm, g, mode, l);
2672:   DMGlobalToLocalEnd(dm, g, mode, l);
2673:   return 0;
2674: }

2676: /*@
2677:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2679:     Neighbor-wise Collective on dm

2681:     Input Parameters:
2682: +   dm - the `DM` object
2683: .   g - the global vector
2684: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2685: -   l - the local vector

2687:     Level: intermediate

2689:     Notes:
2690:     The operation is completed with `DMGlobalToLocalEnd()`

2692:     One can perform local computations between the `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()` to overlap communication and computation

2694:     `DMGlobalToLocal()` is a short form of  `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()`

2696:     `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.

2698: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`
2699: @*/
2700: PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2701: {
2702:   PetscSF                 sf;
2703:   DMGlobalToLocalHookLink link;

2706:   for (link = dm->gtolhook; link; link = link->next) {
2707:     if (link->beginhook) (*link->beginhook)(dm, g, mode, l, link->ctx);
2708:   }
2709:   DMGetSectionSF(dm, &sf);
2710:   if (sf) {
2711:     const PetscScalar *gArray;
2712:     PetscScalar       *lArray;
2713:     PetscMemType       lmtype, gmtype;

2716:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2717:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2718:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2719:     VecRestoreArrayAndMemType(l, &lArray);
2720:     VecRestoreArrayReadAndMemType(g, &gArray);
2721:   } else {
2722:     (*dm->ops->globaltolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2723:   }
2724:   return 0;
2725: }

2727: /*@
2728:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2730:     Neighbor-wise Collective on dm

2732:     Input Parameters:
2733: +   dm - the `DM` object
2734: .   g - the global vector
2735: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2736: -   l - the local vector

2738:     Level: intermediate

2740:     Note:
2741:     See `DMGlobalToLocalBegin()` for details.

2743: .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`
2744: @*/
2745: PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2746: {
2747:   PetscSF                 sf;
2748:   const PetscScalar      *gArray;
2749:   PetscScalar            *lArray;
2750:   PetscBool               transform;
2751:   DMGlobalToLocalHookLink link;
2752:   PetscMemType            lmtype, gmtype;

2755:   DMGetSectionSF(dm, &sf);
2756:   DMHasBasisTransform(dm, &transform);
2757:   if (sf) {

2760:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2761:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2762:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE);
2763:     VecRestoreArrayAndMemType(l, &lArray);
2764:     VecRestoreArrayReadAndMemType(g, &gArray);
2765:     if (transform) DMPlexGlobalToLocalBasis(dm, l);
2766:   } else {
2767:     (*dm->ops->globaltolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2768:   }
2769:   DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL);
2770:   for (link = dm->gtolhook; link; link = link->next) {
2771:     if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
2772:   }
2773:   return 0;
2774: }

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

2779:    Logically Collective on dm

2781:    Input Parameters:
2782: +  dm - the `DM`
2783: .  beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2784: .  endhook - function to run after `DMLocalToGlobalEnd()` has completed
2785: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

2790: +  dm - global `DM`
2791: .  l - local vector
2792: .  mode - mode
2793: .  g - global vector
2794: -  ctx - optional user-defined function context

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

2799: +  global - global `DM`
2800: .  l - local vector
2801: .  mode - mode
2802: .  g - global vector
2803: -  ctx - optional user-defined function context

2805:    Level: advanced

2807: .seealso: `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2808: @*/
2809: PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx)
2810: {
2811:   DMLocalToGlobalHookLink link, *p;

2814:   for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2815:   PetscNew(&link);
2816:   link->beginhook = beginhook;
2817:   link->endhook   = endhook;
2818:   link->ctx       = ctx;
2819:   link->next      = NULL;
2820:   *p              = link;
2821:   return 0;
2822: }

2824: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2825: {
2826:   Mat          cMat;
2827:   Vec          cVec;
2828:   PetscSection section, cSec;
2829:   PetscInt     pStart, pEnd, p, dof;

2832:   DMGetDefaultConstraints(dm, &cSec, &cMat, NULL);
2833:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2834:     PetscInt nRows;

2836:     MatGetSize(cMat, &nRows, NULL);
2837:     if (nRows <= 0) return 0;
2838:     DMGetLocalSection(dm, &section);
2839:     MatCreateVecs(cMat, NULL, &cVec);
2840:     PetscSectionGetChart(cSec, &pStart, &pEnd);
2841:     for (p = pStart; p < pEnd; p++) {
2842:       PetscSectionGetDof(cSec, p, &dof);
2843:       if (dof) {
2844:         PetscInt     d;
2845:         PetscScalar *vals;
2846:         VecGetValuesSection(l, section, p, &vals);
2847:         VecSetValuesSection(cVec, cSec, p, vals, mode);
2848:         /* for this to be the true transpose, we have to zero the values that
2849:          * we just extracted */
2850:         for (d = 0; d < dof; d++) vals[d] = 0.;
2851:       }
2852:     }
2853:     MatMultTransposeAdd(cMat, cVec, l, l);
2854:     VecDestroy(&cVec);
2855:   }
2856:   return 0;
2857: }
2858: /*@
2859:     DMLocalToGlobal - updates global vectors from local vectors

2861:     Neighbor-wise Collective on dm

2863:     Input Parameters:
2864: +   dm - the `DM` object
2865: .   l - the local vector
2866: .   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.
2867: -   g - the global vector

2869:     Notes:
2870:     The communication involved in this update can be overlapped with computation by using
2871:     `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.

2873:     In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.

2875:     `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.

2877:     Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process

2879:     Level: beginner

2881: .seealso: `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`,  `DMGlobaToLocallHookAdd()`
2882: @*/
2883: PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
2884: {
2885:   DMLocalToGlobalBegin(dm, l, mode, g);
2886:   DMLocalToGlobalEnd(dm, l, mode, g);
2887:   return 0;
2888: }

2890: /*@
2891:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2893:     Neighbor-wise Collective on dm

2895:     Input Parameters:
2896: +   dm - the `DM` object
2897: .   l - the local vector
2898: .   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.
2899: -   g - the global vector

2901:     Notes:
2902:     In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.

2904:     `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.

2906:     Use `DMLocalToGlobalEnd()` to complete the communication process.

2908:     `DMLocalToGlobal()` is a short form of  `DMLocalToGlobalBegin()` and  `DMLocalToGlobalEnd()`

2910:     `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.

2912:     Level: intermediate

2914: .seealso: `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
2915: @*/
2916: PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
2917: {
2918:   PetscSF                 sf;
2919:   PetscSection            s, gs;
2920:   DMLocalToGlobalHookLink link;
2921:   Vec                     tmpl;
2922:   const PetscScalar      *lArray;
2923:   PetscScalar            *gArray;
2924:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2925:   PetscMemType            lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;

2928:   for (link = dm->ltoghook; link; link = link->next) {
2929:     if (link->beginhook) (*link->beginhook)(dm, l, mode, g, link->ctx);
2930:   }
2931:   DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL);
2932:   DMGetSectionSF(dm, &sf);
2933:   DMGetLocalSection(dm, &s);
2934:   switch (mode) {
2935:   case INSERT_VALUES:
2936:   case INSERT_ALL_VALUES:
2937:   case INSERT_BC_VALUES:
2938:     isInsert = PETSC_TRUE;
2939:     break;
2940:   case ADD_VALUES:
2941:   case ADD_ALL_VALUES:
2942:   case ADD_BC_VALUES:
2943:     isInsert = PETSC_FALSE;
2944:     break;
2945:   default:
2946:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
2947:   }
2948:   if ((sf && !isInsert) || (s && isInsert)) {
2949:     DMHasBasisTransform(dm, &transform);
2950:     if (transform) {
2951:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
2952:       VecCopy(l, tmpl);
2953:       DMPlexLocalToGlobalBasis(dm, tmpl);
2954:       VecGetArrayRead(tmpl, &lArray);
2955:     } else if (isInsert) {
2956:       VecGetArrayRead(l, &lArray);
2957:     } else {
2958:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
2959:       l_inplace = PETSC_TRUE;
2960:     }
2961:     if (s && isInsert) {
2962:       VecGetArray(g, &gArray);
2963:     } else {
2964:       VecGetArrayAndMemType(g, &gArray, &gmtype);
2965:       g_inplace = PETSC_TRUE;
2966:     }
2967:     if (sf && !isInsert) {
2968:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
2969:     } else if (s && isInsert) {
2970:       PetscInt gStart, pStart, pEnd, p;

2972:       DMGetGlobalSection(dm, &gs);
2973:       PetscSectionGetChart(s, &pStart, &pEnd);
2974:       VecGetOwnershipRange(g, &gStart, NULL);
2975:       for (p = pStart; p < pEnd; ++p) {
2976:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2978:         PetscSectionGetDof(s, p, &dof);
2979:         PetscSectionGetDof(gs, p, &gdof);
2980:         PetscSectionGetConstraintDof(s, p, &cdof);
2981:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2982:         PetscSectionGetOffset(s, p, &off);
2983:         PetscSectionGetOffset(gs, p, &goff);
2984:         /* Ignore off-process data and points with no global data */
2985:         if (!gdof || goff < 0) continue;
2987:         /* If no constraints are enforced in the global vector */
2988:         if (!gcdof) {
2989:           for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
2990:           /* If constraints are enforced in the global vector */
2991:         } else if (cdof == gcdof) {
2992:           const PetscInt *cdofs;
2993:           PetscInt        cind = 0;

2995:           PetscSectionGetConstraintIndices(s, p, &cdofs);
2996:           for (d = 0, e = 0; d < dof; ++d) {
2997:             if ((cind < cdof) && (d == cdofs[cind])) {
2998:               ++cind;
2999:               continue;
3000:             }
3001:             gArray[goff - gStart + e++] = lArray[off + d];
3002:           }
3003:         } 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);
3004:       }
3005:     }
3006:     if (g_inplace) {
3007:       VecRestoreArrayAndMemType(g, &gArray);
3008:     } else {
3009:       VecRestoreArray(g, &gArray);
3010:     }
3011:     if (transform) {
3012:       VecRestoreArrayRead(tmpl, &lArray);
3013:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3014:     } else if (l_inplace) {
3015:       VecRestoreArrayReadAndMemType(l, &lArray);
3016:     } else {
3017:       VecRestoreArrayRead(l, &lArray);
3018:     }
3019:   } else {
3020:     (*dm->ops->localtoglobalbegin)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3021:   }
3022:   return 0;
3023: }

3025: /*@
3026:     DMLocalToGlobalEnd - updates global vectors from local vectors

3028:     Neighbor-wise Collective on dm

3030:     Input Parameters:
3031: +   dm - the `DM` object
3032: .   l - the local vector
3033: .   mode - `INSERT_VALUES` or `ADD_VALUES`
3034: -   g - the global vector

3036:     Level: intermediate

3038:     Note:
3039:     See `DMLocalToGlobalBegin()` for full details

3041: .seealso: `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalEnd()`
3042: @*/
3043: PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3044: {
3045:   PetscSF                 sf;
3046:   PetscSection            s;
3047:   DMLocalToGlobalHookLink link;
3048:   PetscBool               isInsert, transform;

3051:   DMGetSectionSF(dm, &sf);
3052:   DMGetLocalSection(dm, &s);
3053:   switch (mode) {
3054:   case INSERT_VALUES:
3055:   case INSERT_ALL_VALUES:
3056:     isInsert = PETSC_TRUE;
3057:     break;
3058:   case ADD_VALUES:
3059:   case ADD_ALL_VALUES:
3060:     isInsert = PETSC_FALSE;
3061:     break;
3062:   default:
3063:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3064:   }
3065:   if (sf && !isInsert) {
3066:     const PetscScalar *lArray;
3067:     PetscScalar       *gArray;
3068:     Vec                tmpl;

3070:     DMHasBasisTransform(dm, &transform);
3071:     if (transform) {
3072:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3073:       VecGetArrayRead(tmpl, &lArray);
3074:     } else {
3075:       VecGetArrayReadAndMemType(l, &lArray, NULL);
3076:     }
3077:     VecGetArrayAndMemType(g, &gArray, NULL);
3078:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
3079:     if (transform) {
3080:       VecRestoreArrayRead(tmpl, &lArray);
3081:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3082:     } else {
3083:       VecRestoreArrayReadAndMemType(l, &lArray);
3084:     }
3085:     VecRestoreArrayAndMemType(g, &gArray);
3086:   } else if (s && isInsert) {
3087:   } else {
3088:     (*dm->ops->localtoglobalend)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3089:   }
3090:   for (link = dm->ltoghook; link; link = link->next) {
3091:     if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
3092:   }
3093:   return 0;
3094: }

3096: /*@
3097:    DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include ghost points
3098:    that contain irrelevant values) to another local vector where the ghost
3099:    points in the second are set correctly from values on other MPI ranks. Must be followed by `DMLocalToLocalEnd()`.

3101:    Neighbor-wise Collective on dm

3103:    Input Parameters:
3104: +  dm - the `DM` object
3105: .  g - the original local vector
3106: -  mode - one of `INSERT_VALUES` or `ADD_VALUES`

3108:    Output Parameter:
3109: .  l  - the local vector with correct ghost values

3111:    Level: intermediate

3113: .seealso: `DMLocalToLocalEnd(), `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalEnd()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3114: @*/
3115: PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3116: {
3118:   (*dm->ops->localtolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3119:   return 0;
3120: }

3122: /*@
3123:    DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3124:    points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.

3126:    Neighbor-wise Collective on dm

3128:    Input Parameters:
3129: +  da - the `DM` object
3130: .  g - the original local vector
3131: -  mode - one of `INSERT_VALUES` or `ADD_VALUES`

3133:    Output Parameter:
3134: .  l  - the local vector with correct ghost values

3136:    Level: intermediate

3138: .seealso: `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalBegin()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3139: @*/
3140: PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3141: {
3143:   (*dm->ops->localtolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3144:   return 0;
3145: }

3147: /*@
3148:     DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh

3150:     Collective on dm

3152:     Input Parameters:
3153: +   dm - the `DM` object
3154: -   comm - the communicator to contain the new `DM` object (or MPI_COMM_NULL)

3156:     Output Parameter:
3157: .   dmc - the coarsened `DM`

3159:     Level: developer

3161: .seealso: `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3162: @*/
3163: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3164: {
3165:   DMCoarsenHookLink link;

3168:   PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0);
3169:   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3170:   if (*dmc) {
3171:     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3172:     DMSetCoarseDM(dm, *dmc);
3173:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3174:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc);
3175:     (*dmc)->ctx       = dm->ctx;
3176:     (*dmc)->levelup   = dm->levelup;
3177:     (*dmc)->leveldown = dm->leveldown + 1;
3178:     DMSetMatType(*dmc, dm->mattype);
3179:     for (link = dm->coarsenhook; link; link = link->next) {
3180:       if (link->coarsenhook) (*link->coarsenhook)(dm, *dmc, link->ctx);
3181:     }
3182:   }
3183:   PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0);
3185:   return 0;
3186: }

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

3191:    Logically Collective on fine

3193:    Input Parameters:
3194: +  fine - `DM` on which to run a hook when restricting to a coarser level
3195: .  coarsenhook - function to run when setting up a coarser level
3196: .  restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3197: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

3202: +  fine - fine level `DM`
3203: .  coarse - coarse level `DM` to restrict problem to
3204: -  ctx - optional user-defined function context

3206:    Calling sequence for restricthook:
3207: $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3208: $
3209: +  fine - fine level `DM`
3210: .  mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3211: .  rscale - scaling vector for restriction
3212: .  inject - matrix restricting by injection
3213: .  coarse - coarse level DM to update
3214: -  ctx - optional user-defined function context

3216:    Level: advanced

3218:    Notes:
3219:    This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.

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

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

3226:    The hooks are automatically called by `DMRestrict()`

3228:    Fortran Note:
3229:    This function is not available from Fortran.

3231: .seealso: `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3232: @*/
3233: PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3234: {
3235:   DMCoarsenHookLink link, *p;

3238:   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3239:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3240:   }
3241:   PetscNew(&link);
3242:   link->coarsenhook  = coarsenhook;
3243:   link->restricthook = restricthook;
3244:   link->ctx          = ctx;
3245:   link->next         = NULL;
3246:   *p                 = link;
3247:   return 0;
3248: }

3250: /*@C
3251:    DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`

3253:    Logically Collective on fine

3255:    Input Parameters:
3256: +  fine - `DM` on which to run a hook when restricting to a coarser level
3257: .  coarsenhook - function to run when setting up a coarser level
3258: .  restricthook - function to run to update data on coarser levels
3259: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3261:    Level: advanced

3263:    Note:
3264:    This function does nothing if the hook is not in the list.

3266:    Fortran Note:
3267:    This function is not available from Fortran.

3269: .seealso: `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3270: @*/
3271: PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3272: {
3273:   DMCoarsenHookLink link, *p;

3276:   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3277:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3278:       link = *p;
3279:       *p   = link->next;
3280:       PetscFree(link);
3281:       break;
3282:     }
3283:   }
3284:   return 0;
3285: }

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

3290:    Collective if any hooks are

3292:    Input Parameters:
3293: +  fine - finer `DM` from which the data is obtained
3294: .  restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3295: .  rscale - scaling vector for restriction
3296: .  inject - injection matrix, also use `MatRestrict()`
3297: -  coarse - coarser DM to update

3299:    Level: developer

3301:    Developer Note:
3302:    Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better

3304: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3305: @*/
3306: PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3307: {
3308:   DMCoarsenHookLink link;

3310:   for (link = fine->coarsenhook; link; link = link->next) {
3311:     if (link->restricthook) (*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx);
3312:   }
3313:   return 0;
3314: }

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

3319:    Logically Collective on global

3321:    Input Parameters:
3322: +  global - global `DM`
3323: .  ddhook - function to run to pass data to the decomposition `DM` upon its creation
3324: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3325: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3327:    Calling sequence for ddhook:
3328: $    ddhook(DM global,DM block,void *ctx)

3330: +  global - global `DM`
3331: .  block  - block `DM`
3332: -  ctx - optional user-defined function context

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

3337: +  global - global `DM`
3338: .  out    - scatter to the outer (with ghost and overlap points) block vector
3339: .  in     - scatter to block vector values only owned locally
3340: .  block  - block `DM`
3341: -  ctx - optional user-defined function context

3343:    Level: advanced

3345:    Notes:
3346:    This function is only needed if auxiliary data needs to be set up on subdomain `DM`s.

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

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

3353:    Fortran Note:
3354:    This function is not available from Fortran.

3356: .seealso: `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3357: @*/
3358: PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3359: {
3360:   DMSubDomainHookLink link, *p;

3363:   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3364:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3365:   }
3366:   PetscNew(&link);
3367:   link->restricthook = restricthook;
3368:   link->ddhook       = ddhook;
3369:   link->ctx          = ctx;
3370:   link->next         = NULL;
3371:   *p                 = link;
3372:   return 0;
3373: }

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

3378:    Logically Collective on global

3380:    Input Parameters:
3381: +  global - global `DM`
3382: .  ddhook - function to run to pass data to the decomposition `DM` upon its creation
3383: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
3384: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

3386:    Level: advanced

3388:    Fortran Note:
3389:    This function is not available from Fortran.

3391: .seealso: `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3392: @*/
3393: PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3394: {
3395:   DMSubDomainHookLink link, *p;

3398:   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3399:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3400:       link = *p;
3401:       *p   = link->next;
3402:       PetscFree(link);
3403:       break;
3404:     }
3405:   }
3406:   return 0;
3407: }

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

3412:    Collective if any hooks are

3414:    Input Parameters:
3415: +  fine - finer `DM` to use as a base
3416: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3417: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3418: -  coarse - coarser `DM` to update

3420:    Level: developer

3422: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`
3423: @*/
3424: PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3425: {
3426:   DMSubDomainHookLink link;

3428:   for (link = global->subdomainhook; link; link = link->next) {
3429:     if (link->restricthook) (*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx);
3430:   }
3431:   return 0;
3432: }

3434: /*@
3435:     DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.

3437:     Not Collective

3439:     Input Parameter:
3440: .   dm - the `DM` object

3442:     Output Parameter:
3443: .   level - number of coarsenings

3445:     Level: developer

3447: .seealso: `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3448: @*/
3449: PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3450: {
3453:   *level = dm->leveldown;
3454:   return 0;
3455: }

3457: /*@
3458:     DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.

3460:     Collective on dm

3462:     Input Parameters:
3463: +   dm - the `DM` object
3464: -   level - number of coarsenings

3466:     Level: developer

3468:     Note:
3469:     This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`

3471: .seealso: `DMSetCoarsenLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3472: @*/
3473: PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3474: {
3476:   dm->leveldown = level;
3477:   return 0;
3478: }

3480: /*@C
3481:     DMRefineHierarchy - Refines a `DM` object, all levels at once

3483:     Collective on dm

3485:     Input Parameters:
3486: +   dm - the `DM` object
3487: -   nlevels - the number of levels of refinement

3489:     Output Parameter:
3490: .   dmf - the refined `DM` hierarchy

3492:     Level: developer

3494: .seealso: `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3495: @*/
3496: PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3497: {
3500:   if (nlevels == 0) return 0;
3502:   if (dm->ops->refinehierarchy) {
3503:     PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3504:   } else if (dm->ops->refine) {
3505:     PetscInt i;

3507:     DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]);
3508:     for (i = 1; i < nlevels; i++) DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]);
3509:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No RefineHierarchy for this DM yet");
3510:   return 0;
3511: }

3513: /*@C
3514:     DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once

3516:     Collective on dm

3518:     Input Parameters:
3519: +   dm - the `DM` object
3520: -   nlevels - the number of levels of coarsening

3522:     Output Parameter:
3523: .   dmc - the coarsened `DM` hierarchy

3525:     Level: developer

3527: .seealso: `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3528: @*/
3529: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3530: {
3533:   if (nlevels == 0) return 0;
3535:   if (dm->ops->coarsenhierarchy) {
3536:     PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3537:   } else if (dm->ops->coarsen) {
3538:     PetscInt i;

3540:     DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]);
3541:     for (i = 1; i < nlevels; i++) DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]);
3542:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No CoarsenHierarchy for this DM yet");
3543:   return 0;
3544: }

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

3549:     Logically Collective if the function is collective

3551:     Input Parameters:
3552: +   dm - the `DM` object
3553: -   destroy - the destroy function

3555:     Level: intermediate

3557: .seealso: `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3558: @*/
3559: PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3560: {
3562:   dm->ctxdestroy = destroy;
3563:   return 0;
3564: }

3566: /*@
3567:     DMSetApplicationContext - Set a user context into a `DM` object

3569:     Not Collective

3571:     Input Parameters:
3572: +   dm - the `DM` object
3573: -   ctx - the user context

3575:     Level: intermediate

3577:     Note:
3578:     A user context is a way to pass problem specific information that is accessible whenever the `DM` is available

3580: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3581: @*/
3582: PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3583: {
3585:   dm->ctx = ctx;
3586:   return 0;
3587: }

3589: /*@
3590:     DMGetApplicationContext - Gets a user context from a `DM` object

3592:     Not Collective

3594:     Input Parameter:
3595: .   dm - the `DM` object

3597:     Output Parameter:
3598: .   ctx - the user context

3600:     Level: intermediate

3602:     Note:
3603:     A user context is a way to pass problem specific information that is accessible whenever the `DM` is available

3605: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3606: @*/
3607: PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3608: {
3610:   *(void **)ctx = dm->ctx;
3611:   return 0;
3612: }

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

3617:     Logically Collective on dm

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

3623:     Level: intermediate

3625: .seealso: `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3626:          `DMSetJacobian()`
3627: @*/
3628: PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3629: {
3631:   dm->ops->computevariablebounds = f;
3632:   return 0;
3633: }

3635: /*@
3636:     DMHasVariableBounds - does the `DM` object have a variable bounds function?

3638:     Not Collective

3640:     Input Parameter:
3641: .   dm - the `DM` object to destroy

3643:     Output Parameter:
3644: .   flg - `PETSC_TRUE` if the variable bounds function exists

3646:     Level: developer

3648: .seealso: `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3649: @*/
3650: PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3651: {
3654:   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3655:   return 0;
3656: }

3658: /*@C
3659:     DMComputeVariableBounds - compute variable bounds used by `SNESVI`.

3661:     Logically Collective on dm

3663:     Input Parameter:
3664: .   dm - the `DM` object

3666:     Output parameters:
3667: +   xl - lower bound
3668: -   xu - upper bound

3670:     Level: advanced

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

3675: .seealso: `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3676: @*/
3677: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3678: {
3682:   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3683:   return 0;
3684: }

3686: /*@
3687:     DMHasColoring - does the `DM` object have a method of providing a coloring?

3689:     Not Collective

3691:     Input Parameter:
3692: .   dm - the DM object

3694:     Output Parameter:
3695: .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.

3697:     Level: developer

3699: .seealso: `DMCreateColoring()`
3700: @*/
3701: PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3702: {
3705:   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3706:   return 0;
3707: }

3709: /*@
3710:     DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?

3712:     Not Collective

3714:     Input Parameter:
3715: .   dm - the `DM` object

3717:     Output Parameter:
3718: .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.

3720:     Level: developer

3722: .seealso: `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3723: @*/
3724: PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3725: {
3728:   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3729:   return 0;
3730: }

3732: /*@
3733:     DMHasCreateInjection - does the `DM` object have a method of providing an injection?

3735:     Not Collective

3737:     Input Parameter:
3738: .   dm - the `DM` object

3740:     Output Parameter:
3741: .   flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.

3743:     Level: developer

3745: .seealso: `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3746: @*/
3747: PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3748: {
3751:   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3752:   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3753:   return 0;
3754: }

3756: PetscFunctionList DMList              = NULL;
3757: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

3759: /*@C
3760:   DMSetType - Builds a `DM`, for a particular `DM` implementation.

3762:   Collective on dm

3764:   Input Parameters:
3765: + dm     - The `DM` object
3766: - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`

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

3771:   Level: intermediate

3773:   Note:
3774:   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPLEXCreateBoxMesh()`

3776: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3777: @*/
3778: PetscErrorCode DMSetType(DM dm, DMType method)
3779: {
3780:   PetscErrorCode (*r)(DM);
3781:   PetscBool match;

3784:   PetscObjectTypeCompare((PetscObject)dm, method, &match);
3785:   if (match) return 0;

3787:   DMRegisterAll();
3788:   PetscFunctionListFind(DMList, method, &r);

3791:   PetscTryTypeMethod(dm, destroy);
3792:   PetscMemzero(dm->ops, sizeof(*dm->ops));
3793:   PetscObjectChangeTypeName((PetscObject)dm, method);
3794:   (*r)(dm);
3795:   return 0;
3796: }

3798: /*@C
3799:   DMGetType - Gets the `DM` type name (as a string) from the `DM`.

3801:   Not Collective

3803:   Input Parameter:
3804: . dm  - The `DM`

3806:   Output Parameter:
3807: . type - The `DMType` name

3809:   Level: intermediate

3811: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3812: @*/
3813: PetscErrorCode DMGetType(DM dm, DMType *type)
3814: {
3817:   DMRegisterAll();
3818:   *type = ((PetscObject)dm)->type_name;
3819:   return 0;
3820: }

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

3825:   Collective on dm

3827:   Input Parameters:
3828: + dm - the `DM`
3829: - newtype - new `DM` type (use "same" for the same type)

3831:   Output Parameter:
3832: . M - pointer to new `DM`

3834:   Notes:
3835:   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3836:   the MPI communicator of the generated `DM` is always the same as the communicator
3837:   of the input `DM`.

3839:   Level: intermediate

3841: .seealso: `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
3842: @*/
3843: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3844: {
3845:   DM        B;
3846:   char      convname[256];
3847:   PetscBool sametype /*, issame */;

3852:   PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype);
3853:   /* PetscStrcmp(newtype, "same", &issame); */
3854:   if (sametype) {
3855:     *M = dm;
3856:     PetscObjectReference((PetscObject)dm);
3857:     return 0;
3858:   } else {
3859:     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;

3861:     /*
3862:        Order of precedence:
3863:        1) See if a specialized converter is known to the current DM.
3864:        2) See if a specialized converter is known to the desired DM class.
3865:        3) See if a good general converter is registered for the desired class
3866:        4) See if a good general converter is known for the current matrix.
3867:        5) Use a really basic converter.
3868:     */

3870:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3871:     PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3872:     PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3873:     PetscStrlcat(convname, "_", sizeof(convname));
3874:     PetscStrlcat(convname, newtype, sizeof(convname));
3875:     PetscStrlcat(convname, "_C", sizeof(convname));
3876:     PetscObjectQueryFunction((PetscObject)dm, convname, &conv);
3877:     if (conv) goto foundconv;

3879:     /* 2)  See if a specialized converter is known to the desired DM class. */
3880:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3881:     DMSetType(B, newtype);
3882:     PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3883:     PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3884:     PetscStrlcat(convname, "_", sizeof(convname));
3885:     PetscStrlcat(convname, newtype, sizeof(convname));
3886:     PetscStrlcat(convname, "_C", sizeof(convname));
3887:     PetscObjectQueryFunction((PetscObject)B, convname, &conv);
3888:     if (conv) {
3889:       DMDestroy(&B);
3890:       goto foundconv;
3891:     }

3893: #if 0
3894:     /* 3) See if a good general converter is registered for the desired class */
3895:     conv = B->ops->convertfrom;
3896:     DMDestroy(&B);
3897:     if (conv) goto foundconv;

3899:     /* 4) See if a good general converter is known for the current matrix */
3900:     if (dm->ops->convert) {
3901:       conv = dm->ops->convert;
3902:     }
3903:     if (conv) goto foundconv;
3904: #endif

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

3909:   foundconv:
3910:     PetscLogEventBegin(DM_Convert, dm, 0, 0, 0);
3911:     (*conv)(dm, newtype, M);
3912:     /* Things that are independent of DM type: We should consult DMClone() here */
3913:     {
3914:       const PetscReal *maxCell, *Lstart, *L;

3916:       DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
3917:       DMSetPeriodicity(*M, maxCell, Lstart, L);
3918:       (*M)->prealloc_only = dm->prealloc_only;
3919:       PetscFree((*M)->vectype);
3920:       PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype);
3921:       PetscFree((*M)->mattype);
3922:       PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype);
3923:     }
3924:     PetscLogEventEnd(DM_Convert, dm, 0, 0, 0);
3925:   }
3926:   PetscObjectStateIncrease((PetscObject)*M);
3927:   return 0;
3928: }

3930: /*--------------------------------------------------------------------------------------------------------------------*/

3932: /*@C
3933:   DMRegister -  Adds a new `DM` type implementation

3935:   Not Collective

3937:   Input Parameters:
3938: + name        - The name of a new user-defined creation routine
3939: - create_func - The creation routine itself

3941:   Notes:
3942:   DMRegister() may be called multiple times to add several user-defined `DM`s

3944:   Sample usage:
3945: .vb
3946:     DMRegister("my_da", MyDMCreate);
3947: .ve

3949:   Then, your DM type can be chosen with the procedural interface via
3950: .vb
3951:     DMCreate(MPI_Comm, DM *);
3952:     DMSetType(DM,"my_da");
3953: .ve
3954:    or at runtime via the option
3955: .vb
3956:     -da_type my_da
3957: .ve

3959:   Level: advanced

3961: .seealso: `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
3962: @*/
3963: PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
3964: {
3965:   DMInitializePackage();
3966:   PetscFunctionListAdd(&DMList, sname, function);
3967:   return 0;
3968: }

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

3973:   Collective on viewer

3975:   Input Parameters:
3976: + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
3977:            some related function before a call to `DMLoad()`.
3978: - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
3979:            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`

3981:    Level: intermediate

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

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

3990:   Notes for advanced users:
3991:   Most users should not need to know the details of the binary storage
3992:   format, since `DMLoad()` and `DMView()` completely hide these details.
3993:   But for anyone who's interested, the standard binary matrix storage
3994:   format is
3995: .vb
3996:      has not yet been determined
3997: .ve

3999: .seealso: `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4000: @*/
4001: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4002: {
4003:   PetscBool isbinary, ishdf5;

4007:   PetscViewerCheckReadable(viewer);
4008:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary);
4009:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
4010:   PetscLogEventBegin(DM_Load, viewer, 0, 0, 0);
4011:   if (isbinary) {
4012:     PetscInt classid;
4013:     char     type[256];

4015:     PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT);
4017:     PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR);
4018:     DMSetType(newdm, type);
4019:     PetscTryTypeMethod(newdm, load, viewer);
4020:   } else if (ishdf5) {
4021:     PetscTryTypeMethod(newdm, load, viewer);
4022:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4023:   PetscLogEventEnd(DM_Load, viewer, 0, 0, 0);
4024:   return 0;
4025: }

4027: /******************************** FEM Support **********************************/

4029: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4030: {
4031:   PetscInt f;

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

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

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

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

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

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

4083:   Input Parameter:
4084: . dm - The `DM`

4086:   Output Parameter:
4087: . section - The `PetscSection`

4089:   Options Database Keys:
4090: . -dm_petscsection_view - View the `PetscSection` created by the `DM`

4092:   Level: advanced

4094:   Notes:
4095:   Use `DMGetLocalSection()` in new code.

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

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

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

4110:   Input Parameter:
4111: . dm - The `DM`

4113:   Output Parameter:
4114: . section - The `PetscSection`

4116:   Options Database Keys:
4117: . -dm_petscsection_view - View the section created by the `DM`

4119:   Level: intermediate

4121:   Note:
4122:   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:     PetscUseTypeMethod(dm, createlocalsection);
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 `PetscSection` 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:
4190:   Any existing Section will be destroyed

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

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

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

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

4224:   not collective

4226:   Input Parameter:
4227: . dm - The `DM`

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

4234:   Level: advanced

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

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

4251: /*@
4252:   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.

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

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

4258:   collective on dm

4260:   Input Parameters:
4261: + dm - The `DM`
4262: . 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).
4263: . 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).
4264: - 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).

4266:   Level: advanced

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

4271: .seealso: `DMGetDefaultConstraints()`
4272: @*/
4273: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4274: {
4275:   PetscMPIInt result;

4278:   if (section) {
4280:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result);
4282:   }
4283:   if (mat) {
4285:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result);
4287:   }
4288:   if (bias) {
4290:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result);
4292:   }
4293:   PetscObjectReference((PetscObject)section);
4294:   PetscSectionDestroy(&dm->defaultConstraint.section);
4295:   dm->defaultConstraint.section = section;
4296:   PetscObjectReference((PetscObject)mat);
4297:   MatDestroy(&dm->defaultConstraint.mat);
4298:   dm->defaultConstraint.mat = mat;
4299:   PetscObjectReference((PetscObject)bias);
4300:   VecDestroy(&dm->defaultConstraint.bias);
4301:   dm->defaultConstraint.bias = bias;
4302:   return 0;
4303: }

4305: #if defined(PETSC_USE_DEBUG)
4306: /*
4307:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.

4309:   Input Parameters:
4310: + dm - The `DM`
4311: . localSection - `PetscSection` describing the local data layout
4312: - globalSection - `PetscSection` describing the global data layout

4314:   Level: intermediate

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

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

4341:     PetscSectionGetDof(localSection, p, &dof);
4342:     PetscSectionGetOffset(localSection, p, &off);
4343:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4344:     PetscSectionGetDof(globalSection, p, &gdof);
4345:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4346:     PetscSectionGetOffset(globalSection, p, &goff);
4347:     if (!gdof) continue; /* Censored point */
4348:     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4349:       PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof);
4350:       valid = PETSC_FALSE;
4351:     }
4352:     if (gcdof && (gcdof != cdof)) {
4353:       PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof);
4354:       valid = PETSC_FALSE;
4355:     }
4356:     if (gdof < 0) {
4357:       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4358:       for (d = 0; d < gsize; ++d) {
4359:         PetscInt offset = -(goff + 1) + d, r;

4361:         PetscFindInt(offset, size + 1, ranges, &r);
4362:         if (r < 0) r = -(r + 2);
4363:         if ((r < 0) || (r >= size)) {
4364:           PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff);
4365:           valid = PETSC_FALSE;
4366:           break;
4367:         }
4368:       }
4369:     }
4370:   }
4371:   PetscLayoutDestroy(&layout);
4372:   PetscSynchronizedFlush(comm, NULL);
4373:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4374:   if (!gvalid) {
4375:     DMView(dm, NULL);
4376:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4377:   }
4378:   return 0;
4379: }
4380: #endif

4382: /*@
4383:   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.

4385:   Collective on dm

4387:   Input Parameter:
4388: . dm - The `DM`

4390:   Output Parameter:
4391: . section - The `PetscSection`

4393:   Level: intermediate

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

4398: .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`
4399: @*/
4400: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4401: {
4404:   if (!dm->globalSection) {
4405:     PetscSection s;

4407:     DMGetLocalSection(dm, &s);
4410:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4411:     PetscLayoutDestroy(&dm->map);
4412:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4413:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4414:   }
4415:   *section = dm->globalSection;
4416:   return 0;
4417: }

4419: /*@
4420:   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.

4422:   Input Parameters:
4423: + dm - The `DM`
4424: - section - The PetscSection, or NULL

4426:   Level: intermediate

4428:   Note:
4429:   Any existing `PetscSection` will be destroyed

4431: .seealso: `DMGetGlobalSection()`, `DMSetLocalSection()`
4432: @*/
4433: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4434: {
4437:   PetscObjectReference((PetscObject)section);
4438:   PetscSectionDestroy(&dm->globalSection);
4439:   dm->globalSection = section;
4440: #if defined(PETSC_USE_DEBUG)
4441:   if (section) DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);
4442: #endif
4443:   return 0;
4444: }

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

4450:   Input Parameter:
4451: . dm - The `DM`

4453:   Output Parameter:
4454: . sf - The `PetscSF`

4456:   Level: intermediate

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

4461: .seealso: `DMSetSectionSF()`, `DMCreateSectionSF()`
4462: @*/
4463: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4464: {
4465:   PetscInt nroots;

4469:   if (!dm->sectionSF) PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF);
4470:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4471:   if (nroots < 0) {
4472:     PetscSection section, gSection;

4474:     DMGetLocalSection(dm, &section);
4475:     if (section) {
4476:       DMGetGlobalSection(dm, &gSection);
4477:       DMCreateSectionSF(dm, section, gSection);
4478:     } else {
4479:       *sf = NULL;
4480:       return 0;
4481:     }
4482:   }
4483:   *sf = dm->sectionSF;
4484:   return 0;
4485: }

4487: /*@
4488:   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`

4490:   Input Parameters:
4491: + dm - The `DM`
4492: - sf - The `PetscSF`

4494:   Level: intermediate

4496:   Note:
4497:   Any previous `PetscSF` is destroyed

4499: .seealso: `DMGetSectionSF()`, `DMCreateSectionSF()`
4500: @*/
4501: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4502: {
4505:   PetscObjectReference((PetscObject)sf);
4506:   PetscSFDestroy(&dm->sectionSF);
4507:   dm->sectionSF = sf;
4508:   return 0;
4509: }

4511: /*@C
4512:   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4513:   describing the data layout.

4515:   Input Parameters:
4516: + dm - The `DM`
4517: . localSection - `PetscSection` describing the local data layout
4518: - globalSection - `PetscSection` describing the global data layout

4520:   Level: developer

4522:   Note:
4523:   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`

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

4530: .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4531: @*/
4532: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4533: {
4535:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4536:   return 0;
4537: }

4539: /*@
4540:   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.

4542:   Not collective but the resulting `PetscSF` is collective

4544:   Input Parameter:
4545: . dm - The `DM`

4547:   Output Parameter:
4548: . sf - The `PetscSF`

4550:   Level: intermediate

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

4555: .seealso: `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4556: @*/
4557: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4558: {
4561:   *sf = dm->sf;
4562:   return 0;
4563: }

4565: /*@
4566:   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.

4568:   Collective on dm

4570:   Input Parameters:
4571: + dm - The `DM`
4572: - sf - The `PetscSF`

4574:   Level: intermediate

4576: .seealso: `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4577: @*/
4578: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4579: {
4582:   PetscObjectReference((PetscObject)sf);
4583:   PetscSFDestroy(&dm->sf);
4584:   dm->sf = sf;
4585:   return 0;
4586: }

4588: /*@
4589:   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering

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

4594:   Output Parameter:
4595: . sf - The `PetscSF`

4597:   Level: intermediate

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

4602: .seealso: `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4603: @*/
4604: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4605: {
4608:   *sf = dm->sfNatural;
4609:   return 0;
4610: }

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

4615:   Input Parameters:
4616: + dm - The DM
4617: - sf - The PetscSF

4619:   Level: intermediate

4621: .seealso: `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4622: @*/
4623: PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4624: {
4627:   PetscObjectReference((PetscObject)sf);
4628:   PetscSFDestroy(&dm->sfNatural);
4629:   dm->sfNatural = sf;
4630:   return 0;
4631: }

4633: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4634: {
4635:   PetscClassId id;

4637:   PetscObjectGetClassId(disc, &id);
4638:   if (id == PETSCFE_CLASSID) {
4639:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4640:   } else if (id == PETSCFV_CLASSID) {
4641:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4642:   } else {
4643:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4644:   }
4645:   return 0;
4646: }

4648: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4649: {
4650:   RegionField *tmpr;
4651:   PetscInt     Nf = dm->Nf, f;

4653:   if (Nf >= NfNew) return 0;
4654:   PetscMalloc1(NfNew, &tmpr);
4655:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4656:   for (f = Nf; f < NfNew; ++f) {
4657:     tmpr[f].disc        = NULL;
4658:     tmpr[f].label       = NULL;
4659:     tmpr[f].avoidTensor = PETSC_FALSE;
4660:   }
4661:   PetscFree(dm->fields);
4662:   dm->Nf     = NfNew;
4663:   dm->fields = tmpr;
4664:   return 0;
4665: }

4667: /*@
4668:   DMClearFields - Remove all fields from the DM

4670:   Logically collective on dm

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

4675:   Level: intermediate

4677: .seealso: `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4678: @*/
4679: PetscErrorCode DMClearFields(DM dm)
4680: {
4681:   PetscInt f;

4684:   for (f = 0; f < dm->Nf; ++f) {
4685:     PetscObjectDestroy(&dm->fields[f].disc);
4686:     DMLabelDestroy(&dm->fields[f].label);
4687:   }
4688:   PetscFree(dm->fields);
4689:   dm->fields = NULL;
4690:   dm->Nf     = 0;
4691:   return 0;
4692: }

4694: /*@
4695:   DMGetNumFields - Get the number of fields in the DM

4697:   Not collective

4699:   Input Parameter:
4700: . dm - The DM

4702:   Output Parameter:
4703: . Nf - The number of fields

4705:   Level: intermediate

4707: .seealso: `DMSetNumFields()`, `DMSetField()`
4708: @*/
4709: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4710: {
4713:   *numFields = dm->Nf;
4714:   return 0;
4715: }

4717: /*@
4718:   DMSetNumFields - Set the number of fields in the DM

4720:   Logically collective on dm

4722:   Input Parameters:
4723: + dm - The DM
4724: - Nf - The number of fields

4726:   Level: intermediate

4728: .seealso: `DMGetNumFields()`, `DMSetField()`
4729: @*/
4730: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4731: {
4732:   PetscInt Nf, f;

4735:   DMGetNumFields(dm, &Nf);
4736:   for (f = Nf; f < numFields; ++f) {
4737:     PetscContainer obj;

4739:     PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj);
4740:     DMAddField(dm, NULL, (PetscObject)obj);
4741:     PetscContainerDestroy(&obj);
4742:   }
4743:   return 0;
4744: }

4746: /*@
4747:   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field

4749:   Not collective

4751:   Input Parameters:
4752: + dm - The `DM`
4753: - f  - The field number

4755:   Output Parameters:
4756: + label - The label indicating the support of the field, or NULL for the entire mesh (pass in NULL if not needed)
4757: - disc - The discretization object (pass in NULL if not needed)

4759:   Level: intermediate

4761: .seealso: `DMAddField()`, `DMSetField()`
4762: @*/
4763: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4764: {
4768:   if (label) *label = dm->fields[f].label;
4769:   if (disc) *disc = dm->fields[f].disc;
4770:   return 0;
4771: }

4773: /* Does not clear the DS */
4774: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4775: {
4776:   DMFieldEnlarge_Static(dm, f + 1);
4777:   DMLabelDestroy(&dm->fields[f].label);
4778:   PetscObjectDestroy(&dm->fields[f].disc);
4779:   dm->fields[f].label = label;
4780:   dm->fields[f].disc  = disc;
4781:   PetscObjectReference((PetscObject)label);
4782:   PetscObjectReference((PetscObject)disc);
4783:   return 0;
4784: }

4786: /*@
4787:   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
4788:   the field numbering.

4790:   Logically collective on dm

4792:   Input Parameters:
4793: + dm    - The `DM`
4794: . f     - The field number
4795: . label - The label indicating the support of the field, or NULL for the entire mesh
4796: - disc - The discretization object

4798:   Level: intermediate

4800: .seealso: `DMAddField()`, `DMGetField()`
4801: @*/
4802: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4803: {
4808:   DMSetField_Internal(dm, f, label, disc);
4809:   DMSetDefaultAdjacency_Private(dm, f, disc);
4810:   DMClearDS(dm);
4811:   return 0;
4812: }

4814: /*@
4815:   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
4816:   and a discretization object that defines the function space associated with those points.

4818:   Logically collective on dm

4820:   Input Parameters:
4821: + dm    - The `DM`
4822: . label - The label indicating the support of the field, or NULL for the entire mesh
4823: - disc - The discretization object

4825:   Level: intermediate

4827:   Notes:
4828:   The label already exists or will be added to the `DM` with `DMSetLabel()`.

4830:   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
4831:   within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
4832:   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.

4834: .seealso: `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
4835: @*/
4836: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
4837: {
4838:   PetscInt Nf = dm->Nf;

4843:   DMFieldEnlarge_Static(dm, Nf + 1);
4844:   dm->fields[Nf].label = label;
4845:   dm->fields[Nf].disc  = disc;
4846:   PetscObjectReference((PetscObject)label);
4847:   PetscObjectReference((PetscObject)disc);
4848:   DMSetDefaultAdjacency_Private(dm, Nf, disc);
4849:   DMClearDS(dm);
4850:   return 0;
4851: }

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

4856:   Logically collective on dm

4858:   Input Parameters:
4859: + dm          - The `DM`
4860: . f           - The field index
4861: - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells

4863:   Level: intermediate

4865: .seealso: `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4866: @*/
4867: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4868: {
4870:   dm->fields[f].avoidTensor = avoidTensor;
4871:   return 0;
4872: }

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

4877:   Not collective

4879:   Input Parameters:
4880: + dm          - The `DM`
4881: - f           - The field index

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

4886:   Level: intermediate

4888:  .seealso: `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4889: @*/
4890: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4891: {
4893:   *avoidTensor = dm->fields[f].avoidTensor;
4894:   return 0;
4895: }

4897: /*@
4898:   DMCopyFields - Copy the discretizations for the `DM` into another `DM`

4900:   Collective on dm

4902:   Input Parameter:
4903: . dm - The `DM`

4905:   Output Parameter:
4906: . newdm - The `DM`

4908:   Level: advanced

4910: .seealso: `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
4911: @*/
4912: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4913: {
4914:   PetscInt Nf, f;

4916:   if (dm == newdm) return 0;
4917:   DMGetNumFields(dm, &Nf);
4918:   DMClearFields(newdm);
4919:   for (f = 0; f < Nf; ++f) {
4920:     DMLabel     label;
4921:     PetscObject field;
4922:     PetscBool   useCone, useClosure;

4924:     DMGetField(dm, f, &label, &field);
4925:     DMSetField(newdm, f, label, field);
4926:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4927:     DMSetAdjacency(newdm, f, useCone, useClosure);
4928:   }
4929:   return 0;
4930: }

4932: /*@
4933:   DMGetAdjacency - Returns the flags for determining variable influence

4935:   Not collective

4937:   Input Parameters:
4938: + dm - The DM object
4939: - f  - The field number, or PETSC_DEFAULT for the default adjacency

4941:   Output Parameters:
4942: + useCone    - Flag for variable influence starting with the cone operation
4943: - useClosure - Flag for variable influence using transitive closure

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

4951:   Level: developer

4953: .seealso: `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
4954: @*/
4955: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4956: {
4960:   if (f < 0) {
4961:     if (useCone) *useCone = dm->adjacency[0];
4962:     if (useClosure) *useClosure = dm->adjacency[1];
4963:   } else {
4964:     PetscInt Nf;

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

4974: /*@
4975:   DMSetAdjacency - Set the flags for determining variable influence

4977:   Not collective

4979:   Input Parameters:
4980: + dm         - The DM object
4981: . f          - The field number
4982: . useCone    - Flag for variable influence starting with the cone operation
4983: - useClosure - Flag for variable influence using transitive closure

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

4991:   Level: developer

4993: .seealso: `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
4994: @*/
4995: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4996: {
4998:   if (f < 0) {
4999:     dm->adjacency[0] = useCone;
5000:     dm->adjacency[1] = useClosure;
5001:   } else {
5002:     PetscInt Nf;

5004:     DMGetNumFields(dm, &Nf);
5006:     dm->fields[f].adjacency[0] = useCone;
5007:     dm->fields[f].adjacency[1] = useClosure;
5008:   }
5009:   return 0;
5010: }

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

5015:   Not collective

5017:   Input Parameter:
5018: . dm - The DM object

5020:   Output Parameters:
5021: + useCone    - Flag for variable influence starting with the cone operation
5022: - useClosure - Flag for variable influence using transitive closure

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

5029:   Level: developer

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

5040:   DMGetNumFields(dm, &Nf);
5041:   if (!Nf) {
5042:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5043:   } else {
5044:     DMGetAdjacency(dm, 0, useCone, useClosure);
5045:   }
5046:   return 0;
5047: }

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

5052:   Not collective

5054:   Input Parameters:
5055: + dm         - The DM object
5056: . useCone    - Flag for variable influence starting with the cone operation
5057: - useClosure - Flag for variable influence using transitive closure

5059:   Notes:
5060: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5061: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5062: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5064:   Level: developer

5066: .seealso: `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5067: @*/
5068: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5069: {
5070:   PetscInt Nf;

5073:   DMGetNumFields(dm, &Nf);
5074:   if (!Nf) {
5075:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5076:   } else {
5077:     DMSetAdjacency(dm, 0, useCone, useClosure);
5078:   }
5079:   return 0;
5080: }

5082: PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5083: {
5084:   DM           plex;
5085:   DMLabel     *labels, *glabels;
5086:   const char **names;
5087:   char        *sendNames, *recvNames;
5088:   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5089:   size_t       len;
5090:   MPI_Comm     comm;
5091:   PetscMPIInt  rank, size, p, *counts, *displs;

5093:   PetscObjectGetComm((PetscObject)dm, &comm);
5094:   MPI_Comm_size(comm, &size);
5095:   MPI_Comm_rank(comm, &rank);
5096:   DMGetNumDS(dm, &Nds);
5097:   for (s = 0; s < Nds; ++s) {
5098:     PetscDS  dsBC;
5099:     PetscInt numBd;

5101:     DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5102:     PetscDSGetNumBoundary(dsBC, &numBd);
5103:     maxLabels += numBd;
5104:   }
5105:   PetscCalloc1(maxLabels, &labels);
5106:   /* Get list of labels to be completed */
5107:   for (s = 0; s < Nds; ++s) {
5108:     PetscDS  dsBC;
5109:     PetscInt numBd, bd;

5111:     DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5112:     PetscDSGetNumBoundary(dsBC, &numBd);
5113:     for (bd = 0; bd < numBd; ++bd) {
5114:       DMLabel      label;
5115:       PetscInt     field;
5116:       PetscObject  obj;
5117:       PetscClassId id;

5119:       PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5120:       DMGetField(dm, field, NULL, &obj);
5121:       PetscObjectGetClassId(obj, &id);
5122:       if (!(id == PETSCFE_CLASSID) || !label) continue;
5123:       for (l = 0; l < Nl; ++l)
5124:         if (labels[l] == label) break;
5125:       if (l == Nl) labels[Nl++] = label;
5126:     }
5127:   }
5128:   /* Get label names */
5129:   PetscMalloc1(Nl, &names);
5130:   for (l = 0; l < Nl; ++l) PetscObjectGetName((PetscObject)labels[l], &names[l]);
5131:   for (l = 0; l < Nl; ++l) {
5132:     PetscStrlen(names[l], &len);
5133:     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5134:   }
5135:   PetscFree(labels);
5136:   MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm);
5137:   PetscCalloc1(Nl * gmaxLen, &sendNames);
5138:   for (l = 0; l < Nl; ++l) PetscStrcpy(&sendNames[gmaxLen * l], names[l]);
5139:   PetscFree(names);
5140:   /* Put all names on all processes */
5141:   PetscCalloc2(size, &counts, size + 1, &displs);
5142:   MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm);
5143:   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5144:   gNl = displs[size];
5145:   for (p = 0; p < size; ++p) {
5146:     counts[p] *= gmaxLen;
5147:     displs[p] *= gmaxLen;
5148:   }
5149:   PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels);
5150:   MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm);
5151:   PetscFree2(counts, displs);
5152:   PetscFree(sendNames);
5153:   for (l = 0, gl = 0; l < gNl; ++l) {
5154:     DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]);
5156:     for (m = 0; m < gl; ++m)
5157:       if (glabels[m] == glabels[gl]) continue;
5158:     DMConvert(dm, DMPLEX, &plex);
5159:     DMPlexLabelComplete(plex, glabels[gl]);
5160:     DMDestroy(&plex);
5161:     ++gl;
5162:   }
5163:   PetscFree2(recvNames, glabels);
5164:   return 0;
5165: }

5167: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5168: {
5169:   DMSpace *tmpd;
5170:   PetscInt Nds = dm->Nds, s;

5172:   if (Nds >= NdsNew) return 0;
5173:   PetscMalloc1(NdsNew, &tmpd);
5174:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5175:   for (s = Nds; s < NdsNew; ++s) {
5176:     tmpd[s].ds     = NULL;
5177:     tmpd[s].label  = NULL;
5178:     tmpd[s].fields = NULL;
5179:   }
5180:   PetscFree(dm->probs);
5181:   dm->Nds   = NdsNew;
5182:   dm->probs = tmpd;
5183:   return 0;
5184: }

5186: /*@
5187:   DMGetNumDS - Get the number of discrete systems in the DM

5189:   Not collective

5191:   Input Parameter:
5192: . dm - The DM

5194:   Output Parameter:
5195: . Nds - The number of PetscDS objects

5197:   Level: intermediate

5199: .seealso: `DMGetDS()`, `DMGetCellDS()`
5200: @*/
5201: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5202: {
5205:   *Nds = dm->Nds;
5206:   return 0;
5207: }

5209: /*@
5210:   DMClearDS - Remove all discrete systems from the DM

5212:   Logically collective on dm

5214:   Input Parameter:
5215: . dm - The DM

5217:   Level: intermediate

5219: .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5220: @*/
5221: PetscErrorCode DMClearDS(DM dm)
5222: {
5223:   PetscInt s;

5226:   for (s = 0; s < dm->Nds; ++s) {
5227:     PetscDSDestroy(&dm->probs[s].ds);
5228:     DMLabelDestroy(&dm->probs[s].label);
5229:     ISDestroy(&dm->probs[s].fields);
5230:   }
5231:   PetscFree(dm->probs);
5232:   dm->probs = NULL;
5233:   dm->Nds   = 0;
5234:   return 0;
5235: }

5237: /*@
5238:   DMGetDS - Get the default PetscDS

5240:   Not collective

5242:   Input Parameter:
5243: . dm    - The DM

5245:   Output Parameter:
5246: . prob - The default PetscDS

5248:   Level: intermediate

5250: .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5251: @*/
5252: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5253: {
5257:   if (dm->Nds <= 0) {
5258:     PetscDS ds;

5260:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5261:     DMSetRegionDS(dm, NULL, NULL, ds);
5262:     PetscDSDestroy(&ds);
5263:   }
5264:   *prob = dm->probs[0].ds;
5265:   return 0;
5266: }

5268: /*@
5269:   DMGetCellDS - Get the PetscDS defined on a given cell

5271:   Not collective

5273:   Input Parameters:
5274: + dm    - The DM
5275: - point - Cell for the DS

5277:   Output Parameter:
5278: . prob - The PetscDS defined on the given cell

5280:   Level: developer

5282: .seealso: `DMGetDS()`, `DMSetRegionDS()`
5283: @*/
5284: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5285: {
5286:   PetscDS  probDef = NULL;
5287:   PetscInt s;

5293:   *prob = NULL;
5294:   for (s = 0; s < dm->Nds; ++s) {
5295:     PetscInt val;

5297:     if (!dm->probs[s].label) {
5298:       probDef = dm->probs[s].ds;
5299:     } else {
5300:       DMLabelGetValue(dm->probs[s].label, point, &val);
5301:       if (val >= 0) {
5302:         *prob = dm->probs[s].ds;
5303:         break;
5304:       }
5305:     }
5306:   }
5307:   if (!*prob) *prob = probDef;
5308:   return 0;
5309: }

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

5314:   Not collective

5316:   Input Parameters:
5317: + dm    - The DM
5318: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

5324:   Note:
5325:   If a non-NULL label is given, but there is no PetscDS on that specific label,
5326:   the PetscDS for the full domain (if present) is returned. Returns with
5327:   fields=NULL and prob=NULL if there is no PetscDS for the full domain.

5329:   Level: advanced

5331: .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5332: @*/
5333: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5334: {
5335:   PetscInt Nds = dm->Nds, s;

5339:   if (fields) {
5341:     *fields = NULL;
5342:   }
5343:   if (ds) {
5345:     *ds = NULL;
5346:   }
5347:   for (s = 0; s < Nds; ++s) {
5348:     if (dm->probs[s].label == label || !dm->probs[s].label) {
5349:       if (fields) *fields = dm->probs[s].fields;
5350:       if (ds) *ds = dm->probs[s].ds;
5351:       if (dm->probs[s].label) return 0;
5352:     }
5353:   }
5354:   return 0;
5355: }

5357: /*@
5358:   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`

5360:   Collective on dm

5362:   Input Parameters:
5363: + dm     - The `DM`
5364: . label  - The `DMLabel` defining the mesh region, or NULL for the entire mesh
5365: . fields - The IS containing the `DM` field numbers for the fields in this `PetscDS`, or NULL for all fields
5366: - prob   - The `PetscDS` defined on the given region

5368:   Note:
5369:   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5370:   the fields argument is ignored.

5372:   Level: advanced

5374: .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5375: @*/
5376: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5377: {
5378:   PetscInt Nds = dm->Nds, s;

5383:   for (s = 0; s < Nds; ++s) {
5384:     if (dm->probs[s].label == label) {
5385:       PetscDSDestroy(&dm->probs[s].ds);
5386:       dm->probs[s].ds = ds;
5387:       return 0;
5388:     }
5389:   }
5390:   DMDSEnlarge_Static(dm, Nds + 1);
5391:   PetscObjectReference((PetscObject)label);
5392:   PetscObjectReference((PetscObject)fields);
5393:   PetscObjectReference((PetscObject)ds);
5394:   if (!label) {
5395:     /* Put the NULL label at the front, so it is returned as the default */
5396:     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5397:     Nds = 0;
5398:   }
5399:   dm->probs[Nds].label  = label;
5400:   dm->probs[Nds].fields = fields;
5401:   dm->probs[Nds].ds     = ds;
5402:   return 0;
5403: }

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

5408:   Not collective

5410:   Input Parameters:
5411: + dm  - The DM
5412: - num - The region number, in [0, Nds)

5414:   Output Parameters:
5415: + label  - The region label, or NULL
5416: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5417: - ds     - The PetscDS defined on the given region, or NULL

5419:   Level: advanced

5421: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5422: @*/
5423: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5424: {
5425:   PetscInt Nds;

5428:   DMGetNumDS(dm, &Nds);
5430:   if (label) {
5432:     *label = dm->probs[num].label;
5433:   }
5434:   if (fields) {
5436:     *fields = dm->probs[num].fields;
5437:   }
5438:   if (ds) {
5440:     *ds = dm->probs[num].ds;
5441:   }
5442:   return 0;
5443: }

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

5448:   Not collective

5450:   Input Parameters:
5451: + dm     - The DM
5452: . num    - The region number, in [0, Nds)
5453: . label  - The region label, or NULL
5454: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5455: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5457:   Level: advanced

5459: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5460: @*/
5461: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5462: {
5463:   PetscInt Nds;

5467:   DMGetNumDS(dm, &Nds);
5469:   PetscObjectReference((PetscObject)label);
5470:   DMLabelDestroy(&dm->probs[num].label);
5471:   dm->probs[num].label = label;
5472:   if (fields) {
5474:     PetscObjectReference((PetscObject)fields);
5475:     ISDestroy(&dm->probs[num].fields);
5476:     dm->probs[num].fields = fields;
5477:   }
5478:   if (ds) {
5480:     PetscObjectReference((PetscObject)ds);
5481:     PetscDSDestroy(&dm->probs[num].ds);
5482:     dm->probs[num].ds = ds;
5483:   }
5484:   return 0;
5485: }

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

5490:   Not collective

5492:   Input Parameters:
5493: + dm  - The DM
5494: - ds  - The PetscDS defined on the given region

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

5499:   Level: advanced

5501: .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5502: @*/
5503: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5504: {
5505:   PetscInt Nds, n;

5510:   DMGetNumDS(dm, &Nds);
5511:   for (n = 0; n < Nds; ++n)
5512:     if (ds == dm->probs[n].ds) break;
5513:   if (n >= Nds) *num = -1;
5514:   else *num = n;
5515:   return 0;
5516: }

5518: /*@C
5519:   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh

5521:   Not collective

5523:   Input Parameters:
5524: + dm     - The `DM`
5525: . Nc     - The number of components for the field
5526: . prefix - The options prefix for the output `PetscFE`, or NULL
5527: - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree

5529:   Output Parameter:
5530: . fem - The `PetscFE`

5532:   Note:
5533:   This is a convenience method that just calls `PetscFECreateByCell()` underneath.

5535:   Level: intermediate

5537: .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5538: @*/
5539: PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5540: {
5541:   DMPolytopeType ct;
5542:   PetscInt       dim, cStart;

5549:   DMGetDimension(dm, &dim);
5550:   DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5551:   DMPlexGetCellType(dm, cStart, &ct);
5552:   PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem);
5553:   return 0;
5554: }

5556: /*@
5557:   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`

5559:   Collective on dm

5561:   Input Parameter:
5562: . dm - The `DM`

5564:   Options Database Keys:
5565: . -dm_petscds_view - View all the `PetscDS` objects in this `DM`

5567:   Note:
5568:   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`.

5570:   Level: intermediate

5572: .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5573: @*/
5574: PetscErrorCode DMCreateDS(DM dm)
5575: {
5576:   MPI_Comm  comm;
5577:   PetscDS   dsDef;
5578:   DMLabel  *labelSet;
5579:   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5580:   PetscBool doSetup = PETSC_TRUE, flg;

5583:   if (!dm->fields) return 0;
5584:   PetscObjectGetComm((PetscObject)dm, &comm);
5585:   DMGetCoordinateDim(dm, &dE);
5586:   /* Determine how many regions we have */
5587:   PetscMalloc1(Nf, &labelSet);
5588:   Nl   = 0;
5589:   Ndef = 0;
5590:   for (f = 0; f < Nf; ++f) {
5591:     DMLabel  label = dm->fields[f].label;
5592:     PetscInt l;

5594: #ifdef PETSC_HAVE_LIBCEED
5595:     /* Move CEED context to discretizations */
5596:     {
5597:       PetscClassId id;

5599:       PetscObjectGetClassId(dm->fields[f].disc, &id);
5600:       if (id == PETSCFE_CLASSID) {
5601:         Ceed ceed;

5603:         DMGetCeed(dm, &ceed);
5604:         PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed);
5605:       }
5606:     }
5607: #endif
5608:     if (!label) {
5609:       ++Ndef;
5610:       continue;
5611:     }
5612:     for (l = 0; l < Nl; ++l)
5613:       if (label == labelSet[l]) break;
5614:     if (l < Nl) continue;
5615:     labelSet[Nl++] = label;
5616:   }
5617:   /* Create default DS if there are no labels to intersect with */
5618:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5619:   if (!dsDef && Ndef && !Nl) {
5620:     IS        fields;
5621:     PetscInt *fld, nf;

5623:     for (f = 0, nf = 0; f < Nf; ++f)
5624:       if (!dm->fields[f].label) ++nf;
5626:     PetscMalloc1(nf, &fld);
5627:     for (f = 0, nf = 0; f < Nf; ++f)
5628:       if (!dm->fields[f].label) fld[nf++] = f;
5629:     ISCreate(PETSC_COMM_SELF, &fields);
5630:     PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5631:     ISSetType(fields, ISGENERAL);
5632:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5634:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5635:     DMSetRegionDS(dm, NULL, fields, dsDef);
5636:     PetscDSDestroy(&dsDef);
5637:     ISDestroy(&fields);
5638:   }
5639:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5640:   if (dsDef) PetscDSSetCoordinateDimension(dsDef, dE);
5641:   /* Intersect labels with default fields */
5642:   if (Ndef && Nl) {
5643:     DM              plex;
5644:     DMLabel         cellLabel;
5645:     IS              fieldIS, allcellIS, defcellIS = NULL;
5646:     PetscInt       *fields;
5647:     const PetscInt *cells;
5648:     PetscInt        depth, nf = 0, n, c;

5650:     DMConvert(dm, DMPLEX, &plex);
5651:     DMPlexGetDepth(plex, &depth);
5652:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5653:     if (!allcellIS) DMGetStratumIS(plex, "depth", depth, &allcellIS);
5654:     /* TODO This looks like it only works for one label */
5655:     for (l = 0; l < Nl; ++l) {
5656:       DMLabel label = labelSet[l];
5657:       IS      pointIS;

5659:       ISDestroy(&defcellIS);
5660:       DMLabelGetStratumIS(label, 1, &pointIS);
5661:       ISDifference(allcellIS, pointIS, &defcellIS);
5662:       ISDestroy(&pointIS);
5663:     }
5664:     ISDestroy(&allcellIS);

5666:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5667:     ISGetLocalSize(defcellIS, &n);
5668:     ISGetIndices(defcellIS, &cells);
5669:     for (c = 0; c < n; ++c) DMLabelSetValue(cellLabel, cells[c], 1);
5670:     ISRestoreIndices(defcellIS, &cells);
5671:     ISDestroy(&defcellIS);
5672:     DMPlexLabelComplete(plex, cellLabel);

5674:     PetscMalloc1(Ndef, &fields);
5675:     for (f = 0; f < Nf; ++f)
5676:       if (!dm->fields[f].label) fields[nf++] = f;
5677:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5678:     PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_");
5679:     ISSetType(fieldIS, ISGENERAL);
5680:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5682:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5683:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5684:     PetscDSSetCoordinateDimension(dsDef, dE);
5685:     DMLabelDestroy(&cellLabel);
5686:     PetscDSDestroy(&dsDef);
5687:     ISDestroy(&fieldIS);
5688:     DMDestroy(&plex);
5689:   }
5690:   /* Create label DSes
5691:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5692:   */
5693:   /* TODO Should check that labels are disjoint */
5694:   for (l = 0; l < Nl; ++l) {
5695:     DMLabel   label = labelSet[l];
5696:     PetscDS   ds;
5697:     IS        fields;
5698:     PetscInt *fld, nf;

5700:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5701:     for (f = 0, nf = 0; f < Nf; ++f)
5702:       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5703:     PetscMalloc1(nf, &fld);
5704:     for (f = 0, nf = 0; f < Nf; ++f)
5705:       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5706:     ISCreate(PETSC_COMM_SELF, &fields);
5707:     PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5708:     ISSetType(fields, ISGENERAL);
5709:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5710:     DMSetRegionDS(dm, label, fields, ds);
5711:     ISDestroy(&fields);
5712:     PetscDSSetCoordinateDimension(ds, dE);
5713:     {
5714:       DMPolytopeType ct;
5715:       PetscInt       lStart, lEnd;
5716:       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;

5718:       DMLabelGetBounds(label, &lStart, &lEnd);
5719:       if (lStart >= 0) {
5720:         DMPlexGetCellType(dm, lStart, &ct);
5721:         switch (ct) {
5722:         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5723:         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5724:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5725:         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5726:           isCohesiveLocal = PETSC_TRUE;
5727:           break;
5728:         default:
5729:           break;
5730:         }
5731:       }
5732:       MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm);
5733:       for (f = 0, nf = 0; f < Nf; ++f) {
5734:         if (label == dm->fields[f].label || !dm->fields[f].label) {
5735:           if (label == dm->fields[f].label) {
5736:             PetscDSSetDiscretization(ds, nf, NULL);
5737:             PetscDSSetCohesive(ds, nf, isCohesive);
5738:           }
5739:           ++nf;
5740:         }
5741:       }
5742:     }
5743:     PetscDSDestroy(&ds);
5744:   }
5745:   PetscFree(labelSet);
5746:   /* Set fields in DSes */
5747:   for (s = 0; s < dm->Nds; ++s) {
5748:     PetscDS         ds     = dm->probs[s].ds;
5749:     IS              fields = dm->probs[s].fields;
5750:     const PetscInt *fld;
5751:     PetscInt        nf, dsnf;
5752:     PetscBool       isCohesive;

5754:     PetscDSGetNumFields(ds, &dsnf);
5755:     PetscDSIsCohesive(ds, &isCohesive);
5756:     ISGetLocalSize(fields, &nf);
5757:     ISGetIndices(fields, &fld);
5758:     for (f = 0; f < nf; ++f) {
5759:       PetscObject  disc = dm->fields[fld[f]].disc;
5760:       PetscBool    isCohesiveField;
5761:       PetscClassId id;

5763:       /* Handle DS with no fields */
5764:       if (dsnf) PetscDSGetCohesive(ds, f, &isCohesiveField);
5765:       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5766:       if (isCohesive && !isCohesiveField) PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&disc);
5767:       PetscDSSetDiscretization(ds, f, disc);
5768:       /* We allow people to have placeholder fields and construct the Section by hand */
5769:       PetscObjectGetClassId(disc, &id);
5770:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5771:     }
5772:     ISRestoreIndices(fields, &fld);
5773:   }
5774:   /* Allow k-jet tabulation */
5775:   PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5776:   if (flg) {
5777:     for (s = 0; s < dm->Nds; ++s) {
5778:       PetscDS  ds = dm->probs[s].ds;
5779:       PetscInt Nf, f;

5781:       PetscDSGetNumFields(ds, &Nf);
5782:       for (f = 0; f < Nf; ++f) PetscDSSetJetDegree(ds, f, k);
5783:     }
5784:   }
5785:   /* Setup DSes */
5786:   if (doSetup) {
5787:     for (s = 0; s < dm->Nds; ++s) PetscDSSetUp(dm->probs[s].ds);
5788:   }
5789:   return 0;
5790: }

5792: /*@
5793:   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.

5795:   Collective on `DM`

5797:   Input Parameters:
5798: + dm   - The `DM`
5799: - time - The time

5801:   Output Parameters:
5802: + u    - The vector will be filled with exact solution values, or NULL
5803: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5805:   Note:
5806:   The user must call `PetscDSSetExactSolution()` before using this routine

5808:   Level: developer

5810: .seealso: `PetscDSSetExactSolution()`
5811: @*/
5812: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5813: {
5814:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5815:   void   **ectxs;
5816:   PetscInt Nf, Nds, s;

5821:   DMGetNumFields(dm, &Nf);
5822:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5823:   DMGetNumDS(dm, &Nds);
5824:   for (s = 0; s < Nds; ++s) {
5825:     PetscDS         ds;
5826:     DMLabel         label;
5827:     IS              fieldIS;
5828:     const PetscInt *fields, id = 1;
5829:     PetscInt        dsNf, f;

5831:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5832:     PetscDSGetNumFields(ds, &dsNf);
5833:     ISGetIndices(fieldIS, &fields);
5834:     PetscArrayzero(exacts, Nf);
5835:     PetscArrayzero(ectxs, Nf);
5836:     if (u) {
5837:       for (f = 0; f < dsNf; ++f) {
5838:         const PetscInt field = fields[f];
5839:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5840:       }
5841:       ISRestoreIndices(fieldIS, &fields);
5842:       if (label) {
5843:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5844:       } else {
5845:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5846:       }
5847:     }
5848:     if (u_t) {
5849:       PetscArrayzero(exacts, Nf);
5850:       PetscArrayzero(ectxs, Nf);
5851:       for (f = 0; f < dsNf; ++f) {
5852:         const PetscInt field = fields[f];
5853:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5854:       }
5855:       ISRestoreIndices(fieldIS, &fields);
5856:       if (label) {
5857:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5858:       } else {
5859:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5860:       }
5861:     }
5862:   }
5863:   if (u) {
5864:     PetscObjectSetName((PetscObject)u, "Exact Solution");
5865:     PetscObjectSetOptionsPrefix((PetscObject)u, "exact_");
5866:   }
5867:   if (u_t) {
5868:     PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative");
5869:     PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_");
5870:   }
5871:   PetscFree2(exacts, ectxs);
5872:   return 0;
5873: }

5875: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5876: {
5877:   PetscDS    dsNew;
5878:   DSBoundary b;
5879:   PetscInt   cdim, Nf, f, d;
5880:   PetscBool  isCohesive;
5881:   void      *ctx;

5883:   PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew);
5884:   PetscDSCopyConstants(ds, dsNew);
5885:   PetscDSCopyExactSolutions(ds, dsNew);
5886:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5887:   PetscDSCopyEquations(ds, dsNew);
5888:   PetscDSGetNumFields(ds, &Nf);
5889:   for (f = 0; f < Nf; ++f) {
5890:     PetscDSGetContext(ds, f, &ctx);
5891:     PetscDSSetContext(dsNew, f, ctx);
5892:     PetscDSGetCohesive(ds, f, &isCohesive);
5893:     PetscDSSetCohesive(dsNew, f, isCohesive);
5894:     PetscDSGetJetDegree(ds, f, &d);
5895:     PetscDSSetJetDegree(dsNew, f, d);
5896:   }
5897:   if (Nf) {
5898:     PetscDSGetCoordinateDimension(ds, &cdim);
5899:     PetscDSSetCoordinateDimension(dsNew, cdim);
5900:   }
5901:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5902:   for (b = dsNew->boundary; b; b = b->next) {
5903:     DMGetLabel(dm, b->lname, &b->label);
5904:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5906:   }

5908:   DMSetRegionDS(dm, label, fields, dsNew);
5909:   PetscDSDestroy(&dsNew);
5910:   return 0;
5911: }

5913: /*@
5914:   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`

5916:   Collective on dm

5918:   Input Parameter:
5919: . dm - The `DM`

5921:   Output Parameter:
5922: . newdm - The `DM`

5924:   Level: advanced

5926: .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5927: @*/
5928: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5929: {
5930:   PetscInt Nds, s;

5932:   if (dm == newdm) return 0;
5933:   DMGetNumDS(dm, &Nds);
5934:   DMClearDS(newdm);
5935:   for (s = 0; s < Nds; ++s) {
5936:     DMLabel  label;
5937:     IS       fields;
5938:     PetscDS  ds, newds;
5939:     PetscInt Nbd, bd;

5941:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5942:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5943:     DMTransferDS_Internal(newdm, label, fields, ds);
5944:     /* Complete new labels in the new DS */
5945:     DMGetRegionDS(newdm, label, NULL, &newds);
5946:     PetscDSGetNumBoundary(newds, &Nbd);
5947:     for (bd = 0; bd < Nbd; ++bd) {
5948:       PetscWeakForm wf;
5949:       DMLabel       label;
5950:       PetscInt      field;

5952:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5953:       PetscWeakFormReplaceLabel(wf, label);
5954:     }
5955:   }
5956:   DMCompleteBCLabels_Internal(newdm);
5957:   return 0;
5958: }

5960: /*@
5961:   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`

5963:   Collective on dm

5965:   Input Parameter:
5966: . dm - The `DM`

5968:   Output Parameter:
5969: . newdm - The `DM`

5971:   Level: advanced

5973:   Developer Note:
5974:   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation

5976: .seealso: `DMCopyFields()`, `DMCopyDS()`
5977: @*/
5978: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5979: {
5980:   DMCopyFields(dm, newdm);
5981:   DMCopyDS(dm, newdm);
5982:   return 0;
5983: }

5985: /*@
5986:   DMGetDimension - Return the topological dimension of the `DM`

5988:   Not collective

5990:   Input Parameter:
5991: . dm - The `DM`

5993:   Output Parameter:
5994: . dim - The topological dimension

5996:   Level: beginner

5998: .seealso: `DMSetDimension()`, `DMCreate()`
5999: @*/
6000: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6001: {
6004:   *dim = dm->dim;
6005:   return 0;
6006: }

6008: /*@
6009:   DMSetDimension - Set the topological dimension of the `DM`

6011:   Collective on dm

6013:   Input Parameters:
6014: + dm - The `DM`
6015: - dim - The topological dimension

6017:   Level: beginner

6019: .seealso: `DMGetDimension()`, `DMCreate()`
6020: @*/
6021: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6022: {
6023:   PetscDS  ds;
6024:   PetscInt Nds, n;

6028:   dm->dim = dim;
6029:   if (dm->dim >= 0) {
6030:     DMGetNumDS(dm, &Nds);
6031:     for (n = 0; n < Nds; ++n) {
6032:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6033:       if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
6034:     }
6035:   }
6036:   return 0;
6037: }

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

6042:   Collective on dm

6044:   Input Parameters:
6045: + dm - the `DM`
6046: - dim - the dimension

6048:   Output Parameters:
6049: + pStart - The first point of the given dimension
6050: - pEnd - The first point following points of the given dimension

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

6057:   Level: intermediate

6059: .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6060: @*/
6061: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6062: {
6063:   PetscInt d;

6066:   DMGetDimension(dm, &d);
6068:   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6069:   return 0;
6070: }

6072: /*@
6073:   DMGetOutputDM - Retrieve the `DM` associated with the layout for output

6075:   Collective on dm

6077:   Input Parameter:
6078: . dm - The original `DM`

6080:   Output Parameter:
6081: . odm - The `DM` which provides the layout for output

6083:   Level: intermediate

6085:   Note:
6086:   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6087:   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6088:   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.

6090: .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6091: @*/
6092: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6093: {
6094:   PetscSection section;
6095:   PetscBool    hasConstraints, ghasConstraints;

6099:   DMGetLocalSection(dm, &section);
6100:   PetscSectionHasConstraints(section, &hasConstraints);
6101:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm));
6102:   if (!ghasConstraints) {
6103:     *odm = dm;
6104:     return 0;
6105:   }
6106:   if (!dm->dmBC) {
6107:     PetscSection newSection, gsection;
6108:     PetscSF      sf;

6110:     DMClone(dm, &dm->dmBC);
6111:     DMCopyDisc(dm, dm->dmBC);
6112:     PetscSectionClone(section, &newSection);
6113:     DMSetLocalSection(dm->dmBC, newSection);
6114:     PetscSectionDestroy(&newSection);
6115:     DMGetPointSF(dm->dmBC, &sf);
6116:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6117:     DMSetGlobalSection(dm->dmBC, gsection);
6118:     PetscSectionDestroy(&gsection);
6119:   }
6120:   *odm = dm->dmBC;
6121:   return 0;
6122: }

6124: /*@
6125:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6127:   Input Parameter:
6128: . dm - The original `DM`

6130:   Output Parameters:
6131: + num - The output sequence number
6132: - val - The output sequence value

6134:   Level: intermediate

6136:   Note:
6137:   This is intended for output that should appear in sequence, for instance
6138:   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.

6140:   Developer Note:
6141:   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6142:   not directly related to the `DM`.

6144: .seealso: `VecView()`
6145: @*/
6146: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6147: {
6149:   if (num) {
6151:     *num = dm->outputSequenceNum;
6152:   }
6153:   if (val) {
6155:     *val = dm->outputSequenceVal;
6156:   }
6157:   return 0;
6158: }

6160: /*@
6161:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6163:   Input Parameters:
6164: + dm - The original `DM`
6165: . num - The output sequence number
6166: - val - The output sequence value

6168:   Level: intermediate

6170:   Note:
6171:   This is intended for output that should appear in sequence, for instance
6172:   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.

6174: .seealso: `VecView()`
6175: @*/
6176: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6177: {
6179:   dm->outputSequenceNum = num;
6180:   dm->outputSequenceVal = val;
6181:   return 0;
6182: }

6184: /*@C
6185:  DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`

6187:   Input Parameters:
6188: + dm   - The original `DM`
6189: . name - The sequence name
6190: - num  - The output sequence number

6192:   Output Parameter:
6193: . val  - The output sequence value

6195:   Level: intermediate

6197:   Note:
6198:   This is intended for output that should appear in sequence, for instance
6199:   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.

6201:   Developer Note:
6202:   It is unclear at the user API level why a `DM` is needed as input

6204: .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6205: @*/
6206: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6207: {
6208:   PetscBool ishdf5;

6213:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
6214:   if (ishdf5) {
6215: #if defined(PETSC_HAVE_HDF5)
6216:     PetscScalar value;

6218:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6219:     *val = PetscRealPart(value);
6220: #endif
6221:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6222:   return 0;
6223: }

6225: /*@
6226:   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel

6228:   Not collective

6230:   Input Parameter:
6231: . dm - The `DM`

6233:   Output Parameter:
6234: . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution

6236:   Level: beginner

6238: .seealso: `DMSetUseNatural()`, `DMCreate()`
6239: @*/
6240: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6241: {
6244:   *useNatural = dm->useNatural;
6245:   return 0;
6246: }

6248: /*@
6249:   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel

6251:   Collective on dm

6253:   Input Parameters:
6254:  + dm - The `DM`
6255: - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution

6257:   Note:
6258:   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`

6260:   Level: beginner

6262: .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6263: @*/
6264: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6265: {
6268:   dm->useNatural = useNatural;
6269:   return 0;
6270: }

6272: /*@C
6273:   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`

6275:   Not Collective

6277:   Input Parameters:
6278: + dm   - The `DM` object
6279: - name - The label name

6281:   Level: intermediate

6283: .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6284: @*/
6285: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6286: {
6287:   PetscBool flg;
6288:   DMLabel   label;

6292:   DMHasLabel(dm, name, &flg);
6293:   if (!flg) {
6294:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6295:     DMAddLabel(dm, label);
6296:     DMLabelDestroy(&label);
6297:   }
6298:   return 0;
6299: }

6301: /*@C
6302:   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.

6304:   Not Collective

6306:   Input Parameters:
6307: + dm   - The `DM` object
6308: . l    - The index for the label
6309: - name - The label name

6311:   Level: intermediate

6313: .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6314: @*/
6315: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6316: {
6317:   DMLabelLink orig, prev = NULL;
6318:   DMLabel     label;
6319:   PetscInt    Nl, m;
6320:   PetscBool   flg, match;
6321:   const char *lname;

6325:   DMHasLabel(dm, name, &flg);
6326:   if (!flg) {
6327:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6328:     DMAddLabel(dm, label);
6329:     DMLabelDestroy(&label);
6330:   }
6331:   DMGetNumLabels(dm, &Nl);
6333:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6334:     PetscObjectGetName((PetscObject)orig->label, &lname);
6335:     PetscStrcmp(name, lname, &match);
6336:     if (match) break;
6337:   }
6338:   if (m == l) return 0;
6339:   if (!m) dm->labels = orig->next;
6340:   else prev->next = orig->next;
6341:   if (!l) {
6342:     orig->next = dm->labels;
6343:     dm->labels = orig;
6344:   } else {
6345:     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6346:       ;
6347:     orig->next = prev->next;
6348:     prev->next = orig;
6349:   }
6350:   return 0;
6351: }

6353: /*@C
6354:   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default

6356:   Not Collective

6358:   Input Parameters:
6359: + dm   - The `DM` object
6360: . name - The label name
6361: - point - The mesh point

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

6366:   Level: beginner

6368: .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6369: @*/
6370: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6371: {
6372:   DMLabel label;

6376:   DMGetLabel(dm, name, &label);
6378:   DMLabelGetValue(label, point, value);
6379:   return 0;
6380: }

6382: /*@C
6383:   DMSetLabelValue - Add a point to a `DMLabel` with given value

6385:   Not Collective

6387:   Input Parameters:
6388: + dm   - The `DM` object
6389: . name - The label name
6390: . point - The mesh point
6391: - value - The label value for this point

6393:   Output Parameter:

6395:   Level: beginner

6397: .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6398: @*/
6399: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6400: {
6401:   DMLabel label;

6405:   DMGetLabel(dm, name, &label);
6406:   if (!label) {
6407:     DMCreateLabel(dm, name);
6408:     DMGetLabel(dm, name, &label);
6409:   }
6410:   DMLabelSetValue(label, point, value);
6411:   return 0;
6412: }

6414: /*@C
6415:   DMClearLabelValue - Remove a point from a `DMLabel` with given value

6417:   Not Collective

6419:   Input Parameters:
6420: + dm   - The `DM` object
6421: . name - The label name
6422: . point - The mesh point
6423: - value - The label value for this point

6425:   Level: beginner

6427: .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6428: @*/
6429: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6430: {
6431:   DMLabel label;

6435:   DMGetLabel(dm, name, &label);
6436:   if (!label) return 0;
6437:   DMLabelClearValue(label, point, value);
6438:   return 0;
6439: }

6441: /*@C
6442:   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`

6444:   Not Collective

6446:   Input Parameters:
6447: + dm   - The `DM` object
6448: - name - The label name

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

6453:   Level: beginner

6455:   Developer Note:
6456:   This should be renamed to something like `DMGetLabelNumValues()` or removed.

6458: .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6459: @*/
6460: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6461: {
6462:   DMLabel label;

6467:   DMGetLabel(dm, name, &label);
6468:   *size = 0;
6469:   if (!label) return 0;
6470:   DMLabelGetNumValues(label, size);
6471:   return 0;
6472: }

6474: /*@C
6475:   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`

6477:   Not Collective

6479:   Input Parameters:
6480: + mesh - The `DM` object
6481: - name - The label name

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

6486:   Level: beginner

6488: .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6489: @*/
6490: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6491: {
6492:   DMLabel label;

6497:   DMGetLabel(dm, name, &label);
6498:   *ids = NULL;
6499:   if (label) {
6500:     DMLabelGetValueIS(label, ids);
6501:   } else {
6502:     /* returning an empty IS */
6503:     ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids);
6504:   }
6505:   return 0;
6506: }

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

6511:   Not Collective

6513:   Input Parameters:
6514: + dm - The `DM` object
6515: . name - The label name
6516: - value - The stratum value

6518:   Output Parameter:
6519: . size - The number of points, also called the stratum size

6521:   Level: beginner

6523: .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6524: @*/
6525: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6526: {
6527:   DMLabel label;

6532:   DMGetLabel(dm, name, &label);
6533:   *size = 0;
6534:   if (!label) return 0;
6535:   DMLabelGetStratumSize(label, value, size);
6536:   return 0;
6537: }

6539: /*@C
6540:   DMGetStratumIS - Get the points in a label stratum

6542:   Not Collective

6544:   Input Parameters:
6545: + dm - The `DM` object
6546: . name - The label name
6547: - value - The stratum value

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

6552:   Level: beginner

6554: .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6555: @*/
6556: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6557: {
6558:   DMLabel label;

6563:   DMGetLabel(dm, name, &label);
6564:   *points = NULL;
6565:   if (!label) return 0;
6566:   DMLabelGetStratumIS(label, value, points);
6567:   return 0;
6568: }

6570: /*@C
6571:   DMSetStratumIS - Set the points in a label stratum

6573:   Not Collective

6575:   Input Parameters:
6576: + dm - The `DM` object
6577: . name - The label name
6578: . value - The stratum value
6579: - points - The stratum points

6581:   Level: beginner

6583: .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6584: @*/
6585: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6586: {
6587:   DMLabel label;

6592:   DMGetLabel(dm, name, &label);
6593:   if (!label) return 0;
6594:   DMLabelSetStratumIS(label, value, points);
6595:   return 0;
6596: }

6598: /*@C
6599:   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`

6601:   Not Collective

6603:   Input Parameters:
6604: + dm   - The `DM` object
6605: . name - The label name
6606: - value - The label value for this point

6608:   Output Parameter:

6610:   Level: beginner

6612: .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6613: @*/
6614: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6615: {
6616:   DMLabel label;

6620:   DMGetLabel(dm, name, &label);
6621:   if (!label) return 0;
6622:   DMLabelClearStratum(label, value);
6623:   return 0;
6624: }

6626: /*@
6627:   DMGetNumLabels - Return the number of labels defined by on the `DM`

6629:   Not Collective

6631:   Input Parameter:
6632: . dm   - The `DM` object

6634:   Output Parameter:
6635: . numLabels - the number of Labels

6637:   Level: intermediate

6639: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6640: @*/
6641: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6642: {
6643:   DMLabelLink next = dm->labels;
6644:   PetscInt    n    = 0;

6648:   while (next) {
6649:     ++n;
6650:     next = next->next;
6651:   }
6652:   *numLabels = n;
6653:   return 0;
6654: }

6656: /*@C
6657:   DMGetLabelName - Return the name of nth label

6659:   Not Collective

6661:   Input Parameters:
6662: + dm - The `DM` object
6663: - n  - the label number

6665:   Output Parameter:
6666: . name - the label name

6668:   Level: intermediate

6670:   Developer Note:
6671:   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.

6673: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6674: @*/
6675: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6676: {
6677:   DMLabelLink next = dm->labels;
6678:   PetscInt    l    = 0;

6682:   while (next) {
6683:     if (l == n) {
6684:       PetscObjectGetName((PetscObject)next->label, name);
6685:       return 0;
6686:     }
6687:     ++l;
6688:     next = next->next;
6689:   }
6690:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6691: }

6693: /*@C
6694:   DMHasLabel - Determine whether the `DM` has a label of a given name

6696:   Not Collective

6698:   Input Parameters:
6699: + dm   - The `DM` object
6700: - name - The label name

6702:   Output Parameter:
6703: . hasLabel - `PETSC_TRUE` if the label is present

6705:   Level: intermediate

6707: .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6708: @*/
6709: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6710: {
6711:   DMLabelLink next = dm->labels;
6712:   const char *lname;

6717:   *hasLabel = PETSC_FALSE;
6718:   while (next) {
6719:     PetscObjectGetName((PetscObject)next->label, &lname);
6720:     PetscStrcmp(name, lname, hasLabel);
6721:     if (*hasLabel) break;
6722:     next = next->next;
6723:   }
6724:   return 0;
6725: }

6727: /*@C
6728:   DMGetLabel - Return the label of a given name, or NULL, from a `DM`

6730:   Not Collective

6732:   Input Parameters:
6733: + dm   - The `DM` object
6734: - name - The label name

6736:   Output Parameter:
6737: . label - The `DMLabel`, or NULL if the label is absent

6739:   Default labels in a `DMPLEX`:
6740: +   "depth"       - Holds the depth (co-dimension) of each mesh point
6741: .   "celltype"    - Holds the topological type of each cell
6742: .   "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6743: .   "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6744: .   "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6745: -  "Vertex Sets" - Mirrors the vertex sets defined by GMsh

6747:   Level: intermediate

6749: .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6750: @*/
6751: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6752: {
6753:   DMLabelLink next = dm->labels;
6754:   PetscBool   hasLabel;
6755:   const char *lname;

6760:   *label = NULL;
6761:   while (next) {
6762:     PetscObjectGetName((PetscObject)next->label, &lname);
6763:     PetscStrcmp(name, lname, &hasLabel);
6764:     if (hasLabel) {
6765:       *label = next->label;
6766:       break;
6767:     }
6768:     next = next->next;
6769:   }
6770:   return 0;
6771: }

6773: /*@C
6774:   DMGetLabelByNum - Return the nth label on a `DM`

6776:   Not Collective

6778:   Input Parameters:
6779: + dm - The `DM` object
6780: - n  - the label number

6782:   Output Parameter:
6783: . label - the label

6785:   Level: intermediate

6787: .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6788: @*/
6789: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6790: {
6791:   DMLabelLink next = dm->labels;
6792:   PetscInt    l    = 0;

6796:   while (next) {
6797:     if (l == n) {
6798:       *label = next->label;
6799:       return 0;
6800:     }
6801:     ++l;
6802:     next = next->next;
6803:   }
6804:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6805: }

6807: /*@C
6808:   DMAddLabel - Add the label to this `DM`

6810:   Not Collective

6812:   Input Parameters:
6813: + dm   - The `DM` object
6814: - label - The `DMLabel`

6816:   Level: developer

6818: .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6819: @*/
6820: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6821: {
6822:   DMLabelLink l, *p, tmpLabel;
6823:   PetscBool   hasLabel;
6824:   const char *lname;
6825:   PetscBool   flg;

6828:   PetscObjectGetName((PetscObject)label, &lname);
6829:   DMHasLabel(dm, lname, &hasLabel);
6831:   PetscCalloc1(1, &tmpLabel);
6832:   tmpLabel->label  = label;
6833:   tmpLabel->output = PETSC_TRUE;
6834:   for (p = &dm->labels; (l = *p); p = &l->next) { }
6835:   *p = tmpLabel;
6836:   PetscObjectReference((PetscObject)label);
6837:   PetscStrcmp(lname, "depth", &flg);
6838:   if (flg) dm->depthLabel = label;
6839:   PetscStrcmp(lname, "celltype", &flg);
6840:   if (flg) dm->celltypeLabel = label;
6841:   return 0;
6842: }

6844: /*@C
6845:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

6847:   Not Collective

6849:   Input Parameters:
6850: + dm    - The `DM` object
6851: - label - The `DMLabel`, having the same name, to substitute

6853:   Default labels in a `DMPLEX`:
6854: +  "depth"       - Holds the depth (co-dimension) of each mesh point
6855: .  "celltype"    - Holds the topological type of each cell
6856: .  "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6857: .  "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6858: .  "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6859: - "Vertex Sets" - Mirrors the vertex sets defined by GMsh

6861:   Level: intermediate

6863: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6864: @*/
6865: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
6866: {
6867:   DMLabelLink next = dm->labels;
6868:   PetscBool   hasLabel, flg;
6869:   const char *name, *lname;

6873:   PetscObjectGetName((PetscObject)label, &name);
6874:   while (next) {
6875:     PetscObjectGetName((PetscObject)next->label, &lname);
6876:     PetscStrcmp(name, lname, &hasLabel);
6877:     if (hasLabel) {
6878:       PetscObjectReference((PetscObject)label);
6879:       PetscStrcmp(lname, "depth", &flg);
6880:       if (flg) dm->depthLabel = label;
6881:       PetscStrcmp(lname, "celltype", &flg);
6882:       if (flg) dm->celltypeLabel = label;
6883:       DMLabelDestroy(&next->label);
6884:       next->label = label;
6885:       break;
6886:     }
6887:     next = next->next;
6888:   }
6889:   return 0;
6890: }

6892: /*@C
6893:   DMRemoveLabel - Remove the label given by name from this `DM`

6895:   Not Collective

6897:   Input Parameters:
6898: + dm   - The `DM` object
6899: - name - The label name

6901:   Output Parameter:
6902: . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the
6903:           caller is responsible for calling `DMLabelDestroy()`.

6905:   Level: developer

6907: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
6908: @*/
6909: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6910: {
6911:   DMLabelLink link, *pnext;
6912:   PetscBool   hasLabel;
6913:   const char *lname;

6917:   if (label) {
6919:     *label = NULL;
6920:   }
6921:   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6922:     PetscObjectGetName((PetscObject)link->label, &lname);
6923:     PetscStrcmp(name, lname, &hasLabel);
6924:     if (hasLabel) {
6925:       *pnext = link->next; /* Remove from list */
6926:       PetscStrcmp(name, "depth", &hasLabel);
6927:       if (hasLabel) dm->depthLabel = NULL;
6928:       PetscStrcmp(name, "celltype", &hasLabel);
6929:       if (hasLabel) dm->celltypeLabel = NULL;
6930:       if (label) *label = link->label;
6931:       else DMLabelDestroy(&link->label);
6932:       PetscFree(link);
6933:       break;
6934:     }
6935:   }
6936:   return 0;
6937: }

6939: /*@
6940:   DMRemoveLabelBySelf - Remove the label from this `DM`

6942:   Not Collective

6944:   Input Parameters:
6945: + dm   - The `DM` object
6946: . label - The `DMLabel` to be removed from the `DM`
6947: - failNotFound - Should it fail if the label is not found in the DM?

6949:   Level: developer

6951:   Note:
6952:   Only exactly the same instance is removed if found, name match is ignored.
6953:   If the `DM` has an exclusive reference to the label, the label gets destroyed and
6954:   *label nullified.

6956: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
6957: @*/
6958: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
6959: {
6960:   DMLabelLink link, *pnext;
6961:   PetscBool   hasLabel = PETSC_FALSE;

6965:   if (!*label && !failNotFound) return 0;
6968:   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6969:     if (*label == link->label) {
6970:       hasLabel = PETSC_TRUE;
6971:       *pnext   = link->next; /* Remove from list */
6972:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
6973:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
6974:       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
6975:       DMLabelDestroy(&link->label);
6976:       PetscFree(link);
6977:       break;
6978:     }
6979:   }
6981:   return 0;
6982: }

6984: /*@C
6985:   DMGetLabelOutput - Get the output flag for a given label

6987:   Not Collective

6989:   Input Parameters:
6990: + dm   - The `DM` object
6991: - name - The label name

6993:   Output Parameter:
6994: . output - The flag for output

6996:   Level: developer

6998: .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6999: @*/
7000: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7001: {
7002:   DMLabelLink next = dm->labels;
7003:   const char *lname;

7008:   while (next) {
7009:     PetscBool flg;

7011:     PetscObjectGetName((PetscObject)next->label, &lname);
7012:     PetscStrcmp(name, lname, &flg);
7013:     if (flg) {
7014:       *output = next->output;
7015:       return 0;
7016:     }
7017:     next = next->next;
7018:   }
7019:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7020: }

7022: /*@C
7023:   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`

7025:   Not Collective

7027:   Input Parameters:
7028: + dm     - The `DM` object
7029: . name   - The label name
7030: - output - `PETSC_TRUE` to save the label to the viewer

7032:   Level: developer

7034: .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7035: @*/
7036: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7037: {
7038:   DMLabelLink next = dm->labels;
7039:   const char *lname;

7043:   while (next) {
7044:     PetscBool flg;

7046:     PetscObjectGetName((PetscObject)next->label, &lname);
7047:     PetscStrcmp(name, lname, &flg);
7048:     if (flg) {
7049:       next->output = output;
7050:       return 0;
7051:     }
7052:     next = next->next;
7053:   }
7054:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7055: }

7057: /*@
7058:   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points

7060:   Collective on dmA

7062:   Input Parameters:
7063: + dmA - The `DM` object with initial labels
7064: . dmB - The `DM` object to which labels are copied
7065: . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7066: . all  - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7067: - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)

7069:   Level: intermediate

7071:   Note:
7072:   This is typically used when interpolating or otherwise adding to a mesh, or testing.

7074: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7075: @*/
7076: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7077: {
7078:   DMLabel     label, labelNew, labelOld;
7079:   const char *name;
7080:   PetscBool   flg;
7081:   DMLabelLink link;

7088:   if (dmA == dmB) return 0;
7089:   for (link = dmA->labels; link; link = link->next) {
7090:     label = link->label;
7091:     PetscObjectGetName((PetscObject)label, &name);
7092:     if (!all) {
7093:       PetscStrcmp(name, "depth", &flg);
7094:       if (flg) continue;
7095:       PetscStrcmp(name, "dim", &flg);
7096:       if (flg) continue;
7097:       PetscStrcmp(name, "celltype", &flg);
7098:       if (flg) continue;
7099:     }
7100:     DMGetLabel(dmB, name, &labelOld);
7101:     if (labelOld) {
7102:       switch (emode) {
7103:       case DM_COPY_LABELS_KEEP:
7104:         continue;
7105:       case DM_COPY_LABELS_REPLACE:
7106:         DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
7107:         break;
7108:       case DM_COPY_LABELS_FAIL:
7109:         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7110:       default:
7111:         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7112:       }
7113:     }
7114:     if (mode == PETSC_COPY_VALUES) {
7115:       DMLabelDuplicate(label, &labelNew);
7116:     } else {
7117:       labelNew = label;
7118:     }
7119:     DMAddLabel(dmB, labelNew);
7120:     if (mode == PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
7121:   }
7122:   return 0;
7123: }

7125: /*@C
7126:   DMCompareLabels - Compare labels of two `DMPLEX` meshes

7128:   Collective

7130:   Input Parameters:
7131: + dm0 - First `DM` object
7132: - dm1 - Second `DM` object

7134:   Output Parameters
7135: + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7136: - message - (Optional) Message describing the difference, or NULL if there is no difference

7138:   Level: intermediate

7140:   Notes:
7141:   The output flag equal will be the same on all processes.

7143:   If equal is passed as NULL and difference is found, an error is thrown on all processes.

7145:   Make sure to pass equal is NULL on all processes or none of them.

7147:   The output message is set independently on each rank.

7149:   message must be freed with `PetscFree()`

7151:   If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner.

7153:   Make sure to pass message as NULL on all processes or no processes.

7155:   Labels are matched by name. If the number of labels and their names are equal,
7156:   `DMLabelCompare()` is used to compare each pair of labels with the same name.

7158:   Fortran Note:
7159:   This function is not available from Fortran.

7161: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7162: @*/
7163: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7164: {
7165:   PetscInt    n, i;
7166:   char        msg[PETSC_MAX_PATH_LEN] = "";
7167:   PetscBool   eq;
7168:   MPI_Comm    comm;
7169:   PetscMPIInt rank;

7176:   PetscObjectGetComm((PetscObject)dm0, &comm);
7177:   MPI_Comm_rank(comm, &rank);
7178:   {
7179:     PetscInt n1;

7181:     DMGetNumLabels(dm0, &n);
7182:     DMGetNumLabels(dm1, &n1);
7183:     eq = (PetscBool)(n == n1);
7184:     if (!eq) PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1);
7185:     MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7186:     if (!eq) goto finish;
7187:   }
7188:   for (i = 0; i < n; i++) {
7189:     DMLabel     l0, l1;
7190:     const char *name;
7191:     char       *msgInner;

7193:     /* Ignore label order */
7194:     DMGetLabelByNum(dm0, i, &l0);
7195:     PetscObjectGetName((PetscObject)l0, &name);
7196:     DMGetLabel(dm1, name, &l1);
7197:     if (!l1) {
7198:       PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i);
7199:       eq = PETSC_FALSE;
7200:       break;
7201:     }
7202:     DMLabelCompare(comm, l0, l1, &eq, &msgInner);
7203:     PetscStrncpy(msg, msgInner, sizeof(msg));
7204:     PetscFree(msgInner);
7205:     if (!eq) break;
7206:   }
7207:   MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7208: finish:
7209:   /* If message output arg not set, print to stderr */
7210:   if (message) {
7211:     *message = NULL;
7212:     if (msg[0]) PetscStrallocpy(msg, message);
7213:   } else {
7214:     if (msg[0]) PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
7215:     PetscSynchronizedFlush(comm, PETSC_STDERR);
7216:   }
7217:   /* If same output arg not ser and labels are not equal, throw error */
7218:   if (equal) *equal = eq;
7220:   return 0;
7221: }

7223: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7224: {
7226:   if (!*label) {
7227:     DMCreateLabel(dm, name);
7228:     DMGetLabel(dm, name, label);
7229:   }
7230:   DMLabelSetValue(*label, point, value);
7231:   return 0;
7232: }

7234: /*
7235:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7236:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7237:   (label, id) pair in the DM.

7239:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7240:   each label.
7241: */
7242: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7243: {
7244:   DMUniversalLabel ul;
7245:   PetscBool       *active;
7246:   PetscInt         pStart, pEnd, p, Nl, l, m;

7248:   PetscMalloc1(1, &ul);
7249:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
7250:   DMGetNumLabels(dm, &Nl);
7251:   PetscCalloc1(Nl, &active);
7252:   ul->Nl = 0;
7253:   for (l = 0; l < Nl; ++l) {
7254:     PetscBool   isdepth, iscelltype;
7255:     const char *name;

7257:     DMGetLabelName(dm, l, &name);
7258:     PetscStrncmp(name, "depth", 6, &isdepth);
7259:     PetscStrncmp(name, "celltype", 9, &iscelltype);
7260:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7261:     if (active[l]) ++ul->Nl;
7262:   }
7263:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks);
7264:   ul->Nv = 0;
7265:   for (l = 0, m = 0; l < Nl; ++l) {
7266:     DMLabel     label;
7267:     PetscInt    nv;
7268:     const char *name;

7270:     if (!active[l]) continue;
7271:     DMGetLabelName(dm, l, &name);
7272:     DMGetLabelByNum(dm, l, &label);
7273:     DMLabelGetNumValues(label, &nv);
7274:     PetscStrallocpy(name, &ul->names[m]);
7275:     ul->indices[m] = l;
7276:     ul->Nv += nv;
7277:     ul->offsets[m + 1] = nv;
7278:     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7279:     ++m;
7280:   }
7281:   for (l = 1; l <= ul->Nl; ++l) {
7282:     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7283:     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7284:   }
7285:   for (l = 0; l < ul->Nl; ++l) {
7286:     PetscInt b;

7288:     ul->masks[l] = 0;
7289:     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7290:   }
7291:   PetscMalloc1(ul->Nv, &ul->values);
7292:   for (l = 0, m = 0; l < Nl; ++l) {
7293:     DMLabel         label;
7294:     IS              valueIS;
7295:     const PetscInt *varr;
7296:     PetscInt        nv, v;

7298:     if (!active[l]) continue;
7299:     DMGetLabelByNum(dm, l, &label);
7300:     DMLabelGetNumValues(label, &nv);
7301:     DMLabelGetValueIS(label, &valueIS);
7302:     ISGetIndices(valueIS, &varr);
7303:     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7304:     ISRestoreIndices(valueIS, &varr);
7305:     ISDestroy(&valueIS);
7306:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
7307:     ++m;
7308:   }
7309:   DMPlexGetChart(dm, &pStart, &pEnd);
7310:   for (p = pStart; p < pEnd; ++p) {
7311:     PetscInt  uval   = 0;
7312:     PetscBool marked = PETSC_FALSE;

7314:     for (l = 0, m = 0; l < Nl; ++l) {
7315:       DMLabel  label;
7316:       PetscInt val, defval, loc, nv;

7318:       if (!active[l]) continue;
7319:       DMGetLabelByNum(dm, l, &label);
7320:       DMLabelGetValue(label, p, &val);
7321:       DMLabelGetDefaultValue(label, &defval);
7322:       if (val == defval) {
7323:         ++m;
7324:         continue;
7325:       }
7326:       nv     = ul->offsets[m + 1] - ul->offsets[m];
7327:       marked = PETSC_TRUE;
7328:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
7330:       uval += (loc + 1) << ul->bits[m];
7331:       ++m;
7332:     }
7333:     if (marked) DMLabelSetValue(ul->label, p, uval);
7334:   }
7335:   PetscFree(active);
7336:   *universal = ul;
7337:   return 0;
7338: }

7340: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7341: {
7342:   PetscInt l;

7344:   for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
7345:   DMLabelDestroy(&(*universal)->label);
7346:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
7347:   PetscFree((*universal)->values);
7348:   PetscFree(*universal);
7349:   *universal = NULL;
7350:   return 0;
7351: }

7353: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7354: {
7356:   *ulabel = ul->label;
7357:   return 0;
7358: }

7360: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7361: {
7362:   PetscInt Nl = ul->Nl, l;

7365:   for (l = 0; l < Nl; ++l) {
7366:     if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
7367:     else DMCreateLabel(dm, ul->names[l]);
7368:   }
7369:   if (preserveOrder) {
7370:     for (l = 0; l < ul->Nl; ++l) {
7371:       const char *name;
7372:       PetscBool   match;

7374:       DMGetLabelName(dm, ul->indices[l], &name);
7375:       PetscStrcmp(name, ul->names[l], &match);
7377:     }
7378:   }
7379:   return 0;
7380: }

7382: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7383: {
7384:   PetscInt l;

7386:   for (l = 0; l < ul->Nl; ++l) {
7387:     DMLabel  label;
7388:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

7390:     if (lval) {
7391:       if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
7392:       else DMGetLabel(dm, ul->names[l], &label);
7393:       DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]);
7394:     }
7395:   }
7396:   return 0;
7397: }

7399: /*@
7400:   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement

7402:   Not collective

7404:   Input Parameter:
7405: . dm - The `DM` object

7407:   Output Parameter:
7408: . cdm - The coarse `DM`

7410:   Level: intermediate

7412: .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7413: @*/
7414: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7415: {
7418:   *cdm = dm->coarseMesh;
7419:   return 0;
7420: }

7422: /*@
7423:   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement

7425:   Input Parameters:
7426: + dm - The `DM` object
7427: - cdm - The coarse `DM`

7429:   Level: intermediate

7431:   Note:
7432:   Normally this is set automatically by `DMRefine()`

7434: .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7435: @*/
7436: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7437: {
7440:   if (dm == cdm) cdm = NULL;
7441:   PetscObjectReference((PetscObject)cdm);
7442:   DMDestroy(&dm->coarseMesh);
7443:   dm->coarseMesh = cdm;
7444:   return 0;
7445: }

7447: /*@
7448:   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening

7450:   Input Parameter:
7451: . dm - The `DM` object

7453:   Output Parameter:
7454: . fdm - The fine `DM`

7456:   Level: intermediate

7458: .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7459: @*/
7460: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7461: {
7464:   *fdm = dm->fineMesh;
7465:   return 0;
7466: }

7468: /*@
7469:   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening

7471:   Input Parameters:
7472: + dm - The `DM` object
7473: - fdm - The fine `DM`

7475:   Level: developer

7477:   Note:
7478:   Normally this is set automatically by `DMCoarsen()`

7480: .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7481: @*/
7482: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7483: {
7486:   if (dm == fdm) fdm = NULL;
7487:   PetscObjectReference((PetscObject)fdm);
7488:   DMDestroy(&dm->fineMesh);
7489:   dm->fineMesh = fdm;
7490:   return 0;
7491: }

7493: /*@C
7494:   DMAddBoundary - Add a boundary condition to a model represented by a `DM`

7496:   Collective on dm

7498:   Input Parameters:
7499: + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7500: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7501: . name     - The BC name
7502: . label    - The label defining constrained points
7503: . Nv       - The number of `DMLabel` values for constrained points
7504: . values   - An array of values for constrained points
7505: . field    - The field to constrain
7506: . Nc       - The number of constrained field components (0 will constrain all fields)
7507: . comps    - An array of constrained component numbers
7508: . bcFunc   - A pointwise function giving boundary values
7509: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7510: - ctx      - An optional user context for bcFunc

7512:   Output Parameter:
7513: . bd          - (Optional) Boundary number

7515:   Options Database Keys:
7516: + -bc_<boundary name> <num> - Overrides the boundary ids
7517: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7519:   Notes:
7520:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:

7522: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

7524:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:

7526: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7527: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7528: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7529: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

7531: + dim - the spatial dimension
7532: . Nf - the number of fields
7533: . uOff - the offset into u[] and u_t[] for each field
7534: . uOff_x - the offset into u_x[] for each field
7535: . u - each field evaluated at the current point
7536: . u_t - the time derivative of each field evaluated at the current point
7537: . u_x - the gradient of each field evaluated at the current point
7538: . aOff - the offset into a[] and a_t[] for each auxiliary field
7539: . aOff_x - the offset into a_x[] for each auxiliary field
7540: . a - each auxiliary field evaluated at the current point
7541: . a_t - the time derivative of each auxiliary field evaluated at the current point
7542: . a_x - the gradient of auxiliary each field evaluated at the current point
7543: . t - current time
7544: . x - coordinates of the current point
7545: . numConstants - number of constant parameters
7546: . constants - constant parameters
7547: - bcval - output values at the current point

7549:   Level: intermediate

7551: .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7552: @*/
7553: 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)
7554: {
7555:   PetscDS ds;

7564:   DMGetDS(dm, &ds);
7565:   /* Complete label */
7566:   if (label) {
7567:     PetscObject  obj;
7568:     PetscClassId id;

7570:     DMGetField(dm, field, NULL, &obj);
7571:     PetscObjectGetClassId(obj, &id);
7572:     if (id == PETSCFE_CLASSID) {
7573:       DM plex;

7575:       DMConvert(dm, DMPLEX, &plex);
7576:       if (plex) DMPlexLabelComplete(plex, label);
7577:       DMDestroy(&plex);
7578:     }
7579:   }
7580:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
7581:   return 0;
7582: }

7584: /* TODO Remove this since now the structures are the same */
7585: static PetscErrorCode DMPopulateBoundary(DM dm)
7586: {
7587:   PetscDS     ds;
7588:   DMBoundary *lastnext;
7589:   DSBoundary  dsbound;

7591:   DMGetDS(dm, &ds);
7592:   dsbound = ds->boundary;
7593:   if (dm->boundary) {
7594:     DMBoundary next = dm->boundary;

7596:     /* quick check to see if the PetscDS has changed */
7597:     if (next->dsboundary == dsbound) return 0;
7598:     /* the PetscDS has changed: tear down and rebuild */
7599:     while (next) {
7600:       DMBoundary b = next;

7602:       next = b->next;
7603:       PetscFree(b);
7604:     }
7605:     dm->boundary = NULL;
7606:   }

7608:   lastnext = &(dm->boundary);
7609:   while (dsbound) {
7610:     DMBoundary dmbound;

7612:     PetscNew(&dmbound);
7613:     dmbound->dsboundary = dsbound;
7614:     dmbound->label      = dsbound->label;
7615:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7616:     *lastnext = dmbound;
7617:     lastnext  = &(dmbound->next);
7618:     dsbound   = dsbound->next;
7619:   }
7620:   return 0;
7621: }

7623: /* TODO: missing manual page */
7624: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7625: {
7626:   DMBoundary b;

7630:   *isBd = PETSC_FALSE;
7631:   DMPopulateBoundary(dm);
7632:   b = dm->boundary;
7633:   while (b && !(*isBd)) {
7634:     DMLabel    label = b->label;
7635:     DSBoundary dsb   = b->dsboundary;
7636:     PetscInt   i;

7638:     if (label) {
7639:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
7640:     }
7641:     b = b->next;
7642:   }
7643:   return 0;
7644: }

7646: /*@C
7647:   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.

7649:   Collective on dm

7651:   Input Parameters:
7652: + dm      - The `DM`
7653: . time    - The time
7654: . funcs   - The coordinate functions to evaluate, one per field
7655: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7656: - mode    - The insertion mode for values

7658:   Output Parameter:
7659: . X - vector

7661:    Calling sequence of func:
7662: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7664: +  dim - The spatial dimension
7665: .  time - The time at which to sample
7666: .  x   - The coordinates
7667: .  Nc  - The number of components
7668: .  u   - The output field values
7669: -  ctx - optional user-defined function context

7671:   Level: developer

7673:   Developer Notes:
7674:   This API is specific to only particular usage of `DM`

7676:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7678: .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7679: @*/
7680: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7681: {
7682:   Vec localX;

7685:   DMGetLocalVector(dm, &localX);
7686:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7687:   DMLocalToGlobalBegin(dm, localX, mode, X);
7688:   DMLocalToGlobalEnd(dm, localX, mode, X);
7689:   DMRestoreLocalVector(dm, &localX);
7690:   return 0;
7691: }

7693: /*@C
7694:   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.

7696:   Not collective

7698:   Input Parameters:
7699: + dm      - The `DM`
7700: . time    - The time
7701: . funcs   - The coordinate functions to evaluate, one per field
7702: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7703: - mode    - The insertion mode for values

7705:   Output Parameter:
7706: . localX - vector

7708:    Calling sequence of func:
7709: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7711: +  dim - The spatial dimension
7712: .  x   - The coordinates
7713: .  Nc  - The number of components
7714: .  u   - The output field values
7715: -  ctx - optional user-defined function context

7717:   Level: developer

7719:   Developer Notes:
7720:   This API is specific to only particular usage of `DM`

7722:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7724: .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7725: @*/
7726: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7727: {
7730:   (dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX);
7731:   return 0;
7732: }

7734: /*@C
7735:   DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.

7737:   Collective on dm

7739:   Input Parameters:
7740: + dm      - The `DM`
7741: . time    - The time
7742: . label   - The `DMLabel` selecting the portion of the mesh for projection
7743: . funcs   - The coordinate functions to evaluate, one per field
7744: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
7745: - mode    - The insertion mode for values

7747:   Output Parameter:
7748: . X - vector

7750:    Calling sequence of func:
7751: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7753: +  dim - The spatial dimension
7754: .  x   - The coordinates
7755: .  Nc  - The number of components
7756: .  u   - The output field values
7757: -  ctx - optional user-defined function context

7759:   Level: developer

7761:   Developer Notes:
7762:   This API is specific to only particular usage of `DM`

7764:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7766: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
7767: @*/
7768: 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)
7769: {
7770:   Vec localX;

7773:   DMGetLocalVector(dm, &localX);
7774:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7775:   DMLocalToGlobalBegin(dm, localX, mode, X);
7776:   DMLocalToGlobalEnd(dm, localX, mode, X);
7777:   DMRestoreLocalVector(dm, &localX);
7778:   return 0;
7779: }

7781: /*@C
7782:   DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.

7784:   Not collective

7786:   Input Parameters:
7787: + dm      - The `DM`
7788: . time    - The time
7789: . label   - The `DMLabel` selecting the portion of the mesh for projection
7790: . funcs   - The coordinate functions to evaluate, one per field
7791: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7792: - mode    - The insertion mode for values

7794:   Output Parameter:
7795: . localX - vector

7797:    Calling sequence of func:
7798: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7800: +  dim - The spatial dimension
7801: .  x   - The coordinates
7802: .  Nc  - The number of components
7803: .  u   - The output field values
7804: -  ctx - optional user-defined function context

7806:   Level: developer

7808:   Developer Notes:
7809:   This API is specific to only particular usage of `DM`

7811:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7813: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7814: @*/
7815: 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)
7816: {
7819:   (dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7820:   return 0;
7821: }

7823: /*@C
7824:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.

7826:   Not collective

7828:   Input Parameters:
7829: + dm      - The `DM`
7830: . time    - The time
7831: . localU  - The input field vector
7832: . funcs   - The functions to evaluate, one per field
7833: - mode    - The insertion mode for values

7835:   Output Parameter:
7836: . localX  - The output vector

7838:    Calling sequence of func:
7839: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7840: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7841: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7842: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7844: +  dim          - The spatial dimension
7845: .  Nf           - The number of input fields
7846: .  NfAux        - The number of input auxiliary fields
7847: .  uOff         - The offset of each field in u[]
7848: .  uOff_x       - The offset of each field in u_x[]
7849: .  u            - The field values at this point in space
7850: .  u_t          - The field time derivative at this point in space (or NULL)
7851: .  u_x          - The field derivatives at this point in space
7852: .  aOff         - The offset of each auxiliary field in u[]
7853: .  aOff_x       - The offset of each auxiliary field in u_x[]
7854: .  a            - The auxiliary field values at this point in space
7855: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7856: .  a_x          - The auxiliary field derivatives at this point in space
7857: .  t            - The current time
7858: .  x            - The coordinates of this point
7859: .  numConstants - The number of constants
7860: .  constants    - The value of each constant
7861: -  f            - The value of the function at this point in space

7863:   Note:
7864:   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
7865:   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
7866:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7867:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7869:   Level: intermediate

7871:   Developer Notes:
7872:   This API is specific to only particular usage of `DM`

7874:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7876: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7877: @*/
7878: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX)
7879: {
7883:   (dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX);
7884:   return 0;
7885: }

7887: /*@C
7888:   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.

7890:   Not collective

7892:   Input Parameters:
7893: + dm      - The `DM`
7894: . time    - The time
7895: . label   - The `DMLabel` marking the portion of the domain to output
7896: . numIds  - The number of label ids to use
7897: . ids     - The label ids to use for marking
7898: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7899: . comps   - The components to set in the output, or NULL for all components
7900: . localU  - The input field vector
7901: . funcs   - The functions to evaluate, one per field
7902: - mode    - The insertion mode for values

7904:   Output Parameter:
7905: . localX  - The output vector

7907:    Calling sequence of func:
7908: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7909: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7910: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7911: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7913: +  dim          - The spatial dimension
7914: .  Nf           - The number of input fields
7915: .  NfAux        - The number of input auxiliary fields
7916: .  uOff         - The offset of each field in u[]
7917: .  uOff_x       - The offset of each field in u_x[]
7918: .  u            - The field values at this point in space
7919: .  u_t          - The field time derivative at this point in space (or NULL)
7920: .  u_x          - The field derivatives at this point in space
7921: .  aOff         - The offset of each auxiliary field in u[]
7922: .  aOff_x       - The offset of each auxiliary field in u_x[]
7923: .  a            - The auxiliary field values at this point in space
7924: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7925: .  a_x          - The auxiliary field derivatives at this point in space
7926: .  t            - The current time
7927: .  x            - The coordinates of this point
7928: .  numConstants - The number of constants
7929: .  constants    - The value of each constant
7930: -  f            - The value of the function at this point in space

7932:   Note:
7933:   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
7934:   The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
7935:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7936:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7938:   Level: intermediate

7940:   Developer Notes:
7941:   This API is specific to only particular usage of `DM`

7943:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7945: .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7946: @*/
7947: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX)
7948: {
7952:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
7953:   return 0;
7954: }

7956: /*@C
7957:   DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.

7959:   Not collective

7961:   Input Parameters:
7962: + dm      - The `DM`
7963: . time    - The time
7964: . label   - The `DMLabel` marking the portion of the domain to output
7965: . numIds  - The number of label ids to use
7966: . ids     - The label ids to use for marking
7967: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7968: . comps   - The components to set in the output, or NULL for all components
7969: . U       - The input field vector
7970: . funcs   - The functions to evaluate, one per field
7971: - mode    - The insertion mode for values

7973:   Output Parameter:
7974: . X       - The output vector

7976:    Calling sequence of func:
7977: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7978: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7979: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7980: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7982: +  dim          - The spatial dimension
7983: .  Nf           - The number of input fields
7984: .  NfAux        - The number of input auxiliary fields
7985: .  uOff         - The offset of each field in u[]
7986: .  uOff_x       - The offset of each field in u_x[]
7987: .  u            - The field values at this point in space
7988: .  u_t          - The field time derivative at this point in space (or NULL)
7989: .  u_x          - The field derivatives at this point in space
7990: .  aOff         - The offset of each auxiliary field in u[]
7991: .  aOff_x       - The offset of each auxiliary field in u_x[]
7992: .  a            - The auxiliary field values at this point in space
7993: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7994: .  a_x          - The auxiliary field derivatives at this point in space
7995: .  t            - The current time
7996: .  x            - The coordinates of this point
7997: .  numConstants - The number of constants
7998: .  constants    - The value of each constant
7999: -  f            - The value of the function at this point in space

8001:   Note:
8002:   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8003:   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
8004:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8005:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8007:   Level: intermediate

8009:   Developer Notes:
8010:   This API is specific to only particular usage of `DM`

8012:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8014: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8015: @*/
8016: PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec X)
8017: {
8018:   DM  dmIn;
8019:   Vec localU, localX;

8022:   VecGetDM(U, &dmIn);
8023:   DMGetLocalVector(dmIn, &localU);
8024:   DMGetLocalVector(dm, &localX);
8025:   DMGlobalToLocalBegin(dmIn, U, mode, localU);
8026:   DMGlobalToLocalEnd(dmIn, U, mode, localU);
8027:   DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8028:   DMLocalToGlobalBegin(dm, localX, mode, X);
8029:   DMLocalToGlobalEnd(dm, localX, mode, X);
8030:   DMRestoreLocalVector(dm, &localX);
8031:   DMRestoreLocalVector(dmIn, &localU);
8032:   return 0;
8033: }

8035: /*@C
8036:   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.

8038:   Not collective

8040:   Input Parameters:
8041: + dm      - The `DM`
8042: . time    - The time
8043: . label   - The `DMLabel` marking the portion of the domain boundary to output
8044: . numIds  - The number of label ids to use
8045: . ids     - The label ids to use for marking
8046: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8047: . comps   - The components to set in the output, or NULL for all components
8048: . localU  - The input field vector
8049: . funcs   - The functions to evaluate, one per field
8050: - mode    - The insertion mode for values

8052:   Output Parameter:
8053: . localX  - The output vector

8055:    Calling sequence of func:
8056: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8057: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8058: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8059: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8061: +  dim          - The spatial dimension
8062: .  Nf           - The number of input fields
8063: .  NfAux        - The number of input auxiliary fields
8064: .  uOff         - The offset of each field in u[]
8065: .  uOff_x       - The offset of each field in u_x[]
8066: .  u            - The field values at this point in space
8067: .  u_t          - The field time derivative at this point in space (or NULL)
8068: .  u_x          - The field derivatives at this point in space
8069: .  aOff         - The offset of each auxiliary field in u[]
8070: .  aOff_x       - The offset of each auxiliary field in u_x[]
8071: .  a            - The auxiliary field values at this point in space
8072: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8073: .  a_x          - The auxiliary field derivatives at this point in space
8074: .  t            - The current time
8075: .  x            - The coordinates of this point
8076: .  n            - The face normal
8077: .  numConstants - The number of constants
8078: .  constants    - The value of each constant
8079: -  f            - The value of the function at this point in space

8081:   Note:
8082:   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8083:   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
8084:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8085:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8087:   Level: intermediate

8089:   Developer Notes:
8090:   This API is specific to only particular usage of `DM`

8092:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8094: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8095: @*/
8096: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX)
8097: {
8101:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8102:   return 0;
8103: }

8105: /*@C
8106:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8108:   Collective on dm

8110:   Input Parameters:
8111: + dm    - The `DM`
8112: . time  - The time
8113: . funcs - The functions to evaluate for each field component
8114: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8115: - X     - The coefficient vector u_h, a global vector

8117:   Output Parameter:
8118: . diff - The diff ||u - u_h||_2

8120:   Level: developer

8122:   Developer Notes:
8123:   This API is specific to only particular usage of `DM`

8125:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8127: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8128: @*/
8129: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8130: {
8133:   (dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff);
8134:   return 0;
8135: }

8137: /*@C
8138:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8140:   Collective on dm

8142:   Input Parameters:
8143: + dm    - The `DM`
8144: , time  - The time
8145: . funcs - The gradient functions to evaluate for each field component
8146: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8147: . X     - The coefficient vector u_h, a global vector
8148: - n     - The vector to project along

8150:   Output Parameter:
8151: . diff - The diff ||(grad u - grad u_h) . n||_2

8153:   Level: developer

8155:   Developer Notes:
8156:   This API is specific to only particular usage of `DM`

8158:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8160: .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8161: @*/
8162: 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)
8163: {
8166:   (dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff);
8167:   return 0;
8168: }

8170: /*@C
8171:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8173:   Collective on dm

8175:   Input Parameters:
8176: + dm    - The `DM`
8177: . time  - The time
8178: . funcs - The functions to evaluate for each field component
8179: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8180: - X     - The coefficient vector u_h, a global vector

8182:   Output Parameter:
8183: . diff - The array of differences, ||u^f - u^f_h||_2

8185:   Level: developer

8187:   Developer Notes:
8188:   This API is specific to only particular usage of `DM`

8190:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8192: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8193: @*/
8194: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8195: {
8198:   (dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff);
8199:   return 0;
8200: }

8202: /*@C
8203:  DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors

8205:  Not Collective

8207:  Input Parameter:
8208: .  dm    - The `DM`

8210:  Output Parameters:
8211: +  nranks - the number of neighbours
8212: -  ranks - the neighbors ranks

8214:  Note:
8215:  Do not free the array, it is freed when the `DM` is destroyed.

8217:  Level: beginner

8219:  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8220: @*/
8221: PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8222: {
8224:   (dm->ops->getneighbors)(dm, nranks, ranks);
8225:   return 0;
8226: }

8228: #include <petsc/private/matimpl.h>

8230: /*
8231:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8232:     This has be a different function because it requires DM which is not defined in the Mat library
8233: */
8234: PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8235: {
8236:   if (coloring->ctype == IS_COLORING_LOCAL) {
8237:     Vec x1local;
8238:     DM  dm;
8239:     MatGetDM(J, &dm);
8241:     DMGetLocalVector(dm, &x1local);
8242:     DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local);
8243:     DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local);
8244:     x1 = x1local;
8245:   }
8246:   MatFDColoringApply_AIJ(J, coloring, x1, sctx);
8247:   if (coloring->ctype == IS_COLORING_LOCAL) {
8248:     DM dm;
8249:     MatGetDM(J, &dm);
8250:     DMRestoreLocalVector(dm, &x1);
8251:   }
8252:   return 0;
8253: }

8255: /*@
8256:     MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring

8258:     Input Parameter:
8259: .    coloring - the `MatFDColoring` object

8261:     Developer Note:
8262:     this routine exists because the PETSc `Mat` library does not know about the `DM` objects

8264:     Level: advanced

8266: .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8267: @*/
8268: PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8269: {
8270:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8271:   return 0;
8272: }

8274: /*@
8275:     DMGetCompatibility - determine if two `DM`s are compatible

8277:     Collective

8279:     Input Parameters:
8280: +    dm1 - the first `DM`
8281: -    dm2 - the second `DM`

8283:     Output Parameters:
8284: +    compatible - whether or not the two `DM`s are compatible
8285: -    set - whether or not the compatible value was actually determined and set

8287:     Notes:
8288:     Two `DM`s are deemed compatible if they represent the same parallel decomposition
8289:     of the same topology. This implies that the section (field data) on one
8290:     "makes sense" with respect to the topology and parallel decomposition of the other.
8291:     Loosely speaking, compatible `DM`s represent the same domain and parallel
8292:     decomposition, but hold different data.

8294:     Typically, one would confirm compatibility if intending to simultaneously iterate
8295:     over a pair of vectors obtained from different `DM`s.

8297:     For example, two `DMDA` objects are compatible if they have the same local
8298:     and global sizes and the same stencil width. They can have different numbers
8299:     of degrees of freedom per node. Thus, one could use the node numbering from
8300:     either `DM` in bounds for a loop over vectors derived from either `DM`.

8302:     Consider the operation of summing data living on a 2-dof `DMDA` to data living
8303:     on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8304: .vb
8305:   ...
8306:   DMGetCompatibility(da1,da2,&compatible,&set);
8307:   if (set && compatible)  {
8308:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8309:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8310:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8311:     for (j=y; j<y+n; ++j) {
8312:       for (i=x; i<x+m, ++i) {
8313:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8314:       }
8315:     }
8316:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8317:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8318:   } else {
8319:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8320:   }
8321:   ...
8322: .ve

8324:     Checking compatibility might be expensive for a given implementation of `DM`,
8325:     or might be impossible to unambiguously confirm or deny. For this reason,
8326:     this function may decline to determine compatibility, and hence users should
8327:     always check the "set" output parameter.

8329:     A `DM` is always compatible with itself.

8331:     In the current implementation, `DM`s which live on "unequal" communicators
8332:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8333:     incompatible.

8335:     This function is labeled "Collective," as information about all subdomains
8336:     is required on each rank. However, in `DM` implementations which store all this
8337:     information locally, this function may be merely "Logically Collective".

8339:     Developer Note:
8340:     Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8341:     iff B is compatible with A. Thus, this function checks the implementations
8342:     of both dm and dmc (if they are of different types), attempting to determine
8343:     compatibility. It is left to `DM` implementers to ensure that symmetry is
8344:     preserved. The simplest way to do this is, when implementing type-specific
8345:     logic for this function, is to check for existing logic in the implementation
8346:     of other `DM` types and let *set = PETSC_FALSE if found.

8348:     Level: advanced

8350: .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8351: @*/
8352: PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8353: {
8354:   PetscMPIInt compareResult;
8355:   DMType      type, type2;
8356:   PetscBool   sameType;


8361:   /* Declare a DM compatible with itself */
8362:   if (dm1 == dm2) {
8363:     *set        = PETSC_TRUE;
8364:     *compatible = PETSC_TRUE;
8365:     return 0;
8366:   }

8368:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8369:      communicator. Note that this does not preclude compatibility with
8370:      DMs living on "congruent" or "similar" communicators, but this must be
8371:      determined by the implementation-specific logic */
8372:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult);
8373:   if (compareResult == MPI_UNEQUAL) {
8374:     *set        = PETSC_TRUE;
8375:     *compatible = PETSC_FALSE;
8376:     return 0;
8377:   }

8379:   /* Pass to the implementation-specific routine, if one exists. */
8380:   if (dm1->ops->getcompatibility) {
8381:     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8382:     if (*set) return 0;
8383:   }

8385:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8386:      with an implementation of this function from dm2 */
8387:   DMGetType(dm1, &type);
8388:   DMGetType(dm2, &type2);
8389:   PetscStrcmp(type, type2, &sameType);
8390:   if (!sameType && dm2->ops->getcompatibility) {
8391:     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8392:   } else {
8393:     *set = PETSC_FALSE;
8394:   }
8395:   return 0;
8396: }

8398: /*@C
8399:   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.

8401:   Logically Collective on dm

8403:   Input Parameters:
8404: + DM - the `DM`
8405: . f - the monitor function
8406: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8407: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

8409:   Options Database Keys:
8410: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8411:                             does not cancel those set via the options database.

8413:   Note:
8414:   Several different monitoring routines may be set by calling
8415:   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8416:   order in which they were set.

8418:   Fortran Note:
8419:   Only a single monitor function can be set for each `DM` object

8421:   Developer Note:
8422:   This API has a generic name but seems specific to a very particular aspect of the use of `DM`

8424:   Level: intermediate

8426: .seealso: `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8427: @*/
8428: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8429: {
8430:   PetscInt m;

8433:   for (m = 0; m < dm->numbermonitors; ++m) {
8434:     PetscBool identical;

8436:     PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8437:     if (identical) return 0;
8438:   }
8440:   dm->monitor[dm->numbermonitors]          = f;
8441:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8442:   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8443:   return 0;
8444: }

8446: /*@
8447:   DMMonitorCancel - Clears all the monitor functions for a `DM` object.

8449:   Logically Collective on dm

8451:   Input Parameter:
8452: . dm - the DM

8454:   Options Database Key:
8455: . -dm_monitor_cancel - cancels all monitors that have been hardwired
8456:   into a code by calls to `DMonitorSet()`, but does not cancel those
8457:   set via the options database

8459:   Note:
8460:   There is no way to clear one specific monitor from a `DM` object.

8462:   Level: intermediate

8464: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8465: @*/
8466: PetscErrorCode DMMonitorCancel(DM dm)
8467: {
8468:   PetscInt m;

8471:   for (m = 0; m < dm->numbermonitors; ++m) {
8472:     if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
8473:   }
8474:   dm->numbermonitors = 0;
8475:   return 0;
8476: }

8478: /*@C
8479:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

8481:   Collective on dm

8483:   Input Parameters:
8484: + dm   - `DM` object you wish to monitor
8485: . name - the monitor type one is seeking
8486: . help - message indicating what monitoring is done
8487: . manual - manual page for the monitor
8488: . monitor - the monitor function
8489: - 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

8491:   Output Parameter:
8492: . flg - Flag set if the monitor was created

8494:   Level: developer

8496: .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8497:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8498:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8499:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8500:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8501:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8502:           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8503: @*/
8504: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8505: {
8506:   PetscViewer       viewer;
8507:   PetscViewerFormat format;

8510:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg);
8511:   if (*flg) {
8512:     PetscViewerAndFormat *vf;

8514:     PetscViewerAndFormatCreate(viewer, format, &vf);
8515:     PetscObjectDereference((PetscObject)viewer);
8516:     if (monitorsetup) (*monitorsetup)(dm, vf);
8517:     DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy);
8518:   }
8519:   return 0;
8520: }

8522: /*@
8523:    DMMonitor - runs the user provided monitor routines, if they exist

8525:    Collective on dm

8527:    Input Parameters:
8528: .  dm - The `DM`

8530:    Level: developer

8532:    Question:
8533:    Note should indicate when during the life of the `DM` the monitor is run. It appears to be related to the discretization process seems rather specialized
8534:    since some `DM` have no concept of discretization

8536: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8537: @*/
8538: PetscErrorCode DMMonitor(DM dm)
8539: {
8540:   PetscInt m;

8542:   if (!dm) return 0;
8544:   for (m = 0; m < dm->numbermonitors; ++m) (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8545:   return 0;
8546: }

8548: /*@
8549:   DMComputeError - Computes the error assuming the user has provided the exact solution functions

8551:   Collective on dm

8553:   Input Parameters:
8554: + dm     - The `DM`
8555: - sol    - The solution vector

8557:   Input/Output Parameter:
8558: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
8559:            contains the error in each field

8561:   Output Parameter:
8562: . errorVec - A vector to hold the cellwise error (may be NULL)

8564:   Note:
8565:   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.

8567:   Level: developer

8569: .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8570: @*/
8571: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8572: {
8573:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8574:   void    **ctxs;
8575:   PetscReal time;
8576:   PetscInt  Nf, f, Nds, s;

8578:   DMGetNumFields(dm, &Nf);
8579:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
8580:   DMGetNumDS(dm, &Nds);
8581:   for (s = 0; s < Nds; ++s) {
8582:     PetscDS         ds;
8583:     DMLabel         label;
8584:     IS              fieldIS;
8585:     const PetscInt *fields;
8586:     PetscInt        dsNf;

8588:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
8589:     PetscDSGetNumFields(ds, &dsNf);
8590:     if (fieldIS) ISGetIndices(fieldIS, &fields);
8591:     for (f = 0; f < dsNf; ++f) {
8592:       const PetscInt field = fields[f];
8593:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
8594:     }
8595:     if (fieldIS) ISRestoreIndices(fieldIS, &fields);
8596:   }
8598:   DMGetOutputSequenceNumber(dm, NULL, &time);
8599:   if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
8600:   if (errorVec) {
8601:     DM             edm;
8602:     DMPolytopeType ct;
8603:     PetscBool      simplex;
8604:     PetscInt       dim, cStart, Nf;

8606:     DMClone(dm, &edm);
8607:     DMGetDimension(edm, &dim);
8608:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
8609:     DMPlexGetCellType(dm, cStart, &ct);
8610:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8611:     DMGetNumFields(dm, &Nf);
8612:     for (f = 0; f < Nf; ++f) {
8613:       PetscFE         fe, efe;
8614:       PetscQuadrature q;
8615:       const char     *name;

8617:       DMGetField(dm, f, NULL, (PetscObject *)&fe);
8618:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
8619:       PetscObjectGetName((PetscObject)fe, &name);
8620:       PetscObjectSetName((PetscObject)efe, name);
8621:       PetscFEGetQuadrature(fe, &q);
8622:       PetscFESetQuadrature(efe, q);
8623:       DMSetField(edm, f, NULL, (PetscObject)efe);
8624:       PetscFEDestroy(&efe);
8625:     }
8626:     DMCreateDS(edm);

8628:     DMCreateGlobalVector(edm, errorVec);
8629:     PetscObjectSetName((PetscObject)*errorVec, "Error");
8630:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
8631:     DMDestroy(&edm);
8632:   }
8633:   PetscFree2(exactSol, ctxs);
8634:   return 0;
8635: }

8637: /*@
8638:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`

8640:   Not collective

8642:   Input Parameter:
8643: . dm     - The `DM`

8645:   Output Parameter:
8646: . numAux - The number of auxiliary data vectors

8648:   Level: advanced

8650: .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8651: @*/
8652: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8653: {
8655:   PetscHMapAuxGetSize(dm->auxData, numAux);
8656:   return 0;
8657: }

8659: /*@
8660:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part

8662:   Not collective

8664:   Input Parameters:
8665: + dm     - The `DM`
8666: . label  - The `DMLabel`
8667: . value  - The label value indicating the region
8668: - part   - The equation part, or 0 if unused

8670:   Output Parameter:
8671: . aux    - The `Vec` holding auxiliary field data

8673:   Note:
8674:   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.

8676:   Level: advanced

8678: .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8679: @*/
8680: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8681: {
8682:   PetscHashAuxKey key, wild = {NULL, 0, 0};
8683:   PetscBool       has;

8687:   key.label = label;
8688:   key.value = value;
8689:   key.part  = part;
8690:   PetscHMapAuxHas(dm->auxData, key, &has);
8691:   if (has) PetscHMapAuxGet(dm->auxData, key, aux);
8692:   else PetscHMapAuxGet(dm->auxData, wild, aux);
8693:   return 0;
8694: }

8696: /*@
8697:   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part

8699:   Not collective because auxiliary vectors are not parallel

8701:   Input Parameters:
8702: + dm     - The `DM`
8703: . label  - The `DMLabel`
8704: . value  - The label value indicating the region
8705: . part   - The equation part, or 0 if unused
8706: - aux    - The `Vec` holding auxiliary field data

8708:   Level: advanced

8710: .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8711: @*/
8712: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8713: {
8714:   Vec             old;
8715:   PetscHashAuxKey key;

8719:   key.label = label;
8720:   key.value = value;
8721:   key.part  = part;
8722:   PetscHMapAuxGet(dm->auxData, key, &old);
8723:   PetscObjectReference((PetscObject)aux);
8724:   PetscObjectDereference((PetscObject)old);
8725:   if (!aux) PetscHMapAuxDel(dm->auxData, key);
8726:   else PetscHMapAuxSet(dm->auxData, key, aux);
8727:   return 0;
8728: }

8730: /*@C
8731:   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`

8733:   Not collective

8735:   Input Parameter:
8736: . dm      - The `DM`

8738:   Output Parameters:
8739: + labels  - The `DMLabel`s for each `Vec`
8740: . values  - The label values for each `Vec`
8741: - parts   - The equation parts for each `Vec`

8743:   Note:
8744:   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.

8746:   Level: advanced

8748: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
8749: @*/
8750: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
8751: {
8752:   PetscHashAuxKey *keys;
8753:   PetscInt         n, i, off = 0;

8759:   DMGetNumAuxiliaryVec(dm, &n);
8760:   PetscMalloc1(n, &keys);
8761:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
8762:   for (i = 0; i < n; ++i) {
8763:     labels[i] = keys[i].label;
8764:     values[i] = keys[i].value;
8765:     parts[i]  = keys[i].part;
8766:   }
8767:   PetscFree(keys);
8768:   return 0;
8769: }

8771: /*@
8772:   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`

8774:   Not collective

8776:   Input Parameter:
8777: . dm    - The `DM`

8779:   Output Parameter:
8780: . dmNew - The new `DM`, now with the same auxiliary data

8782:   Level: advanced

8784:   Note:
8785:   This is a shallow copy of the auxiliary vectors

8787: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8788: @*/
8789: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
8790: {
8792:   PetscHMapAuxDestroy(&dmNew->auxData);
8793:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
8794:   return 0;
8795: }

8797: /*@C
8798:   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement

8800:   Not collective

8802:   Input Parameters:
8803: + ct         - The `DMPolytopeType`
8804: . sourceCone - The source arrangement of faces
8805: - targetCone - The target arrangement of faces

8807:   Output Parameters:
8808: + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
8809: - found - Flag indicating that a suitable orientation was found

8811:   Level: advanced

8813:   Note:
8814:   An arrangement is a face order combined with an orientation for each face

8816:   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8817:   that labels each arrangement (face ordering plus orientation for each face).

8819:   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement

8821: .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
8822: @*/
8823: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
8824: {
8825:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
8826:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8827:   PetscInt       o, c;

8829:   if (!nO) {
8830:     *ornt  = 0;
8831:     *found = PETSC_TRUE;
8832:     return 0;
8833:   }
8834:   for (o = -nO; o < nO; ++o) {
8835:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

8837:     for (c = 0; c < cS; ++c)
8838:       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
8839:     if (c == cS) {
8840:       *ornt = o;
8841:       break;
8842:     }
8843:   }
8844:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8845:   return 0;
8846: }

8848: /*@C
8849:   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement

8851:   Not collective

8853:   Input Parameters:
8854: + ct         - The `DMPolytopeType`
8855: . sourceCone - The source arrangement of faces
8856: - targetCone - The target arrangement of faces

8858:   Output Parameters:
8859: . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement

8861:   Level: advanced

8863:   Note:
8864:   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.

8866:   Developer Note:
8867:   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found

8869: .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
8870: @*/
8871: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8872: {
8873:   PetscBool found;

8875:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
8877:   return 0;
8878: }

8880: /*@C
8881:   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement

8883:   Not collective

8885:   Input Parameters:
8886: + ct         - The `DMPolytopeType`
8887: . sourceVert - The source arrangement of vertices
8888: - targetVert - The target arrangement of vertices

8890:   Output Parameters:
8891: + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
8892: - found - Flag indicating that a suitable orientation was found

8894:   Level: advanced

8896:   Note:
8897:   An arrangement is a vertex order

8899:   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8900:   that labels each arrangement (vertex ordering).

8902:   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement

8904: .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
8905: @*/
8906: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
8907: {
8908:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
8909:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8910:   PetscInt       o, c;

8912:   if (!nO) {
8913:     *ornt  = 0;
8914:     *found = PETSC_TRUE;
8915:     return 0;
8916:   }
8917:   for (o = -nO; o < nO; ++o) {
8918:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

8920:     for (c = 0; c < cS; ++c)
8921:       if (sourceVert[arr[c]] != targetVert[c]) break;
8922:     if (c == cS) {
8923:       *ornt = o;
8924:       break;
8925:     }
8926:   }
8927:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8928:   return 0;
8929: }

8931: /*@C
8932:   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement

8934:   Not collective

8936:   Input Parameters:
8937: + ct         - The `DMPolytopeType`
8938: . sourceCone - The source arrangement of vertices
8939: - targetCone - The target arrangement of vertices

8941:   Output Parameters:
8942: . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement

8944:   Level: advanced

8946:   Note:
8947:   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.

8949:   Developer Note:
8950:   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found

8952: .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
8953: @*/
8954: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8955: {
8956:   PetscBool found;

8958:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
8960:   return 0;
8961: }

8963: /*@C
8964:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

8966:   Not collective

8968:   Input Parameters:
8969: + ct    - The `DMPolytopeType`
8970: - point - Coordinates of the point

8972:   Output Parameters:
8973: . inside  - Flag indicating whether the point is inside the reference cell of given type

8975:   Level: advanced

8977: .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
8978: @*/
8979: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
8980: {
8981:   PetscReal sum = 0.0;
8982:   PetscInt  d;

8984:   *inside = PETSC_TRUE;
8985:   switch (ct) {
8986:   case DM_POLYTOPE_TRIANGLE:
8987:   case DM_POLYTOPE_TETRAHEDRON:
8988:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
8989:       if (point[d] < -1.0) {
8990:         *inside = PETSC_FALSE;
8991:         break;
8992:       }
8993:       sum += point[d];
8994:     }
8995:     if (sum > PETSC_SMALL) {
8996:       *inside = PETSC_FALSE;
8997:       break;
8998:     }
8999:     break;
9000:   case DM_POLYTOPE_QUADRILATERAL:
9001:   case DM_POLYTOPE_HEXAHEDRON:
9002:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9003:       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9004:         *inside = PETSC_FALSE;
9005:         break;
9006:       }
9007:     break;
9008:   default:
9009:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9010:   }
9011:   return 0;
9012: }