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

101:   *dm = v;
102:   return 0;
103: }

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

108:   Collective

110:   Input Parameter:
111: . dm - The original `DM` object

113:   Output Parameter:
114: . newdm  - The new `DM` object

116:   Level: beginner

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

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

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

127: .seealso: `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMSetType()`, `DMConvert()`

129: @*/
130: PetscErrorCode DMClone(DM dm, DM *newdm)
131: {
132:   PetscSF  sf;
133:   Vec      coords;
134:   void    *ctx;
135:   PetscInt dim, cdim, i;

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

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

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

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

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

209:    Logically Collective on da

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

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

218:    Level: intermediate

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

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

234:    Logically Collective on da

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

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

242:    Level: intermediate

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

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

256:   Not collective

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

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

264:   Level: intermediate

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

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

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

282:   Not collective

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

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

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

293:   Level: developer

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

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

308:    Logically Collective on dm

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

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

317:    Level: intermediate

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

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

332:    Logically Collective on dm

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

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

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

343:    Level: intermediate

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

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

358:    Logically Collective on dm

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

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

367:    Level: intermediate

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

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

382:    Logically Collective on dm

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

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

390:    Level: intermediate

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

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

404:   Not collective

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

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

412:   Level: intermediate

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

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

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

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

433:   Not collective

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

439:   Level: developer

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

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

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

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

461:    Logically Collective on dm

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

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

471:    Level: advanced

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

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

488:    Logically Collective on dm

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

494:    Notes:
495:    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.
496:    A hyphen (-) must NOT be given at the beginning of the prefix name.
497:    The first character of all runtime options is AUTOMATICALLY the hyphen.

499:    Level: advanced

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

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

514:    Not Collective

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

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

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

526:    Level: advanced

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

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

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

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

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

564: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
565: {
566:   DMLabelLink next = dm->labels;

568:   /* destroy the labels */
569:   while (next) {
570:     DMLabelLink tmp = next->next;

572:     if (next->label == dm->depthLabel) dm->depthLabel = NULL;
573:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
574:     DMLabelDestroy(&next->label);
575:     PetscFree(next);
576:     next = tmp;
577:   }
578:   dm->labels = NULL;
579:   return 0;
580: }

582: PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
583: {
584:   c->dim = PETSC_DEFAULT;
585:   DMDestroy(&c->dm);
586:   VecDestroy(&c->x);
587:   VecDestroy(&c->xl);
588:   DMFieldDestroy(&c->field);
589:   return 0;
590: }

592: /*@C
593:     DMDestroy - Destroys a `DM`.

595:     Collective on dm

597:     Input Parameter:
598: .   dm - the `DM` object to destroy

600:     Level: developer

602: .seealso: `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`

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

610:   if (!*dm) return 0;

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

623:   DMClearGlobalVectors(*dm);
624:   DMClearLocalVectors(*dm);

626:   nnext              = (*dm)->namedglobal;
627:   (*dm)->namedglobal = NULL;
628:   for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named vectors */
629:     nnext = nlink->next;
631:     PetscFree(nlink->name);
632:     VecDestroy(&nlink->X);
633:     PetscFree(nlink);
634:   }
635:   nnext             = (*dm)->namedlocal;
636:   (*dm)->namedlocal = NULL;
637:   for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named local vectors */
638:     nnext = nlink->next;
640:     PetscFree(nlink->name);
641:     VecDestroy(&nlink->X);
642:     PetscFree(nlink);
643:   }

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

707:       next = b->next;
708:       PetscFree(b);
709:     }
710:   }

712:   PetscObjectDestroy(&(*dm)->dmksp);
713:   PetscObjectDestroy(&(*dm)->dmsnes);
714:   PetscObjectDestroy(&(*dm)->dmts);

716:   if ((*dm)->ctx && (*dm)->ctxdestroy) (*(*dm)->ctxdestroy)(&(*dm)->ctx);
717:   MatFDColoringDestroy(&(*dm)->fd);
718:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
719:   PetscFree((*dm)->vectype);
720:   PetscFree((*dm)->mattype);

722:   PetscSectionDestroy(&(*dm)->localSection);
723:   PetscSectionDestroy(&(*dm)->globalSection);
724:   PetscLayoutDestroy(&(*dm)->map);
725:   PetscSectionDestroy(&(*dm)->defaultConstraint.section);
726:   MatDestroy(&(*dm)->defaultConstraint.mat);
727:   PetscSFDestroy(&(*dm)->sf);
728:   PetscSFDestroy(&(*dm)->sectionSF);
729:   if ((*dm)->useNatural) {
730:     if ((*dm)->sfNatural) PetscSFDestroy(&(*dm)->sfNatural);
731:     PetscObjectDereference((PetscObject)(*dm)->sfMigration);
732:   }
733:   {
734:     Vec     *auxData;
735:     PetscInt n, i, off = 0;

737:     PetscHMapAuxGetSize((*dm)->auxData, &n);
738:     PetscMalloc1(n, &auxData);
739:     PetscHMapAuxGetVals((*dm)->auxData, &off, auxData);
740:     for (i = 0; i < n; ++i) VecDestroy(&auxData[i]);
741:     PetscFree(auxData);
742:     PetscHMapAuxDestroy(&(*dm)->auxData);
743:   }
744:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) DMSetFineDM((*dm)->coarseMesh, NULL);

746:   DMDestroy(&(*dm)->coarseMesh);
747:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) DMSetCoarseDM((*dm)->fineMesh, NULL);
748:   DMDestroy(&(*dm)->fineMesh);
749:   PetscFree((*dm)->Lstart);
750:   PetscFree((*dm)->L);
751:   PetscFree((*dm)->maxCell);
752:   DMDestroyCoordinates_Private(&(*dm)->coordinates[0]);
753:   DMDestroyCoordinates_Private(&(*dm)->coordinates[1]);
754:   if ((*dm)->transformDestroy) (*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);
755:   DMDestroy(&(*dm)->transformDM);
756:   VecDestroy(&(*dm)->transform);

758:   DMClearDS(*dm);
759:   DMDestroy(&(*dm)->dmBC);
760:   /* if memory was published with SAWs then destroy it */
761:   PetscObjectSAWsViewOff((PetscObject)*dm);

763:   if ((*dm)->ops->destroy) (*(*dm)->ops->destroy)(*dm);
764:   DMMonitorCancel(*dm);
765: #ifdef PETSC_HAVE_LIBCEED
766:   CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
767:   CeedDestroy(&(*dm)->ceed);
768: #endif
769:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
770:   PetscHeaderDestroy(dm);
771:   return 0;
772: }

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

777:     Collective on dm

779:     Input Parameter:
780: .   dm - the `DM` object to setup

782:     Level: intermediate

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

787: .seealso: `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`

789: @*/
790: PetscErrorCode DMSetUp(DM dm)
791: {
793:   if (dm->setupcalled) return 0;
794:   PetscTryTypeMethod(dm, setup);
795:   dm->setupcalled = PETSC_TRUE;
796:   return 0;
797: }

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

802:     Collective on dm

804:     Input Parameter:
805: .   dm - the `DM` object to set options for

807:     Options Database:
808: +   -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
809: .   -dm_vec_type <type>  - type of vector to create inside `DM`
810: .   -dm_mat_type <type>  - type of matrix to create inside `DM`
811: .   -dm_is_coloring_type - <global or local>
812: -   -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`

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

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

860:     Level: intermediate

862: .seealso: `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
863:          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
864:          `DMSetOptionsPrefix()`, `DM`, `DMType`, `DMPLEX`, `DMDA`

866: @*/
867: PetscErrorCode DMSetFromOptions(DM dm)
868: {
869:   char      typeName[256];
870:   PetscBool flg;

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

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

894:    Collective on dm

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

901:    Level: intermediate

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

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

915: /*@C
916:     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
917:     save the `DM` in a binary file to be loaded later or create a visualization of the `DM`

919:     Collective on dm

921:     Input Parameters:
922: +   dm - the `DM` object to view
923: -   v - the viewer

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

930:     Level: beginner

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

934: @*/
935: PetscErrorCode DMView(DM dm, PetscViewer v)
936: {
937:   PetscBool         isbinary;
938:   PetscMPIInt       size;
939:   PetscViewerFormat format;

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

954:   PetscViewerGetFormat(v, &format);
955:   MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
956:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return 0;
957:   PetscObjectPrintClassNamePrefixType((PetscObject)dm, v);
958:   PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary);
959:   if (isbinary) {
960:     PetscInt classid = DM_FILE_CLASSID;
961:     char     type[256];

963:     PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT);
964:     PetscStrncpy(type, ((PetscObject)dm)->type_name, 256);
965:     PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR);
966:   }
967:   PetscTryTypeMethod(dm, view, v);
968:   return 0;
969: }

971: /*@
972:     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,
973:     that is it has no ghost locations.

975:     Collective on dm

977:     Input Parameter:
978: .   dm - the `DM` object

980:     Output Parameter:
981: .   vec - the global vector

983:     Level: beginner

985: .seealso: `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
986:          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`

988: @*/
989: PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
990: {
993:   PetscUseTypeMethod(dm, createglobalvector, vec);
994:   if (PetscDefined(USE_DEBUG)) {
995:     DM vdm;

997:     VecGetDM(*vec, &vdm);
999:   }
1000:   return 0;
1001: }

1003: /*@
1004:     DMCreateLocalVector - Creates a local vector from a `DM` object.

1006:     Not Collective

1008:     Input Parameter:
1009: .   dm - the `DM` object

1011:     Output Parameter:
1012: .   vec - the local vector

1014:     Level: beginner

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

1019:  .seealso: `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1020:          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`

1022: @*/
1023: PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1024: {
1027:   PetscUseTypeMethod(dm, createlocalvector, vec);
1028:   if (PetscDefined(USE_DEBUG)) {
1029:     DM vdm;

1031:     VecGetDM(*vec, &vdm);
1033:   }
1034:   return 0;
1035: }

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

1040:    Collective on dm

1042:    Input Parameter:
1043: .  dm - the `DM` that provides the mapping

1045:    Output Parameter:
1046: .  ltog - the mapping

1048:    Level: advanced

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

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

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

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

1067:   if (!dm->ltogmap) {
1068:     PetscSection section, sectionGlobal;

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

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

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

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

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

1129:    Not Collective

1131:    Input Parameter:
1132: .  dm - the `DM` with block structure

1134:    Output Parameter:
1135: .  bs - the block size, 1 implies no exploitable block structure

1137:    Level: intermediate

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

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

1145: .seealso: `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1146: @*/
1147: PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1148: {
1152:   *bs = dm->bs;
1153:   return 0;
1154: }

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

1160:     Collective on dmc

1162:     Input Parameters:
1163: +   dmc - the `DM` object
1164: -   dmf - the second, finer `DM` object

1166:     Output Parameters:
1167: +  mat - the interpolation
1168: -  vec - the scaling (optional), see `DMCreateInterpolationScale()`

1170:     Level: developer

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

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

1179: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`

1181: @*/
1182: PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1183: {
1187:   PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0);
1188:   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1189:   PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0);
1190:   return 0;
1191: }

1193: /*@
1194:     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`.
1195:     xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) restriction. In other words xcoarse is the coarse
1196:     representation of xfine.

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

1203:   Output Parameter:
1204: .    scale - the scaled vector

1206:   Level: advanced

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

1212: .seealso: `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, DMCreateRestriction()`, `DMCreateGlobalVector()`

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

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

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

1247:     Collective on dmc

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

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

1256:     Level: developer

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

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

1300: @*/
1301: PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1302: {
1306:   PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0);
1307:   PetscUseTypeMethod(dac, createinjection, daf, mat);
1308:   PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0);
1309:   return 0;
1310: }

1312: /*@
1313:   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
1314:   a Galerkin finite element model on the `DM`

1316:   Collective on dac

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

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

1325:   Level: developer

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

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

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

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

1348:   Collective on dm

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

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

1356:   Level: developer

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

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

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

1375:     Collective on dm

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

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

1384:     Notes:
1385:     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
1386:     matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).

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

1390:     Level: developer

1392: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`

1394: @*/
1395: PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1396: {
1399:   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1400:   return 0;
1401: }

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

1406:     Collective on dm

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

1411:     Output Parameter:
1412: .   mat - the empty Jacobian

1414:     Level: beginner

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

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

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

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

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

1432: .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`

1434: @*/
1435: PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1436: {
1439:   MatInitializePackage();
1440:   PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0);
1441:   PetscUseTypeMethod(dm, creatematrix, mat);
1442:   if (PetscDefined(USE_DEBUG)) {
1443:     DM mdm;

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

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

1474: /*@
1475:   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and `ISLocalToGlobalMapping` will be
1476:   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
1477:   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` will be used.

1479:   Logically Collective on dm

1481:   Input Parameters:
1482: + dm - the `DM`
1483: - skip - `PETSC_TRUE` to skip preallocation

1485:   Level: developer

1487: .seealso: `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1488: @*/
1489: PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1490: {
1492:   dm->prealloc_skip = skip;
1493:   return 0;
1494: }

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

1500:   Logically Collective on dm

1502:   Input Parameters:
1503: + dm - the `DM`
1504: - only - `PETSC_TRUE` if only want preallocation

1506:   Level: developer

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

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

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

1524:   Logically Collective on dm

1526:   Input Parameters:
1527: + dm - the `DM`
1528: - only - `PETSC_TRUE` if you only want matrix stucture

1530:   Level: developer

1532: .seealso: `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1533: @*/
1534: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1535: {
1537:   dm->structure_only = only;
1538:   return 0;
1539: }

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

1544:   Not Collective

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

1551:   Output Parameter:
1552: . array - the work array

1554:   Level: developer

1556:   Note:
1557:   A `DM` may stash the array between instantations so using this routine may be more efficient than calling `PetscMalloc()`

1559:   The array may contain nonzero values

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

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

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

1595:   Not Collective

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

1602:   Output Parameter:
1603: . array - the work array

1605:   Level: developer

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

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

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

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

1634:   Logically collective on dm

1636:   Input Parameters:
1637: + dm     - The `DM`
1638: . field  - The field number for the nullspace
1639: - nullsp - A callback to create the nullspace

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

1650:   Level: intermediate

1652:   Fortran Notes:
1653:   This function is not available from Fortran.

1655: .seealso: `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1656: @*/
1657: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1658: {
1661:   dm->nullspaceConstructors[field] = nullsp;
1662:   return 0;
1663: }

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

1668:   Not collective

1670:   Input Parameters:
1671: + dm     - The `DM`
1672: - field  - The field number for the nullspace

1674:   Output Parameter:
1675: . nullsp - A callback to create the nullspace

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

1686:   Fortran Note:
1687:   This function is not available from Fortran.

1689:    Level: intermediate

1691: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1692: @*/
1693: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1694: {
1698:   *nullsp = dm->nullspaceConstructors[field];
1699:   return 0;
1700: }

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

1705:   Logically collective on dm

1707:   Input Parameters:
1708: + dm     - The `DM`
1709: . field  - The field number for the nullspace
1710: - nullsp - A callback to create the near-nullspace

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

1721:   Fortran Note:
1722:   This function is not available from Fortran.

1724:    Level: intermediate

1726: .seealso: `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1727:           `MatNullSpace`
1728: @*/
1729: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1730: {
1733:   dm->nearnullspaceConstructors[field] = nullsp;
1734:   return 0;
1735: }

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

1740:   Not collective

1742:   Input Parameters:
1743: + dm     - The `DM`
1744: - field  - The field number for the nullspace

1746:   Output Parameter:
1747: . nullsp - A callback to create the near-nullspace

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

1758:   Fortran Note:
1759:   This function is not available from Fortran.

1761:    Level: intermediate

1763: .seealso: `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1764:           `MatNullSpace`, `DMCreateSuperDM()`
1765: @*/
1766: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *))
1767: {
1771:   *nullsp = dm->nearnullspaceConstructors[field];
1772:   return 0;
1773: }

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

1778:   Not collective

1780:   Input Parameter:
1781: . dm - the `DM` object

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

1788:   Level: intermediate

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

1795:   Fortran Note:
1796:   Not available in Fortran.

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

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

1810:   if (numFields) {
1812:     *numFields = 0;
1813:   }
1814:   if (fieldNames) {
1816:     *fieldNames = NULL;
1817:   }
1818:   if (fields) {
1820:     *fields = NULL;
1821:   }
1822:   DMGetLocalSection(dm, &section);
1823:   if (section) {
1824:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1825:     PetscInt  nF, f, pStart, pEnd, p;

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

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

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

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

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

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

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

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

1907:   Not collective

1909:   Input Parameter:
1910: . dm - the `DM` object

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

1918:   Level: intermediate

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

1925:   Fortran Note:
1926:   Not available in Fortran.

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

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

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

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

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

1991:   Not collective

1993:   Input Parameters:
1994: + dm        - The `DM `object
1995: . numFields - The number of fields to select
1996: - fields    - The field numbers of the selected fields

1998:   Output Parameters:
1999: + is - The global indices for all the degrees of freedom in the new sub `DM`
2000: - subdm - The `DM` for the subproblem

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

2005:   Level: intermediate

2007: .seealso: `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `DM`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2008: @*/
2009: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2010: {
2015:   PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2016:   return 0;
2017: }

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

2022:   Not collective

2024:   Input Parameters:
2025: + dms - The `DM` objects
2026: - n - The number of `DM`s

2028:   Output Parameters:
2029: + is - The global indices for each of subproblem within the super `DM`, or NULL
2030: - superdm - The `DM` for the superproblem

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

2035:   Level: intermediate

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

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

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

2062:   Not collective

2064:   Input Parameter:
2065: . dm - the `DM` object

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

2074:   Level: intermediate

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

2081:   Questions:
2082:   The dmlist is for the inner subdomains or the outer subdomains or all subdomains?

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

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

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

2137:   Not collective

2139:   Input Parameters:
2140: + dm - the `DM` object
2141: . n  - the number of subdomain scatters
2142: - subdms - the local subdomains

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

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

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

2158:   Level: developer

2160: .seealso: `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2161: @*/
2162: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **gscat)
2163: {
2166:   PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2167:   return 0;
2168: }

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

2173:   Collective on dm

2175:   Input Parameters:
2176: + dm   - the `DM` object
2177: - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)

2179:   Output Parameter:
2180: . dmf - the refined `D`M, or NULL

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

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

2188:   Level: developer

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

2197:   PetscLogEventBegin(DM_Refine, dm, 0, 0, 0);
2198:   PetscUseTypeMethod(dm, refine, comm, dmf);
2199:   if (*dmf) {
2200:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

2204:     (*dmf)->ctx       = dm->ctx;
2205:     (*dmf)->leveldown = dm->leveldown;
2206:     (*dmf)->levelup   = dm->levelup + 1;

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

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

2220:    Logically Collective on coarse

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

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

2231: +  coarse - coarse level `DM`
2232: .  fine - fine level `DM` to interpolate problem to
2233: -  ctx - optional user-defined function context

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

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

2243:    Level: advanced

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

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

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

2253:    Fortran Note:
2254:    This function is not available from Fortran.

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

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

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

2279:    Logically Collective on coarse

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

2287:    Level: advanced

2289:    Note:
2290:    This function does nothing if the hook is not in the list.

2292:    Fortran Note:
2293:    This function is not available from Fortran.

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

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

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

2316:    Collective if any hooks are

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

2323:    Level: developer

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

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

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

2341: /*@
2342:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

2344:    Collective on dm

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

2354:    Output Parameter:
2355: .  fineSol - the interpolation of coarseSol to the fine mesh

2357:    Level: developer

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

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

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


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

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

2391:     Not Collective

2393:     Input Parameter:
2394: .   dm - the `DM` object

2396:     Output Parameter:
2397: .   level - number of refinements

2399:     Level: developer

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

2404: .seealso: `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

2406: @*/
2407: PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2408: {
2410:   *level = dm->levelup;
2411:   return 0;
2412: }

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

2417:     Not Collective

2419:     Input Parameters:
2420: +   dm - the `DM` object
2421: -   level - number of refinements

2423:     Level: advanced

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

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

2430: .seealso: `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

2432: @*/
2433: PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2434: {
2436:   dm->levelup = level;
2437:   return 0;
2438: }

2440: /*@
2441:   DMExtrude - Extrude a `DM` object from a surface

2443:   Collective on dm

2445:   Input Parameters:
2446: + dm     - the `DM` object
2447: - layers - the number of extruded cell layers

2449:   Output Parameter:
2450: . dme - the extruded `DM`, or NULL

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

2455:   Level: developer

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

2472: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2473: {
2476:   *tdm = dm->transformDM;
2477:   return 0;
2478: }

2480: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2481: {
2484:   *tv = dm->transform;
2485:   return 0;
2486: }

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

2491:   Input Parameter:
2492: . dm - The DM

2494:   Output Parameter:
2495: . flg - PETSC_TRUE if a basis transformation should be done

2497:   Level: developer

2499: .seealso: `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2500: @*/
2501: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2502: {
2503:   Vec tv;

2507:   DMGetBasisTransformVec_Internal(dm, &tv);
2508:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2509:   return 0;
2510: }

2512: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2513: {
2514:   PetscSection s, ts;
2515:   PetscScalar *ta;
2516:   PetscInt     cdim, pStart, pEnd, p, Nf, f, Nc, dof;

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

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

2559: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2560: {
2563:   newdm->transformCtx       = dm->transformCtx;
2564:   newdm->transformSetUp     = dm->transformSetUp;
2565:   newdm->transformDestroy   = NULL;
2566:   newdm->transformGetMatrix = dm->transformGetMatrix;
2567:   if (newdm->transformSetUp) DMConstructBasisTransform_Internal(newdm);
2568:   return 0;
2569: }

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

2574:    Logically Collective on dm

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

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

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

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

2594: +  global - global DM
2595: -  ctx - optional user-defined function context

2597:    Level: advanced

2599:    Note:
2600:    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.

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

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

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

2627:   DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias);
2628:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2629:     PetscInt nRows;

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

2651: /*@
2652:     DMGlobalToLocal - update local vectors from global vector

2654:     Neighbor-wise Collective on dm

2656:     Input Parameters:
2657: +   dm - the `DM` object
2658: .   g - the global vector
2659: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2660: -   l - the local vector

2662:     Notes:
2663:     The communication involved in this update can be overlapped with computation by instead using
2664:     `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.

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

2668:     Level: beginner

2670: .seealso: `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2671:           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`,
2672:           `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`

2674: @*/
2675: PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2676: {
2677:   DMGlobalToLocalBegin(dm, g, mode, l);
2678:   DMGlobalToLocalEnd(dm, g, mode, l);
2679:   return 0;
2680: }

2682: /*@
2683:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

2685:     Neighbor-wise Collective on dm

2687:     Input Parameters:
2688: +   dm - the `DM` object
2689: .   g - the global vector
2690: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2691: -   l - the local vector

2693:     Level: intermediate

2695:     Notes:
2696:     The operation is completed with `DMGlobalToLocalEnd()`

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

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

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

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

2706: @*/
2707: PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2708: {
2709:   PetscSF                 sf;
2710:   DMGlobalToLocalHookLink link;

2713:   for (link = dm->gtolhook; link; link = link->next) {
2714:     if (link->beginhook) (*link->beginhook)(dm, g, mode, l, link->ctx);
2715:   }
2716:   DMGetSectionSF(dm, &sf);
2717:   if (sf) {
2718:     const PetscScalar *gArray;
2719:     PetscScalar       *lArray;
2720:     PetscMemType       lmtype, gmtype;

2723:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2724:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2725:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
2726:     VecRestoreArrayAndMemType(l, &lArray);
2727:     VecRestoreArrayReadAndMemType(g, &gArray);
2728:   } else {
2729:     (*dm->ops->globaltolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2730:   }
2731:   return 0;
2732: }

2734: /*@
2735:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

2737:     Neighbor-wise Collective on dm

2739:     Input Parameters:
2740: +   dm - the `DM` object
2741: .   g - the global vector
2742: .   mode - `INSERT_VALUES` or `ADD_VALUES`
2743: -   l - the local vector

2745:     Level: intermediate

2747:     Note:
2748:     See `DMGlobalToLocalBegin()` for details.

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

2752: @*/
2753: PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2754: {
2755:   PetscSF                 sf;
2756:   const PetscScalar      *gArray;
2757:   PetscScalar            *lArray;
2758:   PetscBool               transform;
2759:   DMGlobalToLocalHookLink link;
2760:   PetscMemType            lmtype, gmtype;

2763:   DMGetSectionSF(dm, &sf);
2764:   DMHasBasisTransform(dm, &transform);
2765:   if (sf) {

2768:     VecGetArrayAndMemType(l, &lArray, &lmtype);
2769:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
2770:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE);
2771:     VecRestoreArrayAndMemType(l, &lArray);
2772:     VecRestoreArrayReadAndMemType(g, &gArray);
2773:     if (transform) DMPlexGlobalToLocalBasis(dm, l);
2774:   } else {
2775:     (*dm->ops->globaltolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2776:   }
2777:   DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL);
2778:   for (link = dm->gtolhook; link; link = link->next) {
2779:     if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
2780:   }
2781:   return 0;
2782: }

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

2787:    Logically Collective on dm

2789:    Input Parameters:
2790: +  dm - the `DM`
2791: .  beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2792: .  endhook - function to run after `DMLocalToGlobalEnd()` has completed
2793: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

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

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

2807: +  global - global `DM`
2808: .  l - local vector
2809: .  mode - mode
2810: .  g - global vector
2811: -  ctx - optional user-defined function context

2813:    Level: advanced

2815: .seealso: `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2816: @*/
2817: PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx)
2818: {
2819:   DMLocalToGlobalHookLink link, *p;

2822:   for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2823:   PetscNew(&link);
2824:   link->beginhook = beginhook;
2825:   link->endhook   = endhook;
2826:   link->ctx       = ctx;
2827:   link->next      = NULL;
2828:   *p              = link;
2829:   return 0;
2830: }

2832: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2833: {
2834:   Mat          cMat;
2835:   Vec          cVec;
2836:   PetscSection section, cSec;
2837:   PetscInt     pStart, pEnd, p, dof;

2840:   DMGetDefaultConstraints(dm, &cSec, &cMat, NULL);
2841:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
2842:     PetscInt nRows;

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

2869:     Neighbor-wise Collective on dm

2871:     Input Parameters:
2872: +   dm - the `DM` object
2873: .   l - the local vector
2874: .   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.
2875: -   g - the global vector

2877:     Notes:
2878:     The communication involved in this update can be overlapped with computation by using
2879:     `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.

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

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

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

2887:     Level: beginner

2889: .seealso: `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`,  `DMLocalToGlobalHookAdd()`,  `DMGlobaToLocallHookAdd()`

2891: @*/
2892: PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
2893: {
2894:   DMLocalToGlobalBegin(dm, l, mode, g);
2895:   DMLocalToGlobalEnd(dm, l, mode, g);
2896:   return 0;
2897: }

2899: /*@
2900:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

2902:     Neighbor-wise Collective on dm

2904:     Input Parameters:
2905: +   dm - the `DM` object
2906: .   l - the local vector
2907: .   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.
2908: -   g - the global vector

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

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

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

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

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

2921:     Level: intermediate

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

2925: @*/
2926: PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
2927: {
2928:   PetscSF                 sf;
2929:   PetscSection            s, gs;
2930:   DMLocalToGlobalHookLink link;
2931:   Vec                     tmpl;
2932:   const PetscScalar      *lArray;
2933:   PetscScalar            *gArray;
2934:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
2935:   PetscMemType            lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;

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

2982:       DMGetGlobalSection(dm, &gs);
2983:       PetscSectionGetChart(s, &pStart, &pEnd);
2984:       VecGetOwnershipRange(g, &gStart, NULL);
2985:       for (p = pStart; p < pEnd; ++p) {
2986:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

2988:         PetscSectionGetDof(s, p, &dof);
2989:         PetscSectionGetDof(gs, p, &gdof);
2990:         PetscSectionGetConstraintDof(s, p, &cdof);
2991:         PetscSectionGetConstraintDof(gs, p, &gcdof);
2992:         PetscSectionGetOffset(s, p, &off);
2993:         PetscSectionGetOffset(gs, p, &goff);
2994:         /* Ignore off-process data and points with no global data */
2995:         if (!gdof || goff < 0) continue;
2997:         /* If no constraints are enforced in the global vector */
2998:         if (!gcdof) {
2999:           for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
3000:           /* If constraints are enforced in the global vector */
3001:         } else if (cdof == gcdof) {
3002:           const PetscInt *cdofs;
3003:           PetscInt        cind = 0;

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

3035: /*@
3036:     DMLocalToGlobalEnd - updates global vectors from local vectors

3038:     Neighbor-wise Collective on dm

3040:     Input Parameters:
3041: +   dm - the `DM` object
3042: .   l - the local vector
3043: .   mode - `INSERT_VALUES` or `ADD_VALUES`
3044: -   g - the global vector

3046:     Level: intermediate

3048:     Note:
3049:     See `DMLocalToGlobalBegin()` for full details

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

3053: @*/
3054: PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3055: {
3056:   PetscSF                 sf;
3057:   PetscSection            s;
3058:   DMLocalToGlobalHookLink link;
3059:   PetscBool               isInsert, transform;

3062:   DMGetSectionSF(dm, &sf);
3063:   DMGetLocalSection(dm, &s);
3064:   switch (mode) {
3065:   case INSERT_VALUES:
3066:   case INSERT_ALL_VALUES:
3067:     isInsert = PETSC_TRUE;
3068:     break;
3069:   case ADD_VALUES:
3070:   case ADD_ALL_VALUES:
3071:     isInsert = PETSC_FALSE;
3072:     break;
3073:   default:
3074:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3075:   }
3076:   if (sf && !isInsert) {
3077:     const PetscScalar *lArray;
3078:     PetscScalar       *gArray;
3079:     Vec                tmpl;

3081:     DMHasBasisTransform(dm, &transform);
3082:     if (transform) {
3083:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3084:       VecGetArrayRead(tmpl, &lArray);
3085:     } else {
3086:       VecGetArrayReadAndMemType(l, &lArray, NULL);
3087:     }
3088:     VecGetArrayAndMemType(g, &gArray, NULL);
3089:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
3090:     if (transform) {
3091:       VecRestoreArrayRead(tmpl, &lArray);
3092:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
3093:     } else {
3094:       VecRestoreArrayReadAndMemType(l, &lArray);
3095:     }
3096:     VecRestoreArrayAndMemType(g, &gArray);
3097:   } else if (s && isInsert) {
3098:   } else {
3099:     (*dm->ops->localtoglobalend)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3100:   }
3101:   for (link = dm->ltoghook; link; link = link->next) {
3102:     if (link->endhook) (*link->endhook)(dm, g, mode, l, link->ctx);
3103:   }
3104:   return 0;
3105: }

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

3112:    Neighbor-wise Collective on dm

3114:    Input Parameters:
3115: +  dm - the `DM` object
3116: .  g - the original local vector
3117: -  mode - one of `INSERT_VALUES` or `ADD_VALUES`

3119:    Output Parameter:
3120: .  l  - the local vector with correct ghost values

3122:    Level: intermediate

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

3126: @*/
3127: PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3128: {
3130:   (*dm->ops->localtolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3131:   return 0;
3132: }

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

3138:    Neighbor-wise Collective on dm

3140:    Input Parameters:
3141: +  da - the `DM` object
3142: .  g - the original local vector
3143: -  mode - one of `INSERT_VALUES` or `ADD_VALUES`

3145:    Output Parameter:
3146: .  l  - the local vector with correct ghost values

3148:    Level: intermediate

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

3152: @*/
3153: PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3154: {
3156:   (*dm->ops->localtolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3157:   return 0;
3158: }

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

3163:     Collective on dm

3165:     Input Parameters:
3166: +   dm - the `DM` object
3167: -   comm - the communicator to contain the new `DM` object (or MPI_COMM_NULL)

3169:     Output Parameter:
3170: .   dmc - the coarsened `DM`

3172:     Level: developer

3174: .seealso: `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

3176: @*/
3177: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3178: {
3179:   DMCoarsenHookLink link;

3182:   PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0);
3183:   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3184:   if (*dmc) {
3185:     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3186:     DMSetCoarseDM(dm, *dmc);
3187:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3188:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc);
3189:     (*dmc)->ctx       = dm->ctx;
3190:     (*dmc)->levelup   = dm->levelup;
3191:     (*dmc)->leveldown = dm->leveldown + 1;
3192:     DMSetMatType(*dmc, dm->mattype);
3193:     for (link = dm->coarsenhook; link; link = link->next) {
3194:       if (link->coarsenhook) (*link->coarsenhook)(dm, *dmc, link->ctx);
3195:     }
3196:   }
3197:   PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0);
3199:   return 0;
3200: }

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

3205:    Logically Collective on fine

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

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

3216: +  fine - fine level `DM`
3217: .  coarse - coarse level `DM` to restrict problem to
3218: -  ctx - optional user-defined function context

3220:    Calling sequence for restricthook:
3221: $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
3222: $
3223: +  fine - fine level `DM`
3224: .  mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3225: .  rscale - scaling vector for restriction
3226: .  inject - matrix restricting by injection
3227: .  coarse - coarse level DM to update
3228: -  ctx - optional user-defined function context

3230:    Level: advanced

3232:    Notes:
3233:    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`.

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

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

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

3242:    Fortran Note:
3243:    This function is not available from Fortran.

3245: .seealso: `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3246: @*/
3247: PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3248: {
3249:   DMCoarsenHookLink link, *p;

3252:   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3253:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3254:   }
3255:   PetscNew(&link);
3256:   link->coarsenhook  = coarsenhook;
3257:   link->restricthook = restricthook;
3258:   link->ctx          = ctx;
3259:   link->next         = NULL;
3260:   *p                 = link;
3261:   return 0;
3262: }

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

3267:    Logically Collective on fine

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

3275:    Level: advanced

3277:    Note:
3278:    This function does nothing if the hook is not in the list.

3280:    Fortran Note:
3281:    This function is not available from Fortran.

3283: .seealso: `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3284: @*/
3285: PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3286: {
3287:   DMCoarsenHookLink link, *p;

3290:   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3291:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3292:       link = *p;
3293:       *p   = link->next;
3294:       PetscFree(link);
3295:       break;
3296:     }
3297:   }
3298:   return 0;
3299: }

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

3304:    Collective if any hooks are

3306:    Input Parameters:
3307: +  fine - finer `DM` from which the data is obtained
3308: .  restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3309: .  rscale - scaling vector for restriction
3310: .  inject - injection matrix, also use `MatRestrict()`
3311: -  coarse - coarser DM to update

3313:    Level: developer

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

3318: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3319: @*/
3320: PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3321: {
3322:   DMCoarsenHookLink link;

3324:   for (link = fine->coarsenhook; link; link = link->next) {
3325:     if (link->restricthook) (*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx);
3326:   }
3327:   return 0;
3328: }

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

3333:    Logically Collective on global

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

3341:    Calling sequence for ddhook:
3342: $    ddhook(DM global,DM block,void *ctx)

3344: +  global - global `DM`
3345: .  block  - block `DM`
3346: -  ctx - optional user-defined function context

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

3351: +  global - global `DM`
3352: .  out    - scatter to the outer (with ghost and overlap points) block vector
3353: .  in     - scatter to block vector values only owned locally
3354: .  block  - block `DM`
3355: -  ctx - optional user-defined function context

3357:    Level: advanced

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

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

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

3367:    Fortran Note:
3368:    This function is not available from Fortran.

3370: .seealso: `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3371: @*/
3372: PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3373: {
3374:   DMSubDomainHookLink link, *p;

3377:   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3378:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return 0;
3379:   }
3380:   PetscNew(&link);
3381:   link->restricthook = restricthook;
3382:   link->ddhook       = ddhook;
3383:   link->ctx          = ctx;
3384:   link->next         = NULL;
3385:   *p                 = link;
3386:   return 0;
3387: }

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

3392:    Logically Collective on global

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

3400:    Level: advanced

3402:    Fortran Note:
3403:    This function is not available from Fortran.

3405: .seealso: `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3406: @*/
3407: PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3408: {
3409:   DMSubDomainHookLink link, *p;

3412:   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3413:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3414:       link = *p;
3415:       *p   = link->next;
3416:       PetscFree(link);
3417:       break;
3418:     }
3419:   }
3420:   return 0;
3421: }

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

3426:    Collective if any hooks are

3428:    Input Parameters:
3429: +  fine - finer `DM` to use as a base
3430: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
3431: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
3432: -  coarse - coarser `DM` to update

3434:    Level: developer

3436: .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`
3437: @*/
3438: PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3439: {
3440:   DMSubDomainHookLink link;

3442:   for (link = global->subdomainhook; link; link = link->next) {
3443:     if (link->restricthook) (*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx);
3444:   }
3445:   return 0;
3446: }

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

3451:     Not Collective

3453:     Input Parameter:
3454: .   dm - the `DM` object

3456:     Output Parameter:
3457: .   level - number of coarsenings

3459:     Level: developer

3461: .seealso: `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

3463: @*/
3464: PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3465: {
3468:   *level = dm->leveldown;
3469:   return 0;
3470: }

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

3475:     Collective on dm

3477:     Input Parameters:
3478: +   dm - the `DM` object
3479: -   level - number of coarsenings

3481:     Level: developer

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

3486: .seealso: `DMSetCoarsenLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3487: @*/
3488: PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3489: {
3491:   dm->leveldown = level;
3492:   return 0;
3493: }

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

3498:     Collective on dm

3500:     Input Parameters:
3501: +   dm - the `DM` object
3502: -   nlevels - the number of levels of refinement

3504:     Output Parameter:
3505: .   dmf - the refined `DM` hierarchy

3507:     Level: developer

3509: .seealso: `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

3511: @*/
3512: PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3513: {
3516:   if (nlevels == 0) return 0;
3518:   if (dm->ops->refinehierarchy) {
3519:     PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3520:   } else if (dm->ops->refine) {
3521:     PetscInt i;

3523:     DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]);
3524:     for (i = 1; i < nlevels; i++) DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]);
3525:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No RefineHierarchy for this DM yet");
3526:   return 0;
3527: }

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

3532:     Collective on dm

3534:     Input Parameters:
3535: +   dm - the `DM` object
3536: -   nlevels - the number of levels of coarsening

3538:     Output Parameter:
3539: .   dmc - the coarsened `DM` hierarchy

3541:     Level: developer

3543: .seealso: `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`

3545: @*/
3546: PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3547: {
3550:   if (nlevels == 0) return 0;
3552:   if (dm->ops->coarsenhierarchy) {
3553:     PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3554:   } else if (dm->ops->coarsen) {
3555:     PetscInt i;

3557:     DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]);
3558:     for (i = 1; i < nlevels; i++) DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]);
3559:   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No CoarsenHierarchy for this DM yet");
3560:   return 0;
3561: }

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

3566:     Logically Collective if the function is collective

3568:     Input Parameters:
3569: +   dm - the `DM` object
3570: -   destroy - the destroy function

3572:     Level: intermediate

3574: .seealso: `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`

3576: @*/
3577: PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3578: {
3580:   dm->ctxdestroy = destroy;
3581:   return 0;
3582: }

3584: /*@
3585:     DMSetApplicationContext - Set a user context into a `DM` object

3587:     Not Collective

3589:     Input Parameters:
3590: +   dm - the `DM` object
3591: -   ctx - the user context

3593:     Level: intermediate

3595:     Note:
3596:     A user context is a way to pass problem specific information that is accessable whenever the `DM` is available

3598: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`

3600: @*/
3601: PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3602: {
3604:   dm->ctx = ctx;
3605:   return 0;
3606: }

3608: /*@
3609:     DMGetApplicationContext - Gets a user context from a `DM` object

3611:     Not Collective

3613:     Input Parameter:
3614: .   dm - the `DM` object

3616:     Output Parameter:
3617: .   ctx - the user context

3619:     Level: intermediate

3621:     Note:
3622:     A user context is a way to pass problem specific information that is accessable whenever the `DM` is available

3624: .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`

3626: @*/
3627: PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3628: {
3630:   *(void **)ctx = dm->ctx;
3631:   return 0;
3632: }

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

3637:     Logically Collective on dm

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

3643:     Level: intermediate

3645: .seealso: `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3646:          `DMSetJacobian()`

3648: @*/
3649: PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3650: {
3652:   dm->ops->computevariablebounds = f;
3653:   return 0;
3654: }

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

3659:     Not Collective

3661:     Input Parameter:
3662: .   dm - the `DM` object to destroy

3664:     Output Parameter:
3665: .   flg - `PETSC_TRUE` if the variable bounds function exists

3667:     Level: developer

3669: .seealso: `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`

3671: @*/
3672: PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3673: {
3676:   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3677:   return 0;
3678: }

3680: /*@C
3681:     DMComputeVariableBounds - compute variable bounds used by `SNESVI`.

3683:     Logically Collective on dm

3685:     Input Parameter:
3686: .   dm - the `DM` object

3688:     Output parameters:
3689: +   xl - lower bound
3690: -   xu - upper bound

3692:     Level: advanced

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

3697: .seealso: `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`

3699: @*/
3700: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3701: {
3705:   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3706:   return 0;
3707: }

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

3712:     Not Collective

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

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

3720:     Level: developer

3722: .seealso: `DMCreateColoring()`

3724: @*/
3725: PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3726: {
3729:   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3730:   return 0;
3731: }

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

3736:     Not Collective

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

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

3744:     Level: developer

3746: .seealso: `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`

3748: @*/
3749: PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3750: {
3753:   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3754:   return 0;
3755: }

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

3760:     Not Collective

3762:     Input Parameter:
3763: .   dm - the `DM` object

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

3768:     Level: developer

3770: .seealso: `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`

3772: @*/
3773: PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3774: {
3777:   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3778:   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3779:   return 0;
3780: }

3782: PetscFunctionList DMList              = NULL;
3783: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

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

3788:   Collective on dm

3790:   Input Parameters:
3791: + dm     - The `DM` object
3792: - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`

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

3797:   Level: intermediate

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

3802: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3803: @*/
3804: PetscErrorCode DMSetType(DM dm, DMType method)
3805: {
3806:   PetscErrorCode (*r)(DM);
3807:   PetscBool match;

3810:   PetscObjectTypeCompare((PetscObject)dm, method, &match);
3811:   if (match) return 0;

3813:   DMRegisterAll();
3814:   PetscFunctionListFind(DMList, method, &r);

3817:   PetscTryTypeMethod(dm, destroy);
3818:   PetscMemzero(dm->ops, sizeof(*dm->ops));
3819:   PetscObjectChangeTypeName((PetscObject)dm, method);
3820:   (*r)(dm);
3821:   return 0;
3822: }

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

3827:   Not Collective

3829:   Input Parameter:
3830: . dm  - The `DM`

3832:   Output Parameter:
3833: . type - The `DMType` name

3835:   Level: intermediate

3837: .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3838: @*/
3839: PetscErrorCode DMGetType(DM dm, DMType *type)
3840: {
3843:   DMRegisterAll();
3844:   *type = ((PetscObject)dm)->type_name;
3845:   return 0;
3846: }

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

3851:   Collective on dm

3853:   Input Parameters:
3854: + dm - the `DM`
3855: - newtype - new `DM` type (use "same" for the same type)

3857:   Output Parameter:
3858: . M - pointer to new `DM`

3860:   Notes:
3861:   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3862:   the MPI communicator of the generated `DM` is always the same as the communicator
3863:   of the input `DM`.

3865:   Level: intermediate

3867: .seealso: `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
3868: @*/
3869: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
3870: {
3871:   DM        B;
3872:   char      convname[256];
3873:   PetscBool sametype /*, issame */;

3878:   PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype);
3879:   /* PetscStrcmp(newtype, "same", &issame); */
3880:   if (sametype) {
3881:     *M = dm;
3882:     PetscObjectReference((PetscObject)dm);
3883:     return 0;
3884:   } else {
3885:     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;

3887:     /*
3888:        Order of precedence:
3889:        1) See if a specialized converter is known to the current DM.
3890:        2) See if a specialized converter is known to the desired DM class.
3891:        3) See if a good general converter is registered for the desired class
3892:        4) See if a good general converter is known for the current matrix.
3893:        5) Use a really basic converter.
3894:     */

3896:     /* 1) See if a specialized converter is known to the current DM and the desired class */
3897:     PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3898:     PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3899:     PetscStrlcat(convname, "_", sizeof(convname));
3900:     PetscStrlcat(convname, newtype, sizeof(convname));
3901:     PetscStrlcat(convname, "_C", sizeof(convname));
3902:     PetscObjectQueryFunction((PetscObject)dm, convname, &conv);
3903:     if (conv) goto foundconv;

3905:     /* 2)  See if a specialized converter is known to the desired DM class. */
3906:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
3907:     DMSetType(B, newtype);
3908:     PetscStrncpy(convname, "DMConvert_", sizeof(convname));
3909:     PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname));
3910:     PetscStrlcat(convname, "_", sizeof(convname));
3911:     PetscStrlcat(convname, newtype, sizeof(convname));
3912:     PetscStrlcat(convname, "_C", sizeof(convname));
3913:     PetscObjectQueryFunction((PetscObject)B, convname, &conv);
3914:     if (conv) {
3915:       DMDestroy(&B);
3916:       goto foundconv;
3917:     }

3919: #if 0
3920:     /* 3) See if a good general converter is registered for the desired class */
3921:     conv = B->ops->convertfrom;
3922:     DMDestroy(&B);
3923:     if (conv) goto foundconv;

3925:     /* 4) See if a good general converter is known for the current matrix */
3926:     if (dm->ops->convert) {
3927:       conv = dm->ops->convert;
3928:     }
3929:     if (conv) goto foundconv;
3930: #endif

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

3935:   foundconv:
3936:     PetscLogEventBegin(DM_Convert, dm, 0, 0, 0);
3937:     (*conv)(dm, newtype, M);
3938:     /* Things that are independent of DM type: We should consult DMClone() here */
3939:     {
3940:       const PetscReal *maxCell, *Lstart, *L;

3942:       DMGetPeriodicity(dm, &maxCell, &Lstart, &L);
3943:       DMSetPeriodicity(*M, maxCell, Lstart, L);
3944:       (*M)->prealloc_only = dm->prealloc_only;
3945:       PetscFree((*M)->vectype);
3946:       PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype);
3947:       PetscFree((*M)->mattype);
3948:       PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype);
3949:     }
3950:     PetscLogEventEnd(DM_Convert, dm, 0, 0, 0);
3951:   }
3952:   PetscObjectStateIncrease((PetscObject)*M);
3953:   return 0;
3954: }

3956: /*--------------------------------------------------------------------------------------------------------------------*/

3958: /*@C
3959:   DMRegister -  Adds a new `DM` type implementation

3961:   Not Collective

3963:   Input Parameters:
3964: + name        - The name of a new user-defined creation routine
3965: - create_func - The creation routine itself

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

3970:   Sample usage:
3971: .vb
3972:     DMRegister("my_da", MyDMCreate);
3973: .ve

3975:   Then, your DM type can be chosen with the procedural interface via
3976: .vb
3977:     DMCreate(MPI_Comm, DM *);
3978:     DMSetType(DM,"my_da");
3979: .ve
3980:    or at runtime via the option
3981: .vb
3982:     -da_type my_da
3983: .ve

3985:   Level: advanced

3987: .seealso: `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`

3989: @*/
3990: PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
3991: {
3992:   DMInitializePackage();
3993:   PetscFunctionListAdd(&DMList, sname, function);
3994:   return 0;
3995: }

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

4000:   Collective on viewer

4002:   Input Parameters:
4003: + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4004:            some related function before a call to `DMLoad()`.
4005: - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4006:            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`

4008:    Level: intermediate

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

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

4017:   Notes for advanced users:
4018:   Most users should not need to know the details of the binary storage
4019:   format, since `DMLoad()` and `DMView()` completely hide these details.
4020:   But for anyone who's interested, the standard binary matrix storage
4021:   format is
4022: .vb
4023:      has not yet been determined
4024: .ve

4026: .seealso: `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4027: @*/
4028: PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4029: {
4030:   PetscBool isbinary, ishdf5;

4034:   PetscViewerCheckReadable(viewer);
4035:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary);
4036:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
4037:   PetscLogEventBegin(DM_Load, viewer, 0, 0, 0);
4038:   if (isbinary) {
4039:     PetscInt classid;
4040:     char     type[256];

4042:     PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT);
4044:     PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR);
4045:     DMSetType(newdm, type);
4046:     PetscTryTypeMethod(newdm, load, viewer);
4047:   } else if (ishdf5) {
4048:     PetscTryTypeMethod(newdm, load, viewer);
4049:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4050:   PetscLogEventEnd(DM_Load, viewer, 0, 0, 0);
4051:   return 0;
4052: }

4054: /******************************** FEM Support **********************************/

4056: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4057: {
4058:   PetscInt f;

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

4065: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4066: {
4067:   PetscInt f, g;

4069:   PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name);
4070:   for (f = 0; f < rows; ++f) {
4071:     PetscPrintf(PETSC_COMM_SELF, "  |");
4072:     for (g = 0; g < cols; ++g) PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g]));
4073:     PetscPrintf(PETSC_COMM_SELF, " |\n");
4074:   }
4075:   return 0;
4076: }

4078: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4079: {
4080:   PetscInt           localSize, bs;
4081:   PetscMPIInt        size;
4082:   Vec                x, xglob;
4083:   const PetscScalar *xarray;

4085:   MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);
4086:   VecDuplicate(X, &x);
4087:   VecCopy(X, x);
4088:   VecChop(x, tol);
4089:   PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name);
4090:   if (size > 1) {
4091:     VecGetLocalSize(x, &localSize);
4092:     VecGetArrayRead(x, &xarray);
4093:     VecGetBlockSize(x, &bs);
4094:     VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob);
4095:   } else {
4096:     xglob = x;
4097:   }
4098:   VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm)));
4099:   if (size > 1) {
4100:     VecDestroy(&xglob);
4101:     VecRestoreArrayRead(x, &xarray);
4102:   }
4103:   VecDestroy(&x);
4104:   return 0;
4105: }

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

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

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

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

4119:   Level: advanced

4121:   Notes:
4122:   Use `DMGetLocalSection()` in new code.

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

4126: .seealso: `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4127: @*/
4128: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4129: {
4130:   DMGetLocalSection(dm, section);
4131:   return 0;
4132: }

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

4137:   Input Parameter:
4138: . dm - The `DM`

4140:   Output Parameter:
4141: . section - The `PetscSection`

4143:   Options Database Keys:
4144: . -dm_petscsection_view - View the section created by the `DM`

4146:   Level: intermediate

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

4151: .seealso: `DMSetLocalSection()`, `DMGetGlobalSection()`
4152: @*/
4153: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4154: {
4157:   if (!dm->localSection && dm->ops->createlocalsection) {
4158:     PetscInt d;

4160:     if (dm->setfromoptionscalled) {
4161:       PetscObject       obj = (PetscObject)dm;
4162:       PetscViewer       viewer;
4163:       PetscViewerFormat format;
4164:       PetscBool         flg;

4166:       PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
4167:       if (flg) PetscViewerPushFormat(viewer, format);
4168:       for (d = 0; d < dm->Nds; ++d) {
4169:         PetscDSSetFromOptions(dm->probs[d].ds);
4170:         if (flg) PetscDSView(dm->probs[d].ds, viewer);
4171:       }
4172:       if (flg) {
4173:         PetscViewerFlush(viewer);
4174:         PetscViewerPopFormat(viewer);
4175:         PetscViewerDestroy(&viewer);
4176:       }
4177:     }
4178:     PetscUseTypeMethod(dm, createlocalsection);
4179:     if (dm->localSection) PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view");
4180:   }
4181:   *section = dm->localSection;
4182:   return 0;
4183: }

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

4188:   Input Parameters:
4189: + dm - The `DM`
4190: - section - The `PetscSection`

4192:   Level: advanced

4194:   Notes:
4195:   Use `DMSetLocalSection()` in new code.

4197:   Any existing `PetscSection` will be destroyed

4199: .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4200: @*/
4201: PetscErrorCode DMSetSection(DM dm, PetscSection section)
4202: {
4203:   DMSetLocalSection(dm, section);
4204:   return 0;
4205: }

4207: /*@
4208:   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.

4210:   Input Parameters:
4211: + dm - The `DM`
4212: - section - The `PetscSection`

4214:   Level: intermediate

4216:   Note:
4217:   Any existing Section will be destroyed

4219: .seealso: `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4220: @*/
4221: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4222: {
4223:   PetscInt numFields = 0;
4224:   PetscInt f;

4228:   PetscObjectReference((PetscObject)section);
4229:   PetscSectionDestroy(&dm->localSection);
4230:   dm->localSection = section;
4231:   if (section) PetscSectionGetNumFields(dm->localSection, &numFields);
4232:   if (numFields) {
4233:     DMSetNumFields(dm, numFields);
4234:     for (f = 0; f < numFields; ++f) {
4235:       PetscObject disc;
4236:       const char *name;

4238:       PetscSectionGetFieldName(dm->localSection, f, &name);
4239:       DMGetField(dm, f, NULL, &disc);
4240:       PetscObjectSetName(disc, name);
4241:     }
4242:   }
4243:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4244:   PetscSectionDestroy(&dm->globalSection);
4245:   return 0;
4246: }

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

4251:   not collective

4253:   Input Parameter:
4254: . dm - The `DM`

4256:   Output Parameters:
4257: + 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.
4258: . 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.
4259: - bias - Vector containing bias to be added to constrained dofs

4261:   Level: advanced

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

4266: .seealso: `DMSetDefaultConstraints()`
4267: @*/
4268: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4269: {
4271:   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4272:   if (section) *section = dm->defaultConstraint.section;
4273:   if (mat) *mat = dm->defaultConstraint.mat;
4274:   if (bias) *bias = dm->defaultConstraint.bias;
4275:   return 0;
4276: }

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

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

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

4285:   collective on dm

4287:   Input Parameters:
4288: + dm - The `DM`
4289: . 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).
4290: . 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).
4291: - 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).

4293:   Level: advanced

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

4298: .seealso: `DMGetDefaultConstraints()`
4299: @*/
4300: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4301: {
4302:   PetscMPIInt result;

4305:   if (section) {
4307:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result);
4309:   }
4310:   if (mat) {
4312:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result);
4314:   }
4315:   if (bias) {
4317:     MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result);
4319:   }
4320:   PetscObjectReference((PetscObject)section);
4321:   PetscSectionDestroy(&dm->defaultConstraint.section);
4322:   dm->defaultConstraint.section = section;
4323:   PetscObjectReference((PetscObject)mat);
4324:   MatDestroy(&dm->defaultConstraint.mat);
4325:   dm->defaultConstraint.mat = mat;
4326:   PetscObjectReference((PetscObject)bias);
4327:   VecDestroy(&dm->defaultConstraint.bias);
4328:   dm->defaultConstraint.bias = bias;
4329:   return 0;
4330: }

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

4336:   Input Parameters:
4337: + dm - The `DM`
4338: . localSection - `PetscSection` describing the local data layout
4339: - globalSection - `PetscSection` describing the global data layout

4341:   Level: intermediate

4343: .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`
4344: */
4345: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4346: {
4347:   MPI_Comm        comm;
4348:   PetscLayout     layout;
4349:   const PetscInt *ranges;
4350:   PetscInt        pStart, pEnd, p, nroots;
4351:   PetscMPIInt     size, rank;
4352:   PetscBool       valid = PETSC_TRUE, gvalid;

4354:   PetscObjectGetComm((PetscObject)dm, &comm);
4356:   MPI_Comm_size(comm, &size);
4357:   MPI_Comm_rank(comm, &rank);
4358:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
4359:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
4360:   PetscLayoutCreate(comm, &layout);
4361:   PetscLayoutSetBlockSize(layout, 1);
4362:   PetscLayoutSetLocalSize(layout, nroots);
4363:   PetscLayoutSetUp(layout);
4364:   PetscLayoutGetRanges(layout, &ranges);
4365:   for (p = pStart; p < pEnd; ++p) {
4366:     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;

4368:     PetscSectionGetDof(localSection, p, &dof);
4369:     PetscSectionGetOffset(localSection, p, &off);
4370:     PetscSectionGetConstraintDof(localSection, p, &cdof);
4371:     PetscSectionGetDof(globalSection, p, &gdof);
4372:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
4373:     PetscSectionGetOffset(globalSection, p, &goff);
4374:     if (!gdof) continue; /* Censored point */
4375:     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4376:       PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof);
4377:       valid = PETSC_FALSE;
4378:     }
4379:     if (gcdof && (gcdof != cdof)) {
4380:       PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof);
4381:       valid = PETSC_FALSE;
4382:     }
4383:     if (gdof < 0) {
4384:       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4385:       for (d = 0; d < gsize; ++d) {
4386:         PetscInt offset = -(goff + 1) + d, r;

4388:         PetscFindInt(offset, size + 1, ranges, &r);
4389:         if (r < 0) r = -(r + 2);
4390:         if ((r < 0) || (r >= size)) {
4391:           PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff);
4392:           valid = PETSC_FALSE;
4393:           break;
4394:         }
4395:       }
4396:     }
4397:   }
4398:   PetscLayoutDestroy(&layout);
4399:   PetscSynchronizedFlush(comm, NULL);
4400:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
4401:   if (!gvalid) {
4402:     DMView(dm, NULL);
4403:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4404:   }
4405:   return 0;
4406: }
4407: #endif

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

4412:   Collective on dm

4414:   Input Parameter:
4415: . dm - The `DM`

4417:   Output Parameter:
4418: . section - The `PetscSection`

4420:   Level: intermediate

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

4425: .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`
4426: @*/
4427: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4428: {
4431:   if (!dm->globalSection) {
4432:     PetscSection s;

4434:     DMGetLocalSection(dm, &s);
4437:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
4438:     PetscLayoutDestroy(&dm->map);
4439:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
4440:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
4441:   }
4442:   *section = dm->globalSection;
4443:   return 0;
4444: }

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

4449:   Input Parameters:
4450: + dm - The `DM`
4451: - section - The PetscSection, or NULL

4453:   Level: intermediate

4455:   Note:
4456:   Any existing `PetscSection` will be destroyed

4458: .seealso: `DMGetGlobalSection()`, `DMSetLocalSection()`
4459: @*/
4460: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4461: {
4464:   PetscObjectReference((PetscObject)section);
4465:   PetscSectionDestroy(&dm->globalSection);
4466:   dm->globalSection = section;
4467: #if defined(PETSC_USE_DEBUG)
4468:   if (section) DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);
4469: #endif
4470:   return 0;
4471: }

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

4477:   Input Parameter:
4478: . dm - The `DM`

4480:   Output Parameter:
4481: . sf - The `PetscSF`

4483:   Level: intermediate

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

4488: .seealso: `DMSetSectionSF()`, `DMCreateSectionSF()`
4489: @*/
4490: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4491: {
4492:   PetscInt nroots;

4496:   if (!dm->sectionSF) PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF);
4497:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
4498:   if (nroots < 0) {
4499:     PetscSection section, gSection;

4501:     DMGetLocalSection(dm, &section);
4502:     if (section) {
4503:       DMGetGlobalSection(dm, &gSection);
4504:       DMCreateSectionSF(dm, section, gSection);
4505:     } else {
4506:       *sf = NULL;
4507:       return 0;
4508:     }
4509:   }
4510:   *sf = dm->sectionSF;
4511:   return 0;
4512: }

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

4517:   Input Parameters:
4518: + dm - The `DM`
4519: - sf - The `PetscSF`

4521:   Level: intermediate

4523:   Note:
4524:   Any previous `PetscSF` is destroyed

4526: .seealso: `DMGetSectionSF()`, `DMCreateSectionSF()`
4527: @*/
4528: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4529: {
4532:   PetscObjectReference((PetscObject)sf);
4533:   PetscSFDestroy(&dm->sectionSF);
4534:   dm->sectionSF = sf;
4535:   return 0;
4536: }

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

4542:   Input Parameters:
4543: + dm - The `DM`
4544: . localSection - `PetscSection` describing the local data layout
4545: - globalSection - `PetscSection` describing the global data layout

4547:   Level: developer

4549:   Note:
4550:   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`

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

4557: .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4558: @*/
4559: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4560: {
4562:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
4563:   return 0;
4564: }

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

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

4571:   Input Parameter:
4572: . dm - The `DM`

4574:   Output Parameter:
4575: . sf - The `PetscSF`

4577:   Level: intermediate

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

4582: .seealso: `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4583: @*/
4584: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4585: {
4588:   *sf = dm->sf;
4589:   return 0;
4590: }

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

4595:   Collective on dm

4597:   Input Parameters:
4598: + dm - The `DM`
4599: - sf - The` PetscSF`

4601:   Level: intermediate

4603: .seealso: `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4604: @*/
4605: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4606: {
4609:   PetscObjectReference((PetscObject)sf);
4610:   PetscSFDestroy(&dm->sf);
4611:   dm->sf = sf;
4612:   return 0;
4613: }

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

4618:   Input Parameter:
4619: . dm - The `DM`

4621:   Output Parameter:
4622: . sf - The `PetscSF`

4624:   Level: intermediate

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

4629: .seealso: `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4630: @*/
4631: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4632: {
4635:   *sf = dm->sfNatural;
4636:   return 0;
4637: }

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

4642:   Input Parameters:
4643: + dm - The DM
4644: - sf - The PetscSF

4646:   Level: intermediate

4648: .seealso: `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4649: @*/
4650: PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4651: {
4654:   PetscObjectReference((PetscObject)sf);
4655:   PetscSFDestroy(&dm->sfNatural);
4656:   dm->sfNatural = sf;
4657:   return 0;
4658: }

4660: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4661: {
4662:   PetscClassId id;

4664:   PetscObjectGetClassId(disc, &id);
4665:   if (id == PETSCFE_CLASSID) {
4666:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4667:   } else if (id == PETSCFV_CLASSID) {
4668:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
4669:   } else {
4670:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
4671:   }
4672:   return 0;
4673: }

4675: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4676: {
4677:   RegionField *tmpr;
4678:   PetscInt     Nf = dm->Nf, f;

4680:   if (Nf >= NfNew) return 0;
4681:   PetscMalloc1(NfNew, &tmpr);
4682:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4683:   for (f = Nf; f < NfNew; ++f) {
4684:     tmpr[f].disc        = NULL;
4685:     tmpr[f].label       = NULL;
4686:     tmpr[f].avoidTensor = PETSC_FALSE;
4687:   }
4688:   PetscFree(dm->fields);
4689:   dm->Nf     = NfNew;
4690:   dm->fields = tmpr;
4691:   return 0;
4692: }

4694: /*@
4695:   DMClearFields - Remove all fields from the DM

4697:   Logically collective on dm

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

4702:   Level: intermediate

4704: .seealso: `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4705: @*/
4706: PetscErrorCode DMClearFields(DM dm)
4707: {
4708:   PetscInt f;

4711:   for (f = 0; f < dm->Nf; ++f) {
4712:     PetscObjectDestroy(&dm->fields[f].disc);
4713:     DMLabelDestroy(&dm->fields[f].label);
4714:   }
4715:   PetscFree(dm->fields);
4716:   dm->fields = NULL;
4717:   dm->Nf     = 0;
4718:   return 0;
4719: }

4721: /*@
4722:   DMGetNumFields - Get the number of fields in the DM

4724:   Not collective

4726:   Input Parameter:
4727: . dm - The DM

4729:   Output Parameter:
4730: . Nf - The number of fields

4732:   Level: intermediate

4734: .seealso: `DMSetNumFields()`, `DMSetField()`
4735: @*/
4736: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4737: {
4740:   *numFields = dm->Nf;
4741:   return 0;
4742: }

4744: /*@
4745:   DMSetNumFields - Set the number of fields in the DM

4747:   Logically collective on dm

4749:   Input Parameters:
4750: + dm - The DM
4751: - Nf - The number of fields

4753:   Level: intermediate

4755: .seealso: `DMGetNumFields()`, `DMSetField()`
4756: @*/
4757: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4758: {
4759:   PetscInt Nf, f;

4762:   DMGetNumFields(dm, &Nf);
4763:   for (f = Nf; f < numFields; ++f) {
4764:     PetscContainer obj;

4766:     PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj);
4767:     DMAddField(dm, NULL, (PetscObject)obj);
4768:     PetscContainerDestroy(&obj);
4769:   }
4770:   return 0;
4771: }

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

4776:   Not collective

4778:   Input Parameters:
4779: + dm - The `DM`
4780: - f  - The field number

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

4786:   Level: intermediate

4788: .seealso: `DMAddField()`, `DMSetField()`
4789: @*/
4790: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4791: {
4795:   if (label) *label = dm->fields[f].label;
4796:   if (disc) *disc = dm->fields[f].disc;
4797:   return 0;
4798: }

4800: /* Does not clear the DS */
4801: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4802: {
4803:   DMFieldEnlarge_Static(dm, f + 1);
4804:   DMLabelDestroy(&dm->fields[f].label);
4805:   PetscObjectDestroy(&dm->fields[f].disc);
4806:   dm->fields[f].label = label;
4807:   dm->fields[f].disc  = disc;
4808:   PetscObjectReference((PetscObject)label);
4809:   PetscObjectReference((PetscObject)disc);
4810:   return 0;
4811: }

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

4817:   Logically collective on dm

4819:   Input Parameters:
4820: + dm    - The `DM`
4821: . f     - The field number
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: .seealso: `DMAddField()`, `DMGetField()`
4828: @*/
4829: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4830: {
4835:   DMSetField_Internal(dm, f, label, disc);
4836:   DMSetDefaultAdjacency_Private(dm, f, disc);
4837:   DMClearDS(dm);
4838:   return 0;
4839: }

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

4845:   Logically collective on dm

4847:   Input Parameters:
4848: + dm    - The `DM`
4849: . label - The label indicating the support of the field, or NULL for the entire mesh
4850: - disc - The discretization object

4852:   Level: intermediate

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

4857:   For example, a piecewise continous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
4858:   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
4859:   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.

4861: .seealso: `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
4862: @*/
4863: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
4864: {
4865:   PetscInt Nf = dm->Nf;

4870:   DMFieldEnlarge_Static(dm, Nf + 1);
4871:   dm->fields[Nf].label = label;
4872:   dm->fields[Nf].disc  = disc;
4873:   PetscObjectReference((PetscObject)label);
4874:   PetscObjectReference((PetscObject)disc);
4875:   DMSetDefaultAdjacency_Private(dm, Nf, disc);
4876:   DMClearDS(dm);
4877:   return 0;
4878: }

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

4883:   Logically collective on dm

4885:   Input Parameters:
4886: + dm          - The `DM`
4887: . f           - The field index
4888: - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells

4890:   Level: intermediate

4892: .seealso: `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4893: @*/
4894: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4895: {
4897:   dm->fields[f].avoidTensor = avoidTensor;
4898:   return 0;
4899: }

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

4904:   Not collective

4906:   Input Parameters:
4907: + dm          - The `DM`
4908: - f           - The field index

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

4913:   Level: intermediate

4915:  .seealso: `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
4916: @*/
4917: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4918: {
4920:   *avoidTensor = dm->fields[f].avoidTensor;
4921:   return 0;
4922: }

4924: /*@
4925:   DMCopyFields - Copy the discretizations for the `DM` into another `DM`

4927:   Collective on dm

4929:   Input Parameter:
4930: . dm - The `DM`

4932:   Output Parameter:
4933: . newdm - The `DM`

4935:   Level: advanced

4937: .seealso: `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
4938: @*/
4939: PetscErrorCode DMCopyFields(DM dm, DM newdm)
4940: {
4941:   PetscInt Nf, f;

4943:   if (dm == newdm) return 0;
4944:   DMGetNumFields(dm, &Nf);
4945:   DMClearFields(newdm);
4946:   for (f = 0; f < Nf; ++f) {
4947:     DMLabel     label;
4948:     PetscObject field;
4949:     PetscBool   useCone, useClosure;

4951:     DMGetField(dm, f, &label, &field);
4952:     DMSetField(newdm, f, label, field);
4953:     DMGetAdjacency(dm, f, &useCone, &useClosure);
4954:     DMSetAdjacency(newdm, f, useCone, useClosure);
4955:   }
4956:   return 0;
4957: }

4959: /*@
4960:   DMGetAdjacency - Returns the flags for determining variable influence

4962:   Not collective

4964:   Input Parameters:
4965: + dm - The DM object
4966: - f  - The field number, or PETSC_DEFAULT for the default adjacency

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

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

4978:   Level: developer

4980: .seealso: `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
4981: @*/
4982: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4983: {
4987:   if (f < 0) {
4988:     if (useCone) *useCone = dm->adjacency[0];
4989:     if (useClosure) *useClosure = dm->adjacency[1];
4990:   } else {
4991:     PetscInt Nf;

4993:     DMGetNumFields(dm, &Nf);
4995:     if (useCone) *useCone = dm->fields[f].adjacency[0];
4996:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4997:   }
4998:   return 0;
4999: }

5001: /*@
5002:   DMSetAdjacency - Set the flags for determining variable influence

5004:   Not collective

5006:   Input Parameters:
5007: + dm         - The DM object
5008: . f          - The field number
5009: . useCone    - Flag for variable influence starting with the cone operation
5010: - useClosure - Flag for variable influence using transitive closure

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

5018:   Level: developer

5020: .seealso: `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5021: @*/
5022: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5023: {
5025:   if (f < 0) {
5026:     dm->adjacency[0] = useCone;
5027:     dm->adjacency[1] = useClosure;
5028:   } else {
5029:     PetscInt Nf;

5031:     DMGetNumFields(dm, &Nf);
5033:     dm->fields[f].adjacency[0] = useCone;
5034:     dm->fields[f].adjacency[1] = useClosure;
5035:   }
5036:   return 0;
5037: }

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

5042:   Not collective

5044:   Input Parameter:
5045: . dm - The DM object

5047:   Output Parameters:
5048: + useCone    - Flag for variable influence starting with the cone operation
5049: - useClosure - Flag for variable influence using transitive closure

5051:   Notes:
5052: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5053: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5054: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5056:   Level: developer

5058: .seealso: `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5059: @*/
5060: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5061: {
5062:   PetscInt Nf;

5067:   DMGetNumFields(dm, &Nf);
5068:   if (!Nf) {
5069:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5070:   } else {
5071:     DMGetAdjacency(dm, 0, useCone, useClosure);
5072:   }
5073:   return 0;
5074: }

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

5079:   Not collective

5081:   Input Parameters:
5082: + dm         - The DM object
5083: . useCone    - Flag for variable influence starting with the cone operation
5084: - useClosure - Flag for variable influence using transitive closure

5086:   Notes:
5087: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5088: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5089: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

5091:   Level: developer

5093: .seealso: `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5094: @*/
5095: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5096: {
5097:   PetscInt Nf;

5100:   DMGetNumFields(dm, &Nf);
5101:   if (!Nf) {
5102:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
5103:   } else {
5104:     DMSetAdjacency(dm, 0, useCone, useClosure);
5105:   }
5106:   return 0;
5107: }

5109: PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5110: {
5111:   DM           plex;
5112:   DMLabel     *labels, *glabels;
5113:   const char **names;
5114:   char        *sendNames, *recvNames;
5115:   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5116:   size_t       len;
5117:   MPI_Comm     comm;
5118:   PetscMPIInt  rank, size, p, *counts, *displs;

5120:   PetscObjectGetComm((PetscObject)dm, &comm);
5121:   MPI_Comm_size(comm, &size);
5122:   MPI_Comm_rank(comm, &rank);
5123:   DMGetNumDS(dm, &Nds);
5124:   for (s = 0; s < Nds; ++s) {
5125:     PetscDS  dsBC;
5126:     PetscInt numBd;

5128:     DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5129:     PetscDSGetNumBoundary(dsBC, &numBd);
5130:     maxLabels += numBd;
5131:   }
5132:   PetscCalloc1(maxLabels, &labels);
5133:   /* Get list of labels to be completed */
5134:   for (s = 0; s < Nds; ++s) {
5135:     PetscDS  dsBC;
5136:     PetscInt numBd, bd;

5138:     DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC);
5139:     PetscDSGetNumBoundary(dsBC, &numBd);
5140:     for (bd = 0; bd < numBd; ++bd) {
5141:       DMLabel      label;
5142:       PetscInt     field;
5143:       PetscObject  obj;
5144:       PetscClassId id;

5146:       PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5147:       DMGetField(dm, field, NULL, &obj);
5148:       PetscObjectGetClassId(obj, &id);
5149:       if (!(id == PETSCFE_CLASSID) || !label) continue;
5150:       for (l = 0; l < Nl; ++l)
5151:         if (labels[l] == label) break;
5152:       if (l == Nl) labels[Nl++] = label;
5153:     }
5154:   }
5155:   /* Get label names */
5156:   PetscMalloc1(Nl, &names);
5157:   for (l = 0; l < Nl; ++l) PetscObjectGetName((PetscObject)labels[l], &names[l]);
5158:   for (l = 0; l < Nl; ++l) {
5159:     PetscStrlen(names[l], &len);
5160:     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5161:   }
5162:   PetscFree(labels);
5163:   MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm);
5164:   PetscCalloc1(Nl * gmaxLen, &sendNames);
5165:   for (l = 0; l < Nl; ++l) PetscStrcpy(&sendNames[gmaxLen * l], names[l]);
5166:   PetscFree(names);
5167:   /* Put all names on all processes */
5168:   PetscCalloc2(size, &counts, size + 1, &displs);
5169:   MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm);
5170:   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5171:   gNl = displs[size];
5172:   for (p = 0; p < size; ++p) {
5173:     counts[p] *= gmaxLen;
5174:     displs[p] *= gmaxLen;
5175:   }
5176:   PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels);
5177:   MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm);
5178:   PetscFree2(counts, displs);
5179:   PetscFree(sendNames);
5180:   for (l = 0, gl = 0; l < gNl; ++l) {
5181:     DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]);
5183:     for (m = 0; m < gl; ++m)
5184:       if (glabels[m] == glabels[gl]) continue;
5185:     DMConvert(dm, DMPLEX, &plex);
5186:     DMPlexLabelComplete(plex, glabels[gl]);
5187:     DMDestroy(&plex);
5188:     ++gl;
5189:   }
5190:   PetscFree2(recvNames, glabels);
5191:   return 0;
5192: }

5194: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5195: {
5196:   DMSpace *tmpd;
5197:   PetscInt Nds = dm->Nds, s;

5199:   if (Nds >= NdsNew) return 0;
5200:   PetscMalloc1(NdsNew, &tmpd);
5201:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5202:   for (s = Nds; s < NdsNew; ++s) {
5203:     tmpd[s].ds     = NULL;
5204:     tmpd[s].label  = NULL;
5205:     tmpd[s].fields = NULL;
5206:   }
5207:   PetscFree(dm->probs);
5208:   dm->Nds   = NdsNew;
5209:   dm->probs = tmpd;
5210:   return 0;
5211: }

5213: /*@
5214:   DMGetNumDS - Get the number of discrete systems in the DM

5216:   Not collective

5218:   Input Parameter:
5219: . dm - The DM

5221:   Output Parameter:
5222: . Nds - The number of PetscDS objects

5224:   Level: intermediate

5226: .seealso: `DMGetDS()`, `DMGetCellDS()`
5227: @*/
5228: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5229: {
5232:   *Nds = dm->Nds;
5233:   return 0;
5234: }

5236: /*@
5237:   DMClearDS - Remove all discrete systems from the DM

5239:   Logically collective on dm

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

5244:   Level: intermediate

5246: .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5247: @*/
5248: PetscErrorCode DMClearDS(DM dm)
5249: {
5250:   PetscInt s;

5253:   for (s = 0; s < dm->Nds; ++s) {
5254:     PetscDSDestroy(&dm->probs[s].ds);
5255:     DMLabelDestroy(&dm->probs[s].label);
5256:     ISDestroy(&dm->probs[s].fields);
5257:   }
5258:   PetscFree(dm->probs);
5259:   dm->probs = NULL;
5260:   dm->Nds   = 0;
5261:   return 0;
5262: }

5264: /*@
5265:   DMGetDS - Get the default PetscDS

5267:   Not collective

5269:   Input Parameter:
5270: . dm    - The DM

5272:   Output Parameter:
5273: . prob - The default PetscDS

5275:   Level: intermediate

5277: .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5278: @*/
5279: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5280: {
5284:   if (dm->Nds <= 0) {
5285:     PetscDS ds;

5287:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5288:     DMSetRegionDS(dm, NULL, NULL, ds);
5289:     PetscDSDestroy(&ds);
5290:   }
5291:   *prob = dm->probs[0].ds;
5292:   return 0;
5293: }

5295: /*@
5296:   DMGetCellDS - Get the PetscDS defined on a given cell

5298:   Not collective

5300:   Input Parameters:
5301: + dm    - The DM
5302: - point - Cell for the DS

5304:   Output Parameter:
5305: . prob - The PetscDS defined on the given cell

5307:   Level: developer

5309: .seealso: `DMGetDS()`, `DMSetRegionDS()`
5310: @*/
5311: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5312: {
5313:   PetscDS  probDef = NULL;
5314:   PetscInt s;

5320:   *prob = NULL;
5321:   for (s = 0; s < dm->Nds; ++s) {
5322:     PetscInt val;

5324:     if (!dm->probs[s].label) {
5325:       probDef = dm->probs[s].ds;
5326:     } else {
5327:       DMLabelGetValue(dm->probs[s].label, point, &val);
5328:       if (val >= 0) {
5329:         *prob = dm->probs[s].ds;
5330:         break;
5331:       }
5332:     }
5333:   }
5334:   if (!*prob) *prob = probDef;
5335:   return 0;
5336: }

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

5341:   Not collective

5343:   Input Parameters:
5344: + dm    - The DM
5345: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

5356:   Level: advanced

5358: .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5359: @*/
5360: PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5361: {
5362:   PetscInt Nds = dm->Nds, s;

5366:   if (fields) {
5368:     *fields = NULL;
5369:   }
5370:   if (ds) {
5372:     *ds = NULL;
5373:   }
5374:   for (s = 0; s < Nds; ++s) {
5375:     if (dm->probs[s].label == label || !dm->probs[s].label) {
5376:       if (fields) *fields = dm->probs[s].fields;
5377:       if (ds) *ds = dm->probs[s].ds;
5378:       if (dm->probs[s].label) return 0;
5379:     }
5380:   }
5381:   return 0;
5382: }

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

5387:   Collective on dm

5389:   Input Parameters:
5390: + dm     - The `DM`
5391: . label  - The `DMLabel` defining the mesh region, or NULL for the entire mesh
5392: . fields - The IS containing the `DM` field numbers for the fields in this `PetscDS`, or NULL for all fields
5393: - prob   - The `PetscDS` defined on the given region

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

5399:   Level: advanced

5401: .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5402: @*/
5403: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5404: {
5405:   PetscInt Nds = dm->Nds, s;

5410:   for (s = 0; s < Nds; ++s) {
5411:     if (dm->probs[s].label == label) {
5412:       PetscDSDestroy(&dm->probs[s].ds);
5413:       dm->probs[s].ds = ds;
5414:       return 0;
5415:     }
5416:   }
5417:   DMDSEnlarge_Static(dm, Nds + 1);
5418:   PetscObjectReference((PetscObject)label);
5419:   PetscObjectReference((PetscObject)fields);
5420:   PetscObjectReference((PetscObject)ds);
5421:   if (!label) {
5422:     /* Put the NULL label at the front, so it is returned as the default */
5423:     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5424:     Nds = 0;
5425:   }
5426:   dm->probs[Nds].label  = label;
5427:   dm->probs[Nds].fields = fields;
5428:   dm->probs[Nds].ds     = ds;
5429:   return 0;
5430: }

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

5435:   Not collective

5437:   Input Parameters:
5438: + dm  - The DM
5439: - num - The region number, in [0, Nds)

5441:   Output Parameters:
5442: + label  - The region label, or NULL
5443: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5444: - ds     - The PetscDS defined on the given region, or NULL

5446:   Level: advanced

5448: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5449: @*/
5450: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5451: {
5452:   PetscInt Nds;

5455:   DMGetNumDS(dm, &Nds);
5457:   if (label) {
5459:     *label = dm->probs[num].label;
5460:   }
5461:   if (fields) {
5463:     *fields = dm->probs[num].fields;
5464:   }
5465:   if (ds) {
5467:     *ds = dm->probs[num].ds;
5468:   }
5469:   return 0;
5470: }

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

5475:   Not collective

5477:   Input Parameters:
5478: + dm     - The DM
5479: . num    - The region number, in [0, Nds)
5480: . label  - The region label, or NULL
5481: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5482: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

5484:   Level: advanced

5486: .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5487: @*/
5488: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5489: {
5490:   PetscInt Nds;

5494:   DMGetNumDS(dm, &Nds);
5496:   PetscObjectReference((PetscObject)label);
5497:   DMLabelDestroy(&dm->probs[num].label);
5498:   dm->probs[num].label = label;
5499:   if (fields) {
5501:     PetscObjectReference((PetscObject)fields);
5502:     ISDestroy(&dm->probs[num].fields);
5503:     dm->probs[num].fields = fields;
5504:   }
5505:   if (ds) {
5507:     PetscObjectReference((PetscObject)ds);
5508:     PetscDSDestroy(&dm->probs[num].ds);
5509:     dm->probs[num].ds = ds;
5510:   }
5511:   return 0;
5512: }

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

5517:   Not collective

5519:   Input Parameters:
5520: + dm  - The DM
5521: - ds  - The PetscDS defined on the given region

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

5526:   Level: advanced

5528: .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5529: @*/
5530: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5531: {
5532:   PetscInt Nds, n;

5537:   DMGetNumDS(dm, &Nds);
5538:   for (n = 0; n < Nds; ++n)
5539:     if (ds == dm->probs[n].ds) break;
5540:   if (n >= Nds) *num = -1;
5541:   else *num = n;
5542:   return 0;
5543: }

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

5548:   Not collective

5550:   Input Parameters:
5551: + dm     - The `DM`
5552: . Nc     - The number of components for the field
5553: . prefix - The options prefix for the output `PetscFE`, or NULL
5554: - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree

5556:   Output Parameter:
5557: . fem - The `PetscFE`

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

5562:   Level: intermediate

5564: .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5565: @*/
5566: PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5567: {
5568:   DMPolytopeType ct;
5569:   PetscInt       dim, cStart;

5576:   DMGetDimension(dm, &dim);
5577:   DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
5578:   DMPlexGetCellType(dm, cStart, &ct);
5579:   PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem);
5580:   return 0;
5581: }

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

5586:   Collective on dm

5588:   Input Parameter:
5589: . dm - The `DM`

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

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

5597:   Level: intermediate

5599: .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5600: @*/
5601: PetscErrorCode DMCreateDS(DM dm)
5602: {
5603:   MPI_Comm  comm;
5604:   PetscDS   dsDef;
5605:   DMLabel  *labelSet;
5606:   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5607:   PetscBool doSetup = PETSC_TRUE, flg;

5610:   if (!dm->fields) return 0;
5611:   PetscObjectGetComm((PetscObject)dm, &comm);
5612:   DMGetCoordinateDim(dm, &dE);
5613:   /* Determine how many regions we have */
5614:   PetscMalloc1(Nf, &labelSet);
5615:   Nl   = 0;
5616:   Ndef = 0;
5617:   for (f = 0; f < Nf; ++f) {
5618:     DMLabel  label = dm->fields[f].label;
5619:     PetscInt l;

5621: #ifdef PETSC_HAVE_LIBCEED
5622:     /* Move CEED context to discretizations */
5623:     {
5624:       PetscClassId id;

5626:       PetscObjectGetClassId(dm->fields[f].disc, &id);
5627:       if (id == PETSCFE_CLASSID) {
5628:         Ceed ceed;

5630:         DMGetCeed(dm, &ceed);
5631:         PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed);
5632:       }
5633:     }
5634: #endif
5635:     if (!label) {
5636:       ++Ndef;
5637:       continue;
5638:     }
5639:     for (l = 0; l < Nl; ++l)
5640:       if (label == labelSet[l]) break;
5641:     if (l < Nl) continue;
5642:     labelSet[Nl++] = label;
5643:   }
5644:   /* Create default DS if there are no labels to intersect with */
5645:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5646:   if (!dsDef && Ndef && !Nl) {
5647:     IS        fields;
5648:     PetscInt *fld, nf;

5650:     for (f = 0, nf = 0; f < Nf; ++f)
5651:       if (!dm->fields[f].label) ++nf;
5653:     PetscMalloc1(nf, &fld);
5654:     for (f = 0, nf = 0; f < Nf; ++f)
5655:       if (!dm->fields[f].label) fld[nf++] = f;
5656:     ISCreate(PETSC_COMM_SELF, &fields);
5657:     PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5658:     ISSetType(fields, ISGENERAL);
5659:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

5661:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5662:     DMSetRegionDS(dm, NULL, fields, dsDef);
5663:     PetscDSDestroy(&dsDef);
5664:     ISDestroy(&fields);
5665:   }
5666:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
5667:   if (dsDef) PetscDSSetCoordinateDimension(dsDef, dE);
5668:   /* Intersect labels with default fields */
5669:   if (Ndef && Nl) {
5670:     DM              plex;
5671:     DMLabel         cellLabel;
5672:     IS              fieldIS, allcellIS, defcellIS = NULL;
5673:     PetscInt       *fields;
5674:     const PetscInt *cells;
5675:     PetscInt        depth, nf = 0, n, c;

5677:     DMConvert(dm, DMPLEX, &plex);
5678:     DMPlexGetDepth(plex, &depth);
5679:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
5680:     if (!allcellIS) DMGetStratumIS(plex, "depth", depth, &allcellIS);
5681:     /* TODO This looks like it only works for one label */
5682:     for (l = 0; l < Nl; ++l) {
5683:       DMLabel label = labelSet[l];
5684:       IS      pointIS;

5686:       ISDestroy(&defcellIS);
5687:       DMLabelGetStratumIS(label, 1, &pointIS);
5688:       ISDifference(allcellIS, pointIS, &defcellIS);
5689:       ISDestroy(&pointIS);
5690:     }
5691:     ISDestroy(&allcellIS);

5693:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
5694:     ISGetLocalSize(defcellIS, &n);
5695:     ISGetIndices(defcellIS, &cells);
5696:     for (c = 0; c < n; ++c) DMLabelSetValue(cellLabel, cells[c], 1);
5697:     ISRestoreIndices(defcellIS, &cells);
5698:     ISDestroy(&defcellIS);
5699:     DMPlexLabelComplete(plex, cellLabel);

5701:     PetscMalloc1(Ndef, &fields);
5702:     for (f = 0; f < Nf; ++f)
5703:       if (!dm->fields[f].label) fields[nf++] = f;
5704:     ISCreate(PETSC_COMM_SELF, &fieldIS);
5705:     PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_");
5706:     ISSetType(fieldIS, ISGENERAL);
5707:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

5709:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
5710:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
5711:     PetscDSSetCoordinateDimension(dsDef, dE);
5712:     DMLabelDestroy(&cellLabel);
5713:     PetscDSDestroy(&dsDef);
5714:     ISDestroy(&fieldIS);
5715:     DMDestroy(&plex);
5716:   }
5717:   /* Create label DSes
5718:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5719:   */
5720:   /* TODO Should check that labels are disjoint */
5721:   for (l = 0; l < Nl; ++l) {
5722:     DMLabel   label = labelSet[l];
5723:     PetscDS   ds;
5724:     IS        fields;
5725:     PetscInt *fld, nf;

5727:     PetscDSCreate(PETSC_COMM_SELF, &ds);
5728:     for (f = 0, nf = 0; f < Nf; ++f)
5729:       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5730:     PetscMalloc1(nf, &fld);
5731:     for (f = 0, nf = 0; f < Nf; ++f)
5732:       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5733:     ISCreate(PETSC_COMM_SELF, &fields);
5734:     PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_");
5735:     ISSetType(fields, ISGENERAL);
5736:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
5737:     DMSetRegionDS(dm, label, fields, ds);
5738:     ISDestroy(&fields);
5739:     PetscDSSetCoordinateDimension(ds, dE);
5740:     {
5741:       DMPolytopeType ct;
5742:       PetscInt       lStart, lEnd;
5743:       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;

5745:       DMLabelGetBounds(label, &lStart, &lEnd);
5746:       if (lStart >= 0) {
5747:         DMPlexGetCellType(dm, lStart, &ct);
5748:         switch (ct) {
5749:         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5750:         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5751:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5752:         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5753:           isCohesiveLocal = PETSC_TRUE;
5754:           break;
5755:         default:
5756:           break;
5757:         }
5758:       }
5759:       MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm);
5760:       for (f = 0, nf = 0; f < Nf; ++f) {
5761:         if (label == dm->fields[f].label || !dm->fields[f].label) {
5762:           if (label == dm->fields[f].label) {
5763:             PetscDSSetDiscretization(ds, nf, NULL);
5764:             PetscDSSetCohesive(ds, nf, isCohesive);
5765:           }
5766:           ++nf;
5767:         }
5768:       }
5769:     }
5770:     PetscDSDestroy(&ds);
5771:   }
5772:   PetscFree(labelSet);
5773:   /* Set fields in DSes */
5774:   for (s = 0; s < dm->Nds; ++s) {
5775:     PetscDS         ds     = dm->probs[s].ds;
5776:     IS              fields = dm->probs[s].fields;
5777:     const PetscInt *fld;
5778:     PetscInt        nf, dsnf;
5779:     PetscBool       isCohesive;

5781:     PetscDSGetNumFields(ds, &dsnf);
5782:     PetscDSIsCohesive(ds, &isCohesive);
5783:     ISGetLocalSize(fields, &nf);
5784:     ISGetIndices(fields, &fld);
5785:     for (f = 0; f < nf; ++f) {
5786:       PetscObject  disc = dm->fields[fld[f]].disc;
5787:       PetscBool    isCohesiveField;
5788:       PetscClassId id;

5790:       /* Handle DS with no fields */
5791:       if (dsnf) PetscDSGetCohesive(ds, f, &isCohesiveField);
5792:       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5793:       if (isCohesive && !isCohesiveField) PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&disc);
5794:       PetscDSSetDiscretization(ds, f, disc);
5795:       /* We allow people to have placeholder fields and construct the Section by hand */
5796:       PetscObjectGetClassId(disc, &id);
5797:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5798:     }
5799:     ISRestoreIndices(fields, &fld);
5800:   }
5801:   /* Allow k-jet tabulation */
5802:   PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
5803:   if (flg) {
5804:     for (s = 0; s < dm->Nds; ++s) {
5805:       PetscDS  ds = dm->probs[s].ds;
5806:       PetscInt Nf, f;

5808:       PetscDSGetNumFields(ds, &Nf);
5809:       for (f = 0; f < Nf; ++f) PetscDSSetJetDegree(ds, f, k);
5810:     }
5811:   }
5812:   /* Setup DSes */
5813:   if (doSetup) {
5814:     for (s = 0; s < dm->Nds; ++s) PetscDSSetUp(dm->probs[s].ds);
5815:   }
5816:   return 0;
5817: }

5819: /*@
5820:   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.

5822:   Collective on `DM`

5824:   Input Parameters:
5825: + dm   - The `DM`
5826: - time - The time

5828:   Output Parameters:
5829: + u    - The vector will be filled with exact solution values, or NULL
5830: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

5832:   Note:
5833:   The user must call `PetscDSSetExactSolution()` before using this routine

5835:   Level: developer

5837: .seealso: `PetscDSSetExactSolution()`
5838: @*/
5839: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5840: {
5841:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5842:   void   **ectxs;
5843:   PetscInt Nf, Nds, s;

5848:   DMGetNumFields(dm, &Nf);
5849:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
5850:   DMGetNumDS(dm, &Nds);
5851:   for (s = 0; s < Nds; ++s) {
5852:     PetscDS         ds;
5853:     DMLabel         label;
5854:     IS              fieldIS;
5855:     const PetscInt *fields, id = 1;
5856:     PetscInt        dsNf, f;

5858:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
5859:     PetscDSGetNumFields(ds, &dsNf);
5860:     ISGetIndices(fieldIS, &fields);
5861:     PetscArrayzero(exacts, Nf);
5862:     PetscArrayzero(ectxs, Nf);
5863:     if (u) {
5864:       for (f = 0; f < dsNf; ++f) {
5865:         const PetscInt field = fields[f];
5866:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
5867:       }
5868:       ISRestoreIndices(fieldIS, &fields);
5869:       if (label) {
5870:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
5871:       } else {
5872:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
5873:       }
5874:     }
5875:     if (u_t) {
5876:       PetscArrayzero(exacts, Nf);
5877:       PetscArrayzero(ectxs, Nf);
5878:       for (f = 0; f < dsNf; ++f) {
5879:         const PetscInt field = fields[f];
5880:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
5881:       }
5882:       ISRestoreIndices(fieldIS, &fields);
5883:       if (label) {
5884:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5885:       } else {
5886:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
5887:       }
5888:     }
5889:   }
5890:   if (u) {
5891:     PetscObjectSetName((PetscObject)u, "Exact Solution");
5892:     PetscObjectSetOptionsPrefix((PetscObject)u, "exact_");
5893:   }
5894:   if (u_t) {
5895:     PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative");
5896:     PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_");
5897:   }
5898:   PetscFree2(exacts, ectxs);
5899:   return 0;
5900: }

5902: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5903: {
5904:   PetscDS    dsNew;
5905:   DSBoundary b;
5906:   PetscInt   cdim, Nf, f, d;
5907:   PetscBool  isCohesive;
5908:   void      *ctx;

5910:   PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew);
5911:   PetscDSCopyConstants(ds, dsNew);
5912:   PetscDSCopyExactSolutions(ds, dsNew);
5913:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
5914:   PetscDSCopyEquations(ds, dsNew);
5915:   PetscDSGetNumFields(ds, &Nf);
5916:   for (f = 0; f < Nf; ++f) {
5917:     PetscDSGetContext(ds, f, &ctx);
5918:     PetscDSSetContext(dsNew, f, ctx);
5919:     PetscDSGetCohesive(ds, f, &isCohesive);
5920:     PetscDSSetCohesive(dsNew, f, isCohesive);
5921:     PetscDSGetJetDegree(ds, f, &d);
5922:     PetscDSSetJetDegree(dsNew, f, d);
5923:   }
5924:   if (Nf) {
5925:     PetscDSGetCoordinateDimension(ds, &cdim);
5926:     PetscDSSetCoordinateDimension(dsNew, cdim);
5927:   }
5928:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
5929:   for (b = dsNew->boundary; b; b = b->next) {
5930:     DMGetLabel(dm, b->lname, &b->label);
5931:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5933:   }

5935:   DMSetRegionDS(dm, label, fields, dsNew);
5936:   PetscDSDestroy(&dsNew);
5937:   return 0;
5938: }

5940: /*@
5941:   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`

5943:   Collective on dm

5945:   Input Parameter:
5946: . dm - The `DM`

5948:   Output Parameter:
5949: . newdm - The `DM`

5951:   Level: advanced

5953: .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5954: @*/
5955: PetscErrorCode DMCopyDS(DM dm, DM newdm)
5956: {
5957:   PetscInt Nds, s;

5959:   if (dm == newdm) return 0;
5960:   DMGetNumDS(dm, &Nds);
5961:   DMClearDS(newdm);
5962:   for (s = 0; s < Nds; ++s) {
5963:     DMLabel  label;
5964:     IS       fields;
5965:     PetscDS  ds, newds;
5966:     PetscInt Nbd, bd;

5968:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
5969:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
5970:     DMTransferDS_Internal(newdm, label, fields, ds);
5971:     /* Commplete new labels in the new DS */
5972:     DMGetRegionDS(newdm, label, NULL, &newds);
5973:     PetscDSGetNumBoundary(newds, &Nbd);
5974:     for (bd = 0; bd < Nbd; ++bd) {
5975:       PetscWeakForm wf;
5976:       DMLabel       label;
5977:       PetscInt      field;

5979:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
5980:       PetscWeakFormReplaceLabel(wf, label);
5981:     }
5982:   }
5983:   DMCompleteBCLabels_Internal(newdm);
5984:   return 0;
5985: }

5987: /*@
5988:   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`

5990:   Collective on dm

5992:   Input Parameter:
5993: . dm - The `DM`

5995:   Output Parameter:
5996: . newdm - The `DM`

5998:   Level: advanced

6000:   Developer Note:
6001:   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation

6003: .seealso: `DMCopyFields()`, `DMCopyDS()`
6004: @*/
6005: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6006: {
6007:   DMCopyFields(dm, newdm);
6008:   DMCopyDS(dm, newdm);
6009:   return 0;
6010: }

6012: /*@
6013:   DMGetDimension - Return the topological dimension of the `DM`

6015:   Not collective

6017:   Input Parameter:
6018: . dm - The `DM`

6020:   Output Parameter:
6021: . dim - The topological dimension

6023:   Level: beginner

6025: .seealso: `DMSetDimension()`, `DMCreate()`
6026: @*/
6027: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6028: {
6031:   *dim = dm->dim;
6032:   return 0;
6033: }

6035: /*@
6036:   DMSetDimension - Set the topological dimension of the `DM`

6038:   Collective on dm

6040:   Input Parameters:
6041: + dm - The `DM`
6042: - dim - The topological dimension

6044:   Level: beginner

6046: .seealso: `DMGetDimension()`, `DMCreate()`
6047: @*/
6048: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6049: {
6050:   PetscDS  ds;
6051:   PetscInt Nds, n;

6055:   dm->dim = dim;
6056:   if (dm->dim >= 0) {
6057:     DMGetNumDS(dm, &Nds);
6058:     for (n = 0; n < Nds; ++n) {
6059:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
6060:       if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
6061:     }
6062:   }
6063:   return 0;
6064: }

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

6069:   Collective on dm

6071:   Input Parameters:
6072: + dm - the `DM`
6073: - dim - the dimension

6075:   Output Parameters:
6076: + pStart - The first point of the given dimension
6077: - pEnd - The first point following points of the given dimension

6079:   Note:
6080:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6081:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6082:   then the interval is empty.

6084:   Level: intermediate

6086: .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6087: @*/
6088: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6089: {
6090:   PetscInt d;

6093:   DMGetDimension(dm, &d);
6095:   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6096:   return 0;
6097: }

6099: /*@
6100:   DMGetOutputDM - Retrieve the `DM` associated with the layout for output

6102:   Collective on dm

6104:   Input Parameter:
6105: . dm - The original `DM`

6107:   Output Parameter:
6108: . odm - The `DM` which provides the layout for output

6110:   Level: intermediate

6112:   Note:
6113:   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6114:   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6115:   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.

6117: .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6118: @*/
6119: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6120: {
6121:   PetscSection section;
6122:   PetscBool    hasConstraints, ghasConstraints;

6126:   DMGetLocalSection(dm, &section);
6127:   PetscSectionHasConstraints(section, &hasConstraints);
6128:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm));
6129:   if (!ghasConstraints) {
6130:     *odm = dm;
6131:     return 0;
6132:   }
6133:   if (!dm->dmBC) {
6134:     PetscSection newSection, gsection;
6135:     PetscSF      sf;

6137:     DMClone(dm, &dm->dmBC);
6138:     DMCopyDisc(dm, dm->dmBC);
6139:     PetscSectionClone(section, &newSection);
6140:     DMSetLocalSection(dm->dmBC, newSection);
6141:     PetscSectionDestroy(&newSection);
6142:     DMGetPointSF(dm->dmBC, &sf);
6143:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
6144:     DMSetGlobalSection(dm->dmBC, gsection);
6145:     PetscSectionDestroy(&gsection);
6146:   }
6147:   *odm = dm->dmBC;
6148:   return 0;
6149: }

6151: /*@
6152:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

6154:   Input Parameter:
6155: . dm - The original `DM`

6157:   Output Parameters:
6158: + num - The output sequence number
6159: - val - The output sequence value

6161:   Level: intermediate

6163:   Note:
6164:   This is intended for output that should appear in sequence, for instance
6165:   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.

6167:   Developer Note:
6168:   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6169:   not directly related to the `DM`.

6171: .seealso: `VecView()`
6172: @*/
6173: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6174: {
6176:   if (num) {
6178:     *num = dm->outputSequenceNum;
6179:   }
6180:   if (val) {
6182:     *val = dm->outputSequenceVal;
6183:   }
6184:   return 0;
6185: }

6187: /*@
6188:   DMSetOutputSequenceNumber - Set the sequence number/value for output

6190:   Input Parameters:
6191: + dm - The original `DM`
6192: . num - The output sequence number
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: .seealso: `VecView()`
6202: @*/
6203: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6204: {
6206:   dm->outputSequenceNum = num;
6207:   dm->outputSequenceVal = val;
6208:   return 0;
6209: }

6211: /*@C
6212:  DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`

6214:   Input Parameters:
6215: + dm   - The original `DM`
6216: . name - The sequence name
6217: - num  - The output sequence number

6219:   Output Parameter:
6220: . val  - The output sequence value

6222:   Level: intermediate

6224:   Note:
6225:   This is intended for output that should appear in sequence, for instance
6226:   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.

6228:   Developer Note:
6229:   It is unclear at the user API level why a `DM` is needed as input

6231: .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6232: @*/
6233: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6234: {
6235:   PetscBool ishdf5;

6240:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5);
6241:   if (ishdf5) {
6242: #if defined(PETSC_HAVE_HDF5)
6243:     PetscScalar value;

6245:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
6246:     *val = PetscRealPart(value);
6247: #endif
6248:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6249:   return 0;
6250: }

6252: /*@
6253:   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel

6255:   Not collective

6257:   Input Parameter:
6258: . dm - The `DM`

6260:   Output Parameter:
6261: . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution

6263:   Level: beginner

6265: .seealso: `DMSetUseNatural()`, `DMCreate()`
6266: @*/
6267: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6268: {
6271:   *useNatural = dm->useNatural;
6272:   return 0;
6273: }

6275: /*@
6276:   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel

6278:   Collective on dm

6280:   Input Parameters:
6281:  + dm - The `DM`
6282: - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution

6284:   Note:
6285:   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`

6287:   Level: beginner

6289: .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6290: @*/
6291: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6292: {
6295:   dm->useNatural = useNatural;
6296:   return 0;
6297: }

6299: /*@C
6300:   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`

6302:   Not Collective

6304:   Input Parameters:
6305: + dm   - The `DM` object
6306: - name - The label name

6308:   Level: intermediate

6310: .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6311: @*/
6312: PetscErrorCode DMCreateLabel(DM dm, const char name[])
6313: {
6314:   PetscBool flg;
6315:   DMLabel   label;

6319:   DMHasLabel(dm, name, &flg);
6320:   if (!flg) {
6321:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6322:     DMAddLabel(dm, label);
6323:     DMLabelDestroy(&label);
6324:   }
6325:   return 0;
6326: }

6328: /*@C
6329:   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.

6331:   Not Collective

6333:   Input Parameters:
6334: + dm   - The `DM` object
6335: . l    - The index for the label
6336: - name - The label name

6338:   Level: intermediate

6340: .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6341: @*/
6342: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6343: {
6344:   DMLabelLink orig, prev = NULL;
6345:   DMLabel     label;
6346:   PetscInt    Nl, m;
6347:   PetscBool   flg, match;
6348:   const char *lname;

6352:   DMHasLabel(dm, name, &flg);
6353:   if (!flg) {
6354:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
6355:     DMAddLabel(dm, label);
6356:     DMLabelDestroy(&label);
6357:   }
6358:   DMGetNumLabels(dm, &Nl);
6360:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6361:     PetscObjectGetName((PetscObject)orig->label, &lname);
6362:     PetscStrcmp(name, lname, &match);
6363:     if (match) break;
6364:   }
6365:   if (m == l) return 0;
6366:   if (!m) dm->labels = orig->next;
6367:   else prev->next = orig->next;
6368:   if (!l) {
6369:     orig->next = dm->labels;
6370:     dm->labels = orig;
6371:   } else {
6372:     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6373:       ;
6374:     orig->next = prev->next;
6375:     prev->next = orig;
6376:   }
6377:   return 0;
6378: }

6380: /*@C
6381:   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default

6383:   Not Collective

6385:   Input Parameters:
6386: + dm   - The `DM` object
6387: . name - The label name
6388: - point - The mesh point

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

6393:   Level: beginner

6395: .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6396: @*/
6397: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6398: {
6399:   DMLabel label;

6403:   DMGetLabel(dm, name, &label);
6405:   DMLabelGetValue(label, point, value);
6406:   return 0;
6407: }

6409: /*@C
6410:   DMSetLabelValue - Add a point to a `DMLabel` with given value

6412:   Not Collective

6414:   Input Parameters:
6415: + dm   - The `DM` object
6416: . name - The label name
6417: . point - The mesh point
6418: - value - The label value for this point

6420:   Output Parameter:

6422:   Level: beginner

6424: .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6425: @*/
6426: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6427: {
6428:   DMLabel label;

6432:   DMGetLabel(dm, name, &label);
6433:   if (!label) {
6434:     DMCreateLabel(dm, name);
6435:     DMGetLabel(dm, name, &label);
6436:   }
6437:   DMLabelSetValue(label, point, value);
6438:   return 0;
6439: }

6441: /*@C
6442:   DMClearLabelValue - Remove a point from a `DMLabel` with given value

6444:   Not Collective

6446:   Input Parameters:
6447: + dm   - The `DM` object
6448: . name - The label name
6449: . point - The mesh point
6450: - value - The label value for this point

6452:   Level: beginner

6454: .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6455: @*/
6456: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6457: {
6458:   DMLabel label;

6462:   DMGetLabel(dm, name, &label);
6463:   if (!label) return 0;
6464:   DMLabelClearValue(label, point, value);
6465:   return 0;
6466: }

6468: /*@C
6469:   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`

6471:   Not Collective

6473:   Input Parameters:
6474: + dm   - The `DM` object
6475: - name - The label name

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

6480:   Level: beginner

6482:   Developer Note:
6483:   This should be renamed to something like `DMGetLabelNumValues()` or removed.

6485: .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6486: @*/
6487: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6488: {
6489:   DMLabel label;

6494:   DMGetLabel(dm, name, &label);
6495:   *size = 0;
6496:   if (!label) return 0;
6497:   DMLabelGetNumValues(label, size);
6498:   return 0;
6499: }

6501: /*@C
6502:   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`

6504:   Not Collective

6506:   Input Parameters:
6507: + mesh - The `DM` object
6508: - name - The label name

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

6513:   Level: beginner

6515: .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6516: @*/
6517: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6518: {
6519:   DMLabel label;

6524:   DMGetLabel(dm, name, &label);
6525:   *ids = NULL;
6526:   if (label) {
6527:     DMLabelGetValueIS(label, ids);
6528:   } else {
6529:     /* returning an empty IS */
6530:     ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids);
6531:   }
6532:   return 0;
6533: }

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

6538:   Not Collective

6540:   Input Parameters:
6541: + dm - The `DM` object
6542: . name - The label name
6543: - value - The stratum value

6545:   Output Parameter:
6546: . size - The number of points, also called the stratum size

6548:   Level: beginner

6550: .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6551: @*/
6552: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6553: {
6554:   DMLabel label;

6559:   DMGetLabel(dm, name, &label);
6560:   *size = 0;
6561:   if (!label) return 0;
6562:   DMLabelGetStratumSize(label, value, size);
6563:   return 0;
6564: }

6566: /*@C
6567:   DMGetStratumIS - Get the points in a label stratum

6569:   Not Collective

6571:   Input Parameters:
6572: + dm - The `DM` object
6573: . name - The label name
6574: - value - The stratum value

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

6579:   Level: beginner

6581: .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6582: @*/
6583: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6584: {
6585:   DMLabel label;

6590:   DMGetLabel(dm, name, &label);
6591:   *points = NULL;
6592:   if (!label) return 0;
6593:   DMLabelGetStratumIS(label, value, points);
6594:   return 0;
6595: }

6597: /*@C
6598:   DMSetStratumIS - Set the points in a label stratum

6600:   Not Collective

6602:   Input Parameters:
6603: + dm - The `DM` object
6604: . name - The label name
6605: . value - The stratum value
6606: - points - The stratum points

6608:   Level: beginner

6610: .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6611: @*/
6612: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6613: {
6614:   DMLabel label;

6619:   DMGetLabel(dm, name, &label);
6620:   if (!label) return 0;
6621:   DMLabelSetStratumIS(label, value, points);
6622:   return 0;
6623: }

6625: /*@C
6626:   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`

6628:   Not Collective

6630:   Input Parameters:
6631: + dm   - The `DM` object
6632: . name - The label name
6633: - value - The label value for this point

6635:   Output Parameter:

6637:   Level: beginner

6639: .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6640: @*/
6641: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6642: {
6643:   DMLabel label;

6647:   DMGetLabel(dm, name, &label);
6648:   if (!label) return 0;
6649:   DMLabelClearStratum(label, value);
6650:   return 0;
6651: }

6653: /*@
6654:   DMGetNumLabels - Return the number of labels defined by on the `DM`

6656:   Not Collective

6658:   Input Parameter:
6659: . dm   - The `DM` object

6661:   Output Parameter:
6662: . numLabels - the number of Labels

6664:   Level: intermediate

6666: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6667: @*/
6668: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6669: {
6670:   DMLabelLink next = dm->labels;
6671:   PetscInt    n    = 0;

6675:   while (next) {
6676:     ++n;
6677:     next = next->next;
6678:   }
6679:   *numLabels = n;
6680:   return 0;
6681: }

6683: /*@C
6684:   DMGetLabelName - Return the name of nth label

6686:   Not Collective

6688:   Input Parameters:
6689: + dm - The `DM` object
6690: - n  - the label number

6692:   Output Parameter:
6693: . name - the label name

6695:   Level: intermediate

6697:   Developer Note:
6698:   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.

6700: .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6701: @*/
6702: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6703: {
6704:   DMLabelLink next = dm->labels;
6705:   PetscInt    l    = 0;

6709:   while (next) {
6710:     if (l == n) {
6711:       PetscObjectGetName((PetscObject)next->label, name);
6712:       return 0;
6713:     }
6714:     ++l;
6715:     next = next->next;
6716:   }
6717:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6718: }

6720: /*@C
6721:   DMHasLabel - Determine whether the `DM` has a label of a given name

6723:   Not Collective

6725:   Input Parameters:
6726: + dm   - The `DM` object
6727: - name - The label name

6729:   Output Parameter:
6730: . hasLabel - `PETSC_TRUE` if the label is present

6732:   Level: intermediate

6734: .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6735: @*/
6736: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6737: {
6738:   DMLabelLink next = dm->labels;
6739:   const char *lname;

6744:   *hasLabel = PETSC_FALSE;
6745:   while (next) {
6746:     PetscObjectGetName((PetscObject)next->label, &lname);
6747:     PetscStrcmp(name, lname, hasLabel);
6748:     if (*hasLabel) break;
6749:     next = next->next;
6750:   }
6751:   return 0;
6752: }

6754: /*@C
6755:   DMGetLabel - Return the label of a given name, or NULL, from a `DM`

6757:   Not Collective

6759:   Input Parameters:
6760: + dm   - The `DM` object
6761: - name - The label name

6763:   Output Parameter:
6764: . label - The `DMLabel`, or NULL if the label is absent

6766:   Default labels in a `DMPLEX`:
6767: +   "depth"       - Holds the depth (co-dimension) of each mesh point
6768: .   "celltype"    - Holds the topological type of each cell
6769: .   "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6770: .   "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6771: .   "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6772: -  "Vertex Sets" - Mirrors the vertex sets defined by GMsh

6774:   Level: intermediate

6776: .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6777: @*/
6778: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6779: {
6780:   DMLabelLink next = dm->labels;
6781:   PetscBool   hasLabel;
6782:   const char *lname;

6787:   *label = NULL;
6788:   while (next) {
6789:     PetscObjectGetName((PetscObject)next->label, &lname);
6790:     PetscStrcmp(name, lname, &hasLabel);
6791:     if (hasLabel) {
6792:       *label = next->label;
6793:       break;
6794:     }
6795:     next = next->next;
6796:   }
6797:   return 0;
6798: }

6800: /*@C
6801:   DMGetLabelByNum - Return the nth label on a `DM`

6803:   Not Collective

6805:   Input Parameters:
6806: + dm - The `DM` object
6807: - n  - the label number

6809:   Output Parameter:
6810: . label - the label

6812:   Level: intermediate

6814: .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6815: @*/
6816: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6817: {
6818:   DMLabelLink next = dm->labels;
6819:   PetscInt    l    = 0;

6823:   while (next) {
6824:     if (l == n) {
6825:       *label = next->label;
6826:       return 0;
6827:     }
6828:     ++l;
6829:     next = next->next;
6830:   }
6831:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6832: }

6834: /*@C
6835:   DMAddLabel - Add the label to this `DM`

6837:   Not Collective

6839:   Input Parameters:
6840: + dm   - The `DM` object
6841: - label - The `DMLabel`

6843:   Level: developer

6845: .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6846: @*/
6847: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
6848: {
6849:   DMLabelLink l, *p, tmpLabel;
6850:   PetscBool   hasLabel;
6851:   const char *lname;
6852:   PetscBool   flg;

6855:   PetscObjectGetName((PetscObject)label, &lname);
6856:   DMHasLabel(dm, lname, &hasLabel);
6858:   PetscCalloc1(1, &tmpLabel);
6859:   tmpLabel->label  = label;
6860:   tmpLabel->output = PETSC_TRUE;
6861:   for (p = &dm->labels; (l = *p); p = &l->next) { }
6862:   *p = tmpLabel;
6863:   PetscObjectReference((PetscObject)label);
6864:   PetscStrcmp(lname, "depth", &flg);
6865:   if (flg) dm->depthLabel = label;
6866:   PetscStrcmp(lname, "celltype", &flg);
6867:   if (flg) dm->celltypeLabel = label;
6868:   return 0;
6869: }

6871: /*@C
6872:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

6874:   Not Collective

6876:   Input Parameters:
6877: + dm    - The `DM` object
6878: - label - The `DMLabel`, having the same name, to substitute

6880:   Default labels in a `DMPLEX`:
6881: +  "depth"       - Holds the depth (co-dimension) of each mesh point
6882: .  "celltype"    - Holds the topological type of each cell
6883: .  "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6884: .  "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6885: .  "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6886: - "Vertex Sets" - Mirrors the vertex sets defined by GMsh

6888:   Level: intermediate

6890: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6891: @*/
6892: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
6893: {
6894:   DMLabelLink next = dm->labels;
6895:   PetscBool   hasLabel, flg;
6896:   const char *name, *lname;

6900:   PetscObjectGetName((PetscObject)label, &name);
6901:   while (next) {
6902:     PetscObjectGetName((PetscObject)next->label, &lname);
6903:     PetscStrcmp(name, lname, &hasLabel);
6904:     if (hasLabel) {
6905:       PetscObjectReference((PetscObject)label);
6906:       PetscStrcmp(lname, "depth", &flg);
6907:       if (flg) dm->depthLabel = label;
6908:       PetscStrcmp(lname, "celltype", &flg);
6909:       if (flg) dm->celltypeLabel = label;
6910:       DMLabelDestroy(&next->label);
6911:       next->label = label;
6912:       break;
6913:     }
6914:     next = next->next;
6915:   }
6916:   return 0;
6917: }

6919: /*@C
6920:   DMRemoveLabel - Remove the label given by name from this `DM`

6922:   Not Collective

6924:   Input Parameters:
6925: + dm   - The `DM` object
6926: - name - The label name

6928:   Output Parameter:
6929: . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the
6930:           caller is responsible for calling `DMLabelDestroy()`.

6932:   Level: developer

6934: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
6935: @*/
6936: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
6937: {
6938:   DMLabelLink link, *pnext;
6939:   PetscBool   hasLabel;
6940:   const char *lname;

6944:   if (label) {
6946:     *label = NULL;
6947:   }
6948:   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6949:     PetscObjectGetName((PetscObject)link->label, &lname);
6950:     PetscStrcmp(name, lname, &hasLabel);
6951:     if (hasLabel) {
6952:       *pnext = link->next; /* Remove from list */
6953:       PetscStrcmp(name, "depth", &hasLabel);
6954:       if (hasLabel) dm->depthLabel = NULL;
6955:       PetscStrcmp(name, "celltype", &hasLabel);
6956:       if (hasLabel) dm->celltypeLabel = NULL;
6957:       if (label) *label = link->label;
6958:       else DMLabelDestroy(&link->label);
6959:       PetscFree(link);
6960:       break;
6961:     }
6962:   }
6963:   return 0;
6964: }

6966: /*@
6967:   DMRemoveLabelBySelf - Remove the label from this `DM`

6969:   Not Collective

6971:   Input Parameters:
6972: + dm   - The `DM` object
6973: . label - The `DMLabel` to be removed from the `DM`
6974: - failNotFound - Should it fail if the label is not found in the DM?

6976:   Level: developer

6978:   Note:
6979:   Only exactly the same instance is removed if found, name match is ignored.
6980:   If the `DM` has an exclusive reference to the label, the label gets destroyed and
6981:   *label nullified.

6983: .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
6984: @*/
6985: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
6986: {
6987:   DMLabelLink link, *pnext;
6988:   PetscBool   hasLabel = PETSC_FALSE;

6992:   if (!*label && !failNotFound) return 0;
6995:   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
6996:     if (*label == link->label) {
6997:       hasLabel = PETSC_TRUE;
6998:       *pnext   = link->next; /* Remove from list */
6999:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7000:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7001:       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7002:       DMLabelDestroy(&link->label);
7003:       PetscFree(link);
7004:       break;
7005:     }
7006:   }
7008:   return 0;
7009: }

7011: /*@C
7012:   DMGetLabelOutput - Get the output flag for a given label

7014:   Not Collective

7016:   Input Parameters:
7017: + dm   - The `DM` object
7018: - name - The label name

7020:   Output Parameter:
7021: . output - The flag for output

7023:   Level: developer

7025: .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7026: @*/
7027: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7028: {
7029:   DMLabelLink next = dm->labels;
7030:   const char *lname;

7035:   while (next) {
7036:     PetscBool flg;

7038:     PetscObjectGetName((PetscObject)next->label, &lname);
7039:     PetscStrcmp(name, lname, &flg);
7040:     if (flg) {
7041:       *output = next->output;
7042:       return 0;
7043:     }
7044:     next = next->next;
7045:   }
7046:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7047: }

7049: /*@C
7050:   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`

7052:   Not Collective

7054:   Input Parameters:
7055: + dm     - The `DM` object
7056: . name   - The label name
7057: - output - `PETSC_TRUE` to save the label to the viewer

7059:   Level: developer

7061: .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7062: @*/
7063: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7064: {
7065:   DMLabelLink next = dm->labels;
7066:   const char *lname;

7070:   while (next) {
7071:     PetscBool flg;

7073:     PetscObjectGetName((PetscObject)next->label, &lname);
7074:     PetscStrcmp(name, lname, &flg);
7075:     if (flg) {
7076:       next->output = output;
7077:       return 0;
7078:     }
7079:     next = next->next;
7080:   }
7081:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7082: }

7084: /*@
7085:   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points

7087:   Collective on dmA

7089:   Input Parameters:
7090: + dmA - The `DM` object with initial labels
7091: . dmB - The `DM` object to which labels are copied
7092: . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7093: . all  - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7094: - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)

7096:   Level: intermediate

7098:   Note:
7099:   This is typically used when interpolating or otherwise adding to a mesh, or testing.

7101: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7102: @*/
7103: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7104: {
7105:   DMLabel     label, labelNew, labelOld;
7106:   const char *name;
7107:   PetscBool   flg;
7108:   DMLabelLink link;

7115:   if (dmA == dmB) return 0;
7116:   for (link = dmA->labels; link; link = link->next) {
7117:     label = link->label;
7118:     PetscObjectGetName((PetscObject)label, &name);
7119:     if (!all) {
7120:       PetscStrcmp(name, "depth", &flg);
7121:       if (flg) continue;
7122:       PetscStrcmp(name, "dim", &flg);
7123:       if (flg) continue;
7124:       PetscStrcmp(name, "celltype", &flg);
7125:       if (flg) continue;
7126:     }
7127:     DMGetLabel(dmB, name, &labelOld);
7128:     if (labelOld) {
7129:       switch (emode) {
7130:       case DM_COPY_LABELS_KEEP:
7131:         continue;
7132:       case DM_COPY_LABELS_REPLACE:
7133:         DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
7134:         break;
7135:       case DM_COPY_LABELS_FAIL:
7136:         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7137:       default:
7138:         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7139:       }
7140:     }
7141:     if (mode == PETSC_COPY_VALUES) {
7142:       DMLabelDuplicate(label, &labelNew);
7143:     } else {
7144:       labelNew = label;
7145:     }
7146:     DMAddLabel(dmB, labelNew);
7147:     if (mode == PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
7148:   }
7149:   return 0;
7150: }

7152: /*@C
7153:   DMCompareLabels - Compare labels of two `DMPLEX` meshes

7155:   Collective

7157:   Input Parameters:
7158: + dm0 - First `DM` object
7159: - dm1 - Second `DM` object

7161:   Output Parameters
7162: + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7163: - message - (Optional) Message describing the difference, or NULL if there is no difference

7165:   Level: intermediate

7167:   Notes:
7168:   The output flag equal will be the same on all processes.

7170:   If equal is passed as NULL and difference is found, an error is thrown on all processes.

7172:   Make sure to pass equal is NULL on all processes or none of them.

7174:   The output message is set independently on each rank.

7176:   message must be freed with `PetscFree()`

7178:   If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner.

7180:   Make sure to pass message as NULL on all processes or no processes.

7182:   Labels are matched by name. If the number of labels and their names are equal,
7183:   `DMLabelCompare()` is used to compare each pair of labels with the same name.

7185:   Fortran Note:
7186:   This function is not available from Fortran.

7188: .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7189: @*/
7190: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7191: {
7192:   PetscInt    n, i;
7193:   char        msg[PETSC_MAX_PATH_LEN] = "";
7194:   PetscBool   eq;
7195:   MPI_Comm    comm;
7196:   PetscMPIInt rank;

7203:   PetscObjectGetComm((PetscObject)dm0, &comm);
7204:   MPI_Comm_rank(comm, &rank);
7205:   {
7206:     PetscInt n1;

7208:     DMGetNumLabels(dm0, &n);
7209:     DMGetNumLabels(dm1, &n1);
7210:     eq = (PetscBool)(n == n1);
7211:     if (!eq) PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1);
7212:     MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7213:     if (!eq) goto finish;
7214:   }
7215:   for (i = 0; i < n; i++) {
7216:     DMLabel     l0, l1;
7217:     const char *name;
7218:     char       *msgInner;

7220:     /* Ignore label order */
7221:     DMGetLabelByNum(dm0, i, &l0);
7222:     PetscObjectGetName((PetscObject)l0, &name);
7223:     DMGetLabel(dm1, name, &l1);
7224:     if (!l1) {
7225:       PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i);
7226:       eq = PETSC_FALSE;
7227:       break;
7228:     }
7229:     DMLabelCompare(comm, l0, l1, &eq, &msgInner);
7230:     PetscStrncpy(msg, msgInner, sizeof(msg));
7231:     PetscFree(msgInner);
7232:     if (!eq) break;
7233:   }
7234:   MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
7235: finish:
7236:   /* If message output arg not set, print to stderr */
7237:   if (message) {
7238:     *message = NULL;
7239:     if (msg[0]) PetscStrallocpy(msg, message);
7240:   } else {
7241:     if (msg[0]) PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
7242:     PetscSynchronizedFlush(comm, PETSC_STDERR);
7243:   }
7244:   /* If same output arg not ser and labels are not equal, throw error */
7245:   if (equal) *equal = eq;
7247:   return 0;
7248: }

7250: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7251: {
7253:   if (!*label) {
7254:     DMCreateLabel(dm, name);
7255:     DMGetLabel(dm, name, label);
7256:   }
7257:   DMLabelSetValue(*label, point, value);
7258:   return 0;
7259: }

7261: /*
7262:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7263:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7264:   (label, id) pair in the DM.

7266:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7267:   each label.
7268: */
7269: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7270: {
7271:   DMUniversalLabel ul;
7272:   PetscBool       *active;
7273:   PetscInt         pStart, pEnd, p, Nl, l, m;

7275:   PetscMalloc1(1, &ul);
7276:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
7277:   DMGetNumLabels(dm, &Nl);
7278:   PetscCalloc1(Nl, &active);
7279:   ul->Nl = 0;
7280:   for (l = 0; l < Nl; ++l) {
7281:     PetscBool   isdepth, iscelltype;
7282:     const char *name;

7284:     DMGetLabelName(dm, l, &name);
7285:     PetscStrncmp(name, "depth", 6, &isdepth);
7286:     PetscStrncmp(name, "celltype", 9, &iscelltype);
7287:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7288:     if (active[l]) ++ul->Nl;
7289:   }
7290:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks);
7291:   ul->Nv = 0;
7292:   for (l = 0, m = 0; l < Nl; ++l) {
7293:     DMLabel     label;
7294:     PetscInt    nv;
7295:     const char *name;

7297:     if (!active[l]) continue;
7298:     DMGetLabelName(dm, l, &name);
7299:     DMGetLabelByNum(dm, l, &label);
7300:     DMLabelGetNumValues(label, &nv);
7301:     PetscStrallocpy(name, &ul->names[m]);
7302:     ul->indices[m] = l;
7303:     ul->Nv += nv;
7304:     ul->offsets[m + 1] = nv;
7305:     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7306:     ++m;
7307:   }
7308:   for (l = 1; l <= ul->Nl; ++l) {
7309:     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7310:     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7311:   }
7312:   for (l = 0; l < ul->Nl; ++l) {
7313:     PetscInt b;

7315:     ul->masks[l] = 0;
7316:     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7317:   }
7318:   PetscMalloc1(ul->Nv, &ul->values);
7319:   for (l = 0, m = 0; l < Nl; ++l) {
7320:     DMLabel         label;
7321:     IS              valueIS;
7322:     const PetscInt *varr;
7323:     PetscInt        nv, v;

7325:     if (!active[l]) continue;
7326:     DMGetLabelByNum(dm, l, &label);
7327:     DMLabelGetNumValues(label, &nv);
7328:     DMLabelGetValueIS(label, &valueIS);
7329:     ISGetIndices(valueIS, &varr);
7330:     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7331:     ISRestoreIndices(valueIS, &varr);
7332:     ISDestroy(&valueIS);
7333:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
7334:     ++m;
7335:   }
7336:   DMPlexGetChart(dm, &pStart, &pEnd);
7337:   for (p = pStart; p < pEnd; ++p) {
7338:     PetscInt  uval   = 0;
7339:     PetscBool marked = PETSC_FALSE;

7341:     for (l = 0, m = 0; l < Nl; ++l) {
7342:       DMLabel  label;
7343:       PetscInt val, defval, loc, nv;

7345:       if (!active[l]) continue;
7346:       DMGetLabelByNum(dm, l, &label);
7347:       DMLabelGetValue(label, p, &val);
7348:       DMLabelGetDefaultValue(label, &defval);
7349:       if (val == defval) {
7350:         ++m;
7351:         continue;
7352:       }
7353:       nv     = ul->offsets[m + 1] - ul->offsets[m];
7354:       marked = PETSC_TRUE;
7355:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
7357:       uval += (loc + 1) << ul->bits[m];
7358:       ++m;
7359:     }
7360:     if (marked) DMLabelSetValue(ul->label, p, uval);
7361:   }
7362:   PetscFree(active);
7363:   *universal = ul;
7364:   return 0;
7365: }

7367: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7368: {
7369:   PetscInt l;

7371:   for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
7372:   DMLabelDestroy(&(*universal)->label);
7373:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
7374:   PetscFree((*universal)->values);
7375:   PetscFree(*universal);
7376:   *universal = NULL;
7377:   return 0;
7378: }

7380: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7381: {
7383:   *ulabel = ul->label;
7384:   return 0;
7385: }

7387: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7388: {
7389:   PetscInt Nl = ul->Nl, l;

7392:   for (l = 0; l < Nl; ++l) {
7393:     if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
7394:     else DMCreateLabel(dm, ul->names[l]);
7395:   }
7396:   if (preserveOrder) {
7397:     for (l = 0; l < ul->Nl; ++l) {
7398:       const char *name;
7399:       PetscBool   match;

7401:       DMGetLabelName(dm, ul->indices[l], &name);
7402:       PetscStrcmp(name, ul->names[l], &match);
7404:     }
7405:   }
7406:   return 0;
7407: }

7409: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7410: {
7411:   PetscInt l;

7413:   for (l = 0; l < ul->Nl; ++l) {
7414:     DMLabel  label;
7415:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

7417:     if (lval) {
7418:       if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
7419:       else DMGetLabel(dm, ul->names[l], &label);
7420:       DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]);
7421:     }
7422:   }
7423:   return 0;
7424: }

7426: /*@
7427:   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement

7429:   Not collective

7431:   Input Parameter:
7432: . dm - The `DM` object

7434:   Output Parameter:
7435: . cdm - The coarse `DM`

7437:   Level: intermediate

7439: .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7440: @*/
7441: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7442: {
7445:   *cdm = dm->coarseMesh;
7446:   return 0;
7447: }

7449: /*@
7450:   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement

7452:   Input Parameters:
7453: + dm - The `DM` object
7454: - cdm - The coarse `DM`

7456:   Level: intermediate

7458:   Note:
7459:   Normally this is set automatically by `DMRefine()`

7461: .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7462: @*/
7463: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7464: {
7467:   if (dm == cdm) cdm = NULL;
7468:   PetscObjectReference((PetscObject)cdm);
7469:   DMDestroy(&dm->coarseMesh);
7470:   dm->coarseMesh = cdm;
7471:   return 0;
7472: }

7474: /*@
7475:   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening

7477:   Input Parameter:
7478: . dm - The `DM` object

7480:   Output Parameter:
7481: . fdm - The fine `DM`

7483:   Level: intermediate

7485: .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7486: @*/
7487: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7488: {
7491:   *fdm = dm->fineMesh;
7492:   return 0;
7493: }

7495: /*@
7496:   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening

7498:   Input Parameters:
7499: + dm - The `DM` object
7500: - fdm - The fine `DM`

7502:   Level: developer

7504:   Note:
7505:   Normally this is set automatically by `DMCoarsen()`

7507: .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7508: @*/
7509: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7510: {
7513:   if (dm == fdm) fdm = NULL;
7514:   PetscObjectReference((PetscObject)fdm);
7515:   DMDestroy(&dm->fineMesh);
7516:   dm->fineMesh = fdm;
7517:   return 0;
7518: }

7520: /*@C
7521:   DMAddBoundary - Add a boundary condition to a model represented by a `DM`

7523:   Collective on dm

7525:   Input Parameters:
7526: + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7527: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7528: . name     - The BC name
7529: . label    - The label defining constrained points
7530: . Nv       - The number of `DMLabel` values for constrained points
7531: . values   - An array of values for constrained points
7532: . field    - The field to constrain
7533: . Nc       - The number of constrained field components (0 will constrain all fields)
7534: . comps    - An array of constrained component numbers
7535: . bcFunc   - A pointwise function giving boundary values
7536: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7537: - ctx      - An optional user context for bcFunc

7539:   Output Parameter:
7540: . bd          - (Optional) Boundary number

7542:   Options Database Keys:
7543: + -bc_<boundary name> <num> - Overrides the boundary ids
7544: - -bc_<boundary name>_comp <num> - Overrides the boundary components

7546:   Notes:
7547:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:

7549: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

7551:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:

7553: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7554: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7555: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7556: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

7558: + dim - the spatial dimension
7559: . Nf - the number of fields
7560: . uOff - the offset into u[] and u_t[] for each field
7561: . uOff_x - the offset into u_x[] for each field
7562: . u - each field evaluated at the current point
7563: . u_t - the time derivative of each field evaluated at the current point
7564: . u_x - the gradient of each field evaluated at the current point
7565: . aOff - the offset into a[] and a_t[] for each auxiliary field
7566: . aOff_x - the offset into a_x[] for each auxiliary field
7567: . a - each auxiliary field evaluated at the current point
7568: . a_t - the time derivative of each auxiliary field evaluated at the current point
7569: . a_x - the gradient of auxiliary each field evaluated at the current point
7570: . t - current time
7571: . x - coordinates of the current point
7572: . numConstants - number of constant parameters
7573: . constants - constant parameters
7574: - bcval - output values at the current point

7576:   Level: intermediate

7578: .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7579: @*/
7580: 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)
7581: {
7582:   PetscDS ds;

7591:   DMGetDS(dm, &ds);
7592:   /* Complete label */
7593:   if (label) {
7594:     PetscObject  obj;
7595:     PetscClassId id;

7597:     DMGetField(dm, field, NULL, &obj);
7598:     PetscObjectGetClassId(obj, &id);
7599:     if (id == PETSCFE_CLASSID) {
7600:       DM plex;

7602:       DMConvert(dm, DMPLEX, &plex);
7603:       if (plex) DMPlexLabelComplete(plex, label);
7604:       DMDestroy(&plex);
7605:     }
7606:   }
7607:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
7608:   return 0;
7609: }

7611: /* TODO Remove this since now the structures are the same */
7612: static PetscErrorCode DMPopulateBoundary(DM dm)
7613: {
7614:   PetscDS     ds;
7615:   DMBoundary *lastnext;
7616:   DSBoundary  dsbound;

7618:   DMGetDS(dm, &ds);
7619:   dsbound = ds->boundary;
7620:   if (dm->boundary) {
7621:     DMBoundary next = dm->boundary;

7623:     /* quick check to see if the PetscDS has changed */
7624:     if (next->dsboundary == dsbound) return 0;
7625:     /* the PetscDS has changed: tear down and rebuild */
7626:     while (next) {
7627:       DMBoundary b = next;

7629:       next = b->next;
7630:       PetscFree(b);
7631:     }
7632:     dm->boundary = NULL;
7633:   }

7635:   lastnext = &(dm->boundary);
7636:   while (dsbound) {
7637:     DMBoundary dmbound;

7639:     PetscNew(&dmbound);
7640:     dmbound->dsboundary = dsbound;
7641:     dmbound->label      = dsbound->label;
7642:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7643:     *lastnext = dmbound;
7644:     lastnext  = &(dmbound->next);
7645:     dsbound   = dsbound->next;
7646:   }
7647:   return 0;
7648: }

7650: /* TODO: missing manual page */
7651: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7652: {
7653:   DMBoundary b;

7657:   *isBd = PETSC_FALSE;
7658:   DMPopulateBoundary(dm);
7659:   b = dm->boundary;
7660:   while (b && !(*isBd)) {
7661:     DMLabel    label = b->label;
7662:     DSBoundary dsb   = b->dsboundary;
7663:     PetscInt   i;

7665:     if (label) {
7666:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
7667:     }
7668:     b = b->next;
7669:   }
7670:   return 0;
7671: }

7673: /*@C
7674:   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.

7676:   Collective on dm

7678:   Input Parameters:
7679: + dm      - The `DM`
7680: . time    - The time
7681: . funcs   - The coordinate functions to evaluate, one per field
7682: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7683: - mode    - The insertion mode for values

7685:   Output Parameter:
7686: . X - vector

7688:    Calling sequence of func:
7689: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7691: +  dim - The spatial dimension
7692: .  time - The time at which to sample
7693: .  x   - The coordinates
7694: .  Nc  - The number of components
7695: .  u   - The output field values
7696: -  ctx - optional user-defined function context

7698:   Level: developer

7700:   Developer Notes:
7701:   This API is specific to only particular usage of `DM`

7703:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7705: .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7706: @*/
7707: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7708: {
7709:   Vec localX;

7712:   DMGetLocalVector(dm, &localX);
7713:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
7714:   DMLocalToGlobalBegin(dm, localX, mode, X);
7715:   DMLocalToGlobalEnd(dm, localX, mode, X);
7716:   DMRestoreLocalVector(dm, &localX);
7717:   return 0;
7718: }

7720: /*@C
7721:   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.

7723:   Not collective

7725:   Input Parameters:
7726: + dm      - The `DM`
7727: . time    - The time
7728: . funcs   - The coordinate functions to evaluate, one per field
7729: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7730: - mode    - The insertion mode for values

7732:   Output Parameter:
7733: . localX - vector

7735:    Calling sequence of func:
7736: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7738: +  dim - The spatial dimension
7739: .  x   - The coordinates
7740: .  Nc  - The number of components
7741: .  u   - The output field values
7742: -  ctx - optional user-defined function context

7744:   Level: developer

7746:   Developer Notes:
7747:   This API is specific to only particular usage of `DM`

7749:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7751: .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7752: @*/
7753: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7754: {
7757:   (dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX);
7758:   return 0;
7759: }

7761: /*@C
7762:   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.

7764:   Collective on dm

7766:   Input Parameters:
7767: + dm      - The `DM`
7768: . time    - The time
7769: . label   - The `DMLabel` selecting the portion of the mesh for projection
7770: . funcs   - The coordinate functions to evaluate, one per field
7771: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
7772: - mode    - The insertion mode for values

7774:   Output Parameter:
7775: . X - vector

7777:    Calling sequence of func:
7778: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7780: +  dim - The spatial dimension
7781: .  x   - The coordinates
7782: .  Nc  - The number of components
7783: .  u   - The output field values
7784: -  ctx - optional user-defined function context

7786:   Level: developer

7788:   Developer Notes:
7789:   This API is specific to only particular usage of `DM`

7791:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7793: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
7794: @*/
7795: 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)
7796: {
7797:   Vec localX;

7800:   DMGetLocalVector(dm, &localX);
7801:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7802:   DMLocalToGlobalBegin(dm, localX, mode, X);
7803:   DMLocalToGlobalEnd(dm, localX, mode, X);
7804:   DMRestoreLocalVector(dm, &localX);
7805:   return 0;
7806: }

7808: /*@C
7809:   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.

7811:   Not collective

7813:   Input Parameters:
7814: + dm      - The `DM`
7815: . time    - The time
7816: . label   - The `DMLabel` selecting the portion of the mesh for projection
7817: . funcs   - The coordinate functions to evaluate, one per field
7818: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7819: - mode    - The insertion mode for values

7821:   Output Parameter:
7822: . localX - vector

7824:    Calling sequence of func:
7825: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

7827: +  dim - The spatial dimension
7828: .  x   - The coordinates
7829: .  Nc  - The number of components
7830: .  u   - The output field values
7831: -  ctx - optional user-defined function context

7833:   Level: developer

7835:   Developer Notes:
7836:   This API is specific to only particular usage of `DM`

7838:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7840: .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7841: @*/
7842: 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)
7843: {
7846:   (dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
7847:   return 0;
7848: }

7850: /*@C
7851:   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.

7853:   Not collective

7855:   Input Parameters:
7856: + dm      - The `DM`
7857: . time    - The time
7858: . localU  - The input field vector
7859: . funcs   - The functions to evaluate, one per field
7860: - mode    - The insertion mode for values

7862:   Output Parameter:
7863: . localX  - The output vector

7865:    Calling sequence of func:
7866: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7867: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7868: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7869: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7871: +  dim          - The spatial dimension
7872: .  Nf           - The number of input fields
7873: .  NfAux        - The number of input auxiliary fields
7874: .  uOff         - The offset of each field in u[]
7875: .  uOff_x       - The offset of each field in u_x[]
7876: .  u            - The field values at this point in space
7877: .  u_t          - The field time derivative at this point in space (or NULL)
7878: .  u_x          - The field derivatives at this point in space
7879: .  aOff         - The offset of each auxiliary field in u[]
7880: .  aOff_x       - The offset of each auxiliary field in u_x[]
7881: .  a            - The auxiliary field values at this point in space
7882: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7883: .  a_x          - The auxiliary field derivatives at this point in space
7884: .  t            - The current time
7885: .  x            - The coordinates of this point
7886: .  numConstants - The number of constants
7887: .  constants    - The value of each constant
7888: -  f            - The value of the function at this point in space

7890:   Note:
7891:   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.
7892:   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
7893:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7894:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7896:   Level: intermediate

7898:   Developer Notes:
7899:   This API is specific to only particular usage of `DM`

7901:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7903: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7904: @*/
7905: 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)
7906: {
7910:   (dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX);
7911:   return 0;
7912: }

7914: /*@C
7915:   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.

7917:   Not collective

7919:   Input Parameters:
7920: + dm      - The `DM`
7921: . time    - The time
7922: . label   - The `DMLabel` marking the portion of the domain to output
7923: . numIds  - The number of label ids to use
7924: . ids     - The label ids to use for marking
7925: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7926: . comps   - The components to set in the output, or NULL for all components
7927: . localU  - The input field vector
7928: . funcs   - The functions to evaluate, one per field
7929: - mode    - The insertion mode for values

7931:   Output Parameter:
7932: . localX  - The output vector

7934:    Calling sequence of func:
7935: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7936: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7937: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7938: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

7940: +  dim          - The spatial dimension
7941: .  Nf           - The number of input fields
7942: .  NfAux        - The number of input auxiliary fields
7943: .  uOff         - The offset of each field in u[]
7944: .  uOff_x       - The offset of each field in u_x[]
7945: .  u            - The field values at this point in space
7946: .  u_t          - The field time derivative at this point in space (or NULL)
7947: .  u_x          - The field derivatives at this point in space
7948: .  aOff         - The offset of each auxiliary field in u[]
7949: .  aOff_x       - The offset of each auxiliary field in u_x[]
7950: .  a            - The auxiliary field values at this point in space
7951: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
7952: .  a_x          - The auxiliary field derivatives at this point in space
7953: .  t            - The current time
7954: .  x            - The coordinates of this point
7955: .  numConstants - The number of constants
7956: .  constants    - The value of each constant
7957: -  f            - The value of the function at this point in space

7959:   Note:
7960:   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.
7961:   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
7962:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
7963:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

7965:   Level: intermediate

7967:   Developer Notes:
7968:   This API is specific to only particular usage of `DM`

7970:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

7972: .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
7973: @*/
7974: 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)
7975: {
7979:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
7980:   return 0;
7981: }

7983: /*@C
7984:   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.

7986:   Not collective

7988:   Input Parameters:
7989: + dm      - The `DM`
7990: . time    - The time
7991: . label   - The `DMLabel` marking the portion of the domain to output
7992: . numIds  - The number of label ids to use
7993: . ids     - The label ids to use for marking
7994: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
7995: . comps   - The components to set in the output, or NULL for all components
7996: . U       - The input field vector
7997: . funcs   - The functions to evaluate, one per field
7998: - mode    - The insertion mode for values

8000:   Output Parameter:
8001: . X       - The output vector

8003:    Calling sequence of func:
8004: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8005: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8006: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8007: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8009: +  dim          - The spatial dimension
8010: .  Nf           - The number of input fields
8011: .  NfAux        - The number of input auxiliary fields
8012: .  uOff         - The offset of each field in u[]
8013: .  uOff_x       - The offset of each field in u_x[]
8014: .  u            - The field values at this point in space
8015: .  u_t          - The field time derivative at this point in space (or NULL)
8016: .  u_x          - The field derivatives at this point in space
8017: .  aOff         - The offset of each auxiliary field in u[]
8018: .  aOff_x       - The offset of each auxiliary field in u_x[]
8019: .  a            - The auxiliary field values at this point in space
8020: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8021: .  a_x          - The auxiliary field derivatives at this point in space
8022: .  t            - The current time
8023: .  x            - The coordinates of this point
8024: .  numConstants - The number of constants
8025: .  constants    - The value of each constant
8026: -  f            - The value of the function at this point in space

8028:   Note:
8029:   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.
8030:   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
8031:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8032:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8034:   Level: intermediate

8036:   Developer Notes:
8037:   This API is specific to only particular usage of `DM`

8039:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8041: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8042: @*/
8043: 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)
8044: {
8045:   DM  dmIn;
8046:   Vec localU, localX;

8049:   VecGetDM(U, &dmIn);
8050:   DMGetLocalVector(dmIn, &localU);
8051:   DMGetLocalVector(dm, &localX);
8052:   DMGlobalToLocalBegin(dmIn, U, mode, localU);
8053:   DMGlobalToLocalEnd(dmIn, U, mode, localU);
8054:   DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8055:   DMLocalToGlobalBegin(dm, localX, mode, X);
8056:   DMLocalToGlobalEnd(dm, localX, mode, X);
8057:   DMRestoreLocalVector(dm, &localX);
8058:   DMRestoreLocalVector(dmIn, &localU);
8059:   return 0;
8060: }

8062: /*@C
8063:   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.

8065:   Not collective

8067:   Input Parameters:
8068: + dm      - The `DM`
8069: . time    - The time
8070: . label   - The `DMLabel` marking the portion of the domain boundary to output
8071: . numIds  - The number of label ids to use
8072: . ids     - The label ids to use for marking
8073: . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8074: . comps   - The components to set in the output, or NULL for all components
8075: . localU  - The input field vector
8076: . funcs   - The functions to evaluate, one per field
8077: - mode    - The insertion mode for values

8079:   Output Parameter:
8080: . localX  - The output vector

8082:    Calling sequence of func:
8083: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8084: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8085: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8086: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

8088: +  dim          - The spatial dimension
8089: .  Nf           - The number of input fields
8090: .  NfAux        - The number of input auxiliary fields
8091: .  uOff         - The offset of each field in u[]
8092: .  uOff_x       - The offset of each field in u_x[]
8093: .  u            - The field values at this point in space
8094: .  u_t          - The field time derivative at this point in space (or NULL)
8095: .  u_x          - The field derivatives at this point in space
8096: .  aOff         - The offset of each auxiliary field in u[]
8097: .  aOff_x       - The offset of each auxiliary field in u_x[]
8098: .  a            - The auxiliary field values at this point in space
8099: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8100: .  a_x          - The auxiliary field derivatives at this point in space
8101: .  t            - The current time
8102: .  x            - The coordinates of this point
8103: .  n            - The face normal
8104: .  numConstants - The number of constants
8105: .  constants    - The value of each constant
8106: -  f            - The value of the function at this point in space

8108:   Note:
8109:   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.
8110:   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
8111:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8112:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

8114:   Level: intermediate

8116:   Developer Notes:
8117:   This API is specific to only particular usage of `DM`

8119:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8121: .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8122: @*/
8123: 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)
8124: {
8128:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8129:   return 0;
8130: }

8132: /*@C
8133:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

8135:   Collective on dm

8137:   Input Parameters:
8138: + dm    - The `DM`
8139: . time  - The time
8140: . funcs - The functions to evaluate for each field component
8141: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8142: - X     - The coefficient vector u_h, a global vector

8144:   Output Parameter:
8145: . diff - The diff ||u - u_h||_2

8147:   Level: developer

8149:   Developer Notes:
8150:   This API is specific to only particular usage of `DM`

8152:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8154: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8155: @*/
8156: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8157: {
8160:   (dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff);
8161:   return 0;
8162: }

8164: /*@C
8165:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

8167:   Collective on dm

8169:   Input Parameters:
8170: + dm    - The `DM`
8171: , time  - The time
8172: . funcs - The gradient functions to evaluate for each field component
8173: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8174: . X     - The coefficient vector u_h, a global vector
8175: - n     - The vector to project along

8177:   Output Parameter:
8178: . diff - The diff ||(grad u - grad u_h) . n||_2

8180:   Level: developer

8182:   Developer Notes:
8183:   This API is specific to only particular usage of `DM`

8185:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8187: .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8188: @*/
8189: 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)
8190: {
8193:   (dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff);
8194:   return 0;
8195: }

8197: /*@C
8198:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

8200:   Collective on dm

8202:   Input Parameters:
8203: + dm    - The `DM`
8204: . time  - The time
8205: . funcs - The functions to evaluate for each field component
8206: . ctxs  - Optional array of contexts to pass to each function, or NULL.
8207: - X     - The coefficient vector u_h, a global vector

8209:   Output Parameter:
8210: . diff - The array of differences, ||u^f - u^f_h||_2

8212:   Level: developer

8214:   Developer Notes:
8215:   This API is specific to only particular usage of `DM`

8217:   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.

8219: .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8220: @*/
8221: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8222: {
8225:   (dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff);
8226:   return 0;
8227: }

8229: /*@C
8230:  DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors

8232:  Not Collective

8234:  Input Parameter:
8235: .  dm    - The `DM`

8237:  Output Parameters:
8238: +  nranks - the number of neighbours
8239: -  ranks - the neighbors ranks

8241:  Note:
8242:  Do not free the array, it is freed when the `DM` is destroyed.

8244:  Level: beginner

8246:  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8247: @*/
8248: PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8249: {
8251:   (dm->ops->getneighbors)(dm, nranks, ranks);
8252:   return 0;
8253: }

8255: #include <petsc/private/matimpl.h>

8257: /*
8258:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8259:     This has be a different function because it requires DM which is not defined in the Mat library
8260: */
8261: PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8262: {
8263:   if (coloring->ctype == IS_COLORING_LOCAL) {
8264:     Vec x1local;
8265:     DM  dm;
8266:     MatGetDM(J, &dm);
8268:     DMGetLocalVector(dm, &x1local);
8269:     DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local);
8270:     DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local);
8271:     x1 = x1local;
8272:   }
8273:   MatFDColoringApply_AIJ(J, coloring, x1, sctx);
8274:   if (coloring->ctype == IS_COLORING_LOCAL) {
8275:     DM dm;
8276:     MatGetDM(J, &dm);
8277:     DMRestoreLocalVector(dm, &x1);
8278:   }
8279:   return 0;
8280: }

8282: /*@
8283:     MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring

8285:     Input Parameter:
8286: .    coloring - the `MatFDColoring` object

8288:     Developer Note:
8289:     this routine exists because the PETSc `Mat` library does not know about the `DM` objects

8291:     Level: advanced

8293: .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8294: @*/
8295: PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8296: {
8297:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8298:   return 0;
8299: }

8301: /*@
8302:     DMGetCompatibility - determine if two `DM`s are compatible

8304:     Collective

8306:     Input Parameters:
8307: +    dm1 - the first `DM`
8308: -    dm2 - the second `DM`

8310:     Output Parameters:
8311: +    compatible - whether or not the two `DM`s are compatible
8312: -    set - whether or not the compatible value was actually determined and set

8314:     Notes:
8315:     Two `DM`s are deemed compatible if they represent the same parallel decomposition
8316:     of the same topology. This implies that the section (field data) on one
8317:     "makes sense" with respect to the topology and parallel decomposition of the other.
8318:     Loosely speaking, compatible `DM`s represent the same domain and parallel
8319:     decomposition, but hold different data.

8321:     Typically, one would confirm compatibility if intending to simultaneously iterate
8322:     over a pair of vectors obtained from different `DM`s.

8324:     For example, two `DMDA` objects are compatible if they have the same local
8325:     and global sizes and the same stencil width. They can have different numbers
8326:     of degrees of freedom per node. Thus, one could use the node numbering from
8327:     either `DM` in bounds for a loop over vectors derived from either `DM`.

8329:     Consider the operation of summing data living on a 2-dof `DMDA` to data living
8330:     on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8331: .vb
8332:   ...
8333:   DMGetCompatibility(da1,da2,&compatible,&set);
8334:   if (set && compatible)  {
8335:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
8336:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
8337:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
8338:     for (j=y; j<y+n; ++j) {
8339:       for (i=x; i<x+m, ++i) {
8340:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8341:       }
8342:     }
8343:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
8344:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
8345:   } else {
8346:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8347:   }
8348:   ...
8349: .ve

8351:     Checking compatibility might be expensive for a given implementation of `DM`,
8352:     or might be impossible to unambiguously confirm or deny. For this reason,
8353:     this function may decline to determine compatibility, and hence users should
8354:     always check the "set" output parameter.

8356:     A `DM` is always compatible with itself.

8358:     In the current implementation, `DM`s which live on "unequal" communicators
8359:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8360:     incompatible.

8362:     This function is labeled "Collective," as information about all subdomains
8363:     is required on each rank. However, in `DM` implementations which store all this
8364:     information locally, this function may be merely "Logically Collective".

8366:     Developer Note:
8367:     Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8368:     iff B is compatible with A. Thus, this function checks the implementations
8369:     of both dm and dmc (if they are of different types), attempting to determine
8370:     compatibility. It is left to `DM` implementers to ensure that symmetry is
8371:     preserved. The simplest way to do this is, when implementing type-specific
8372:     logic for this function, is to check for existing logic in the implementation
8373:     of other `DM` types and let *set = PETSC_FALSE if found.

8375:     Level: advanced

8377: .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8378: @*/
8379: PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8380: {
8381:   PetscMPIInt compareResult;
8382:   DMType      type, type2;
8383:   PetscBool   sameType;


8388:   /* Declare a DM compatible with itself */
8389:   if (dm1 == dm2) {
8390:     *set        = PETSC_TRUE;
8391:     *compatible = PETSC_TRUE;
8392:     return 0;
8393:   }

8395:   /* Declare a DM incompatible with a DM that lives on an "unequal"
8396:      communicator. Note that this does not preclude compatibility with
8397:      DMs living on "congruent" or "similar" communicators, but this must be
8398:      determined by the implementation-specific logic */
8399:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult);
8400:   if (compareResult == MPI_UNEQUAL) {
8401:     *set        = PETSC_TRUE;
8402:     *compatible = PETSC_FALSE;
8403:     return 0;
8404:   }

8406:   /* Pass to the implementation-specific routine, if one exists. */
8407:   if (dm1->ops->getcompatibility) {
8408:     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8409:     if (*set) return 0;
8410:   }

8412:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8413:      with an implementation of this function from dm2 */
8414:   DMGetType(dm1, &type);
8415:   DMGetType(dm2, &type2);
8416:   PetscStrcmp(type, type2, &sameType);
8417:   if (!sameType && dm2->ops->getcompatibility) {
8418:     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8419:   } else {
8420:     *set = PETSC_FALSE;
8421:   }
8422:   return 0;
8423: }

8425: /*@C
8426:   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.

8428:   Logically Collective on dm

8430:   Input Parameters:
8431: + DM - the `DM`
8432: . f - the monitor function
8433: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8434: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

8436:   Options Database Keys:
8437: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8438:                             does not cancel those set via the options database.

8440:   Note:
8441:   Several different monitoring routines may be set by calling
8442:   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8443:   order in which they were set.

8445:   Fortran Note:
8446:   Only a single monitor function can be set for each `DM` object

8448:   Developer Note:
8449:   This API has a generic name but seems specific to a very particular aspect of the use of `DM`

8451:   Level: intermediate

8453: .seealso: `DMMonitorCancel()`,`DMMonitorSetFromOptions()`, `DMMonitor()`
8454: @*/
8455: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8456: {
8457:   PetscInt m;

8460:   for (m = 0; m < dm->numbermonitors; ++m) {
8461:     PetscBool identical;

8463:     PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
8464:     if (identical) return 0;
8465:   }
8467:   dm->monitor[dm->numbermonitors]          = f;
8468:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8469:   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8470:   return 0;
8471: }

8473: /*@
8474:   DMMonitorCancel - Clears all the monitor functions for a `DM` object.

8476:   Logically Collective on dm

8478:   Input Parameter:
8479: . dm - the DM

8481:   Options Database Key:
8482: . -dm_monitor_cancel - cancels all monitors that have been hardwired
8483:   into a code by calls to `DMonitorSet()`, but does not cancel those
8484:   set via the options database

8486:   Note:
8487:   There is no way to clear one specific monitor from a `DM` object.

8489:   Level: intermediate

8491: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`,  `DMMonitor()`
8492: @*/
8493: PetscErrorCode DMMonitorCancel(DM dm)
8494: {
8495:   PetscInt m;

8498:   for (m = 0; m < dm->numbermonitors; ++m) {
8499:     if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
8500:   }
8501:   dm->numbermonitors = 0;
8502:   return 0;
8503: }

8505: /*@C
8506:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

8508:   Collective on dm

8510:   Input Parameters:
8511: + dm   - `DM` object you wish to monitor
8512: . name - the monitor type one is seeking
8513: . help - message indicating what monitoring is done
8514: . manual - manual page for the monitor
8515: . monitor - the monitor function
8516: - 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

8518:   Output Parameter:
8519: . flg - Flag set if the monitor was created

8521:   Level: developer

8523: .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8524:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8525:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8526:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8527:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8528:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8529:           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8530: @*/
8531: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8532: {
8533:   PetscViewer       viewer;
8534:   PetscViewerFormat format;

8537:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg);
8538:   if (*flg) {
8539:     PetscViewerAndFormat *vf;

8541:     PetscViewerAndFormatCreate(viewer, format, &vf);
8542:     PetscObjectDereference((PetscObject)viewer);
8543:     if (monitorsetup) (*monitorsetup)(dm, vf);
8544:     DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy);
8545:   }
8546:   return 0;
8547: }

8549: /*@
8550:    DMMonitor - runs the user provided monitor routines, if they exist

8552:    Collective on dm

8554:    Input Parameters:
8555: .  dm - The `DM`

8557:    Level: developer

8559:    Question:
8560:    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
8561:    since some `DM` have no concept of discretization

8563: .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8564: @*/
8565: PetscErrorCode DMMonitor(DM dm)
8566: {
8567:   PetscInt m;

8569:   if (!dm) return 0;
8571:   for (m = 0; m < dm->numbermonitors; ++m) (*dm->monitor[m])(dm, dm->monitorcontext[m]);
8572:   return 0;
8573: }

8575: /*@
8576:   DMComputeError - Computes the error assuming the user has provided the exact solution functions

8578:   Collective on dm

8580:   Input Parameters:
8581: + dm     - The `DM`
8582: - sol    - The solution vector

8584:   Input/Output Parameter:
8585: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
8586:            contains the error in each field

8588:   Output Parameter:
8589: . errorVec - A vector to hold the cellwise error (may be NULL)

8591:   Note:
8592:   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.

8594:   Level: developer

8596: .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8597: @*/
8598: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8599: {
8600:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8601:   void    **ctxs;
8602:   PetscReal time;
8603:   PetscInt  Nf, f, Nds, s;

8605:   DMGetNumFields(dm, &Nf);
8606:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
8607:   DMGetNumDS(dm, &Nds);
8608:   for (s = 0; s < Nds; ++s) {
8609:     PetscDS         ds;
8610:     DMLabel         label;
8611:     IS              fieldIS;
8612:     const PetscInt *fields;
8613:     PetscInt        dsNf;

8615:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
8616:     PetscDSGetNumFields(ds, &dsNf);
8617:     if (fieldIS) ISGetIndices(fieldIS, &fields);
8618:     for (f = 0; f < dsNf; ++f) {
8619:       const PetscInt field = fields[f];
8620:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
8621:     }
8622:     if (fieldIS) ISRestoreIndices(fieldIS, &fields);
8623:   }
8625:   DMGetOutputSequenceNumber(dm, NULL, &time);
8626:   if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
8627:   if (errorVec) {
8628:     DM             edm;
8629:     DMPolytopeType ct;
8630:     PetscBool      simplex;
8631:     PetscInt       dim, cStart, Nf;

8633:     DMClone(dm, &edm);
8634:     DMGetDimension(edm, &dim);
8635:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
8636:     DMPlexGetCellType(dm, cStart, &ct);
8637:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8638:     DMGetNumFields(dm, &Nf);
8639:     for (f = 0; f < Nf; ++f) {
8640:       PetscFE         fe, efe;
8641:       PetscQuadrature q;
8642:       const char     *name;

8644:       DMGetField(dm, f, NULL, (PetscObject *)&fe);
8645:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
8646:       PetscObjectGetName((PetscObject)fe, &name);
8647:       PetscObjectSetName((PetscObject)efe, name);
8648:       PetscFEGetQuadrature(fe, &q);
8649:       PetscFESetQuadrature(efe, q);
8650:       DMSetField(edm, f, NULL, (PetscObject)efe);
8651:       PetscFEDestroy(&efe);
8652:     }
8653:     DMCreateDS(edm);

8655:     DMCreateGlobalVector(edm, errorVec);
8656:     PetscObjectSetName((PetscObject)*errorVec, "Error");
8657:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
8658:     DMDestroy(&edm);
8659:   }
8660:   PetscFree2(exactSol, ctxs);
8661:   return 0;
8662: }

8664: /*@
8665:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`

8667:   Not collective

8669:   Input Parameter:
8670: . dm     - The `DM`

8672:   Output Parameter:
8673: . numAux - The number of auxiliary data vectors

8675:   Level: advanced

8677: .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8678: @*/
8679: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8680: {
8682:   PetscHMapAuxGetSize(dm->auxData, numAux);
8683:   return 0;
8684: }

8686: /*@
8687:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part

8689:   Not collective

8691:   Input Parameters:
8692: + dm     - The `DM`
8693: . label  - The `DMLabel`
8694: . value  - The label value indicating the region
8695: - part   - The equation part, or 0 if unused

8697:   Output Parameter:
8698: . aux    - The `Vec` holding auxiliary field data

8700:   Note:
8701:   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.

8703:   Level: advanced

8705: .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8706: @*/
8707: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8708: {
8709:   PetscHashAuxKey key, wild = {NULL, 0, 0};
8710:   PetscBool       has;

8714:   key.label = label;
8715:   key.value = value;
8716:   key.part  = part;
8717:   PetscHMapAuxHas(dm->auxData, key, &has);
8718:   if (has) PetscHMapAuxGet(dm->auxData, key, aux);
8719:   else PetscHMapAuxGet(dm->auxData, wild, aux);
8720:   return 0;
8721: }

8723: /*@
8724:   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part

8726:   Not collective because auxilary vectors are not parallel

8728:   Input Parameters:
8729: + dm     - The `DM`
8730: . label  - The `DMLabel`
8731: . value  - The label value indicating the region
8732: . part   - The equation part, or 0 if unused
8733: - aux    - The `Vec` holding auxiliary field data

8735:   Level: advanced

8737: .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8738: @*/
8739: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8740: {
8741:   Vec             old;
8742:   PetscHashAuxKey key;

8746:   key.label = label;
8747:   key.value = value;
8748:   key.part  = part;
8749:   PetscHMapAuxGet(dm->auxData, key, &old);
8750:   PetscObjectReference((PetscObject)aux);
8751:   PetscObjectDereference((PetscObject)old);
8752:   if (!aux) PetscHMapAuxDel(dm->auxData, key);
8753:   else PetscHMapAuxSet(dm->auxData, key, aux);
8754:   return 0;
8755: }

8757: /*@C
8758:   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`

8760:   Not collective

8762:   Input Parameter:
8763: . dm      - The `DM`

8765:   Output Parameters:
8766: + labels  - The `DMLabel`s for each `Vec`
8767: . values  - The label values for each `Vec`
8768: - parts   - The equation parts for each `Vec`

8770:   Note:
8771:   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.

8773:   Level: advanced

8775: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
8776: @*/
8777: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
8778: {
8779:   PetscHashAuxKey *keys;
8780:   PetscInt         n, i, off = 0;

8786:   DMGetNumAuxiliaryVec(dm, &n);
8787:   PetscMalloc1(n, &keys);
8788:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
8789:   for (i = 0; i < n; ++i) {
8790:     labels[i] = keys[i].label;
8791:     values[i] = keys[i].value;
8792:     parts[i]  = keys[i].part;
8793:   }
8794:   PetscFree(keys);
8795:   return 0;
8796: }

8798: /*@
8799:   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`

8801:   Not collective

8803:   Input Parameter:
8804: . dm    - The `DM`

8806:   Output Parameter:
8807: . dmNew - The new `DM`, now with the same auxiliary data

8809:   Level: advanced

8811:   Note:
8812:   This is a shallow copy of the auxiliary vectors

8814: .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8815: @*/
8816: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
8817: {
8819:   PetscHMapAuxDestroy(&dmNew->auxData);
8820:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
8821:   return 0;
8822: }

8824: /*@C
8825:   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement

8827:   Not collective

8829:   Input Parameters:
8830: + ct         - The `DMPolytopeType`
8831: . sourceCone - The source arrangement of faces
8832: - targetCone - The target arrangement of faces

8834:   Output Parameters:
8835: + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
8836: - found - Flag indicating that a suitable orientation was found

8838:   Level: advanced

8840:   Note:
8841:   An arrangement is a face order combined with an orientation for each face

8843:   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8844:   that labels each arrangement (face ordering plus orientation for each face).

8846:   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement

8848: .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
8849: @*/
8850: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
8851: {
8852:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
8853:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8854:   PetscInt       o, c;

8856:   if (!nO) {
8857:     *ornt  = 0;
8858:     *found = PETSC_TRUE;
8859:     return 0;
8860:   }
8861:   for (o = -nO; o < nO; ++o) {
8862:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

8864:     for (c = 0; c < cS; ++c)
8865:       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
8866:     if (c == cS) {
8867:       *ornt = o;
8868:       break;
8869:     }
8870:   }
8871:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8872:   return 0;
8873: }

8875: /*@C
8876:   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement

8878:   Not collective

8880:   Input Parameters:
8881: + ct         - The `DMPolytopeType`
8882: . sourceCone - The source arrangement of faces
8883: - targetCone - The target arrangement of faces

8885:   Output Parameters:
8886: . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement

8888:   Level: advanced

8890:   Note:
8891:   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.

8893:   Developer Note:
8894:   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found

8896: .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
8897: @*/
8898: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8899: {
8900:   PetscBool found;

8902:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
8904:   return 0;
8905: }

8907: /*@C
8908:   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement

8910:   Not collective

8912:   Input Parameters:
8913: + ct         - The `DMPolytopeType`
8914: . sourceVert - The source arrangement of vertices
8915: - targetVert - The target arrangement of vertices

8917:   Output Parameters:
8918: + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
8919: - found - Flag indicating that a suitable orientation was found

8921:   Level: advanced

8923:   Note:
8924:   An arrangement is a vertex order

8926:   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
8927:   that labels each arrangement (vertex ordering).

8929:   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement

8931: .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
8932: @*/
8933: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
8934: {
8935:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
8936:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
8937:   PetscInt       o, c;

8939:   if (!nO) {
8940:     *ornt  = 0;
8941:     *found = PETSC_TRUE;
8942:     return 0;
8943:   }
8944:   for (o = -nO; o < nO; ++o) {
8945:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

8947:     for (c = 0; c < cS; ++c)
8948:       if (sourceVert[arr[c]] != targetVert[c]) break;
8949:     if (c == cS) {
8950:       *ornt = o;
8951:       break;
8952:     }
8953:   }
8954:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
8955:   return 0;
8956: }

8958: /*@C
8959:   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement

8961:   Not collective

8963:   Input Parameters:
8964: + ct         - The `DMPolytopeType`
8965: . sourceCone - The source arrangement of vertices
8966: - targetCone - The target arrangement of vertices

8968:   Output Parameters:
8969: . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement

8971:   Level: advanced

8973:   Note:
8974:   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.

8976:   Developer Note:
8977:   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found

8979: .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
8980: @*/
8981: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
8982: {
8983:   PetscBool found;

8985:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
8987:   return 0;
8988: }

8990: /*@C
8991:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

8993:   Not collective

8995:   Input Parameters:
8996: + ct    - The `DMPolytopeType`
8997: - point - Coordinates of the point

8999:   Output Parameters:
9000: . inside  - Flag indicating whether the point is inside the reference cell of given type

9002:   Level: advanced

9004: .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
9005: @*/
9006: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9007: {
9008:   PetscReal sum = 0.0;
9009:   PetscInt  d;

9011:   *inside = PETSC_TRUE;
9012:   switch (ct) {
9013:   case DM_POLYTOPE_TRIANGLE:
9014:   case DM_POLYTOPE_TETRAHEDRON:
9015:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9016:       if (point[d] < -1.0) {
9017:         *inside = PETSC_FALSE;
9018:         break;
9019:       }
9020:       sum += point[d];
9021:     }
9022:     if (sum > PETSC_SMALL) {
9023:       *inside = PETSC_FALSE;
9024:       break;
9025:     }
9026:     break;
9027:   case DM_POLYTOPE_QUADRILATERAL:
9028:   case DM_POLYTOPE_HEXAHEDRON:
9029:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9030:       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9031:         *inside = PETSC_FALSE;
9032:         break;
9033:       }
9034:     break;
9035:   default:
9036:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9037:   }
9038:   return 0;
9039: }