Actual source code: dm.c

      1: #include <petscvec.h>
      2: #include <petsc/private/dmimpl.h>
      3: #include <petsc/private/dmlabelimpl.h>
      4: #include <petsc/private/petscdsimpl.h>
      5: #include <petscdmplex.h>
      6: #include <petscdmfield.h>
      7: #include <petscsf.h>
      8: #include <petscds.h>

     10: #ifdef PETSC_HAVE_LIBCEED
     11: #include <petscfeceed.h>
     12: #endif

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

     18: PetscClassId  DM_CLASSID;
     19: PetscClassId  DMLABEL_CLASSID;
     20: PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_Load, DM_AdaptInterpolator;

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

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

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

     33:   Collective

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

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

     41:   Level: beginner

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

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

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

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

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

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

    104:   Collective

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

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

    112:   Level: beginner

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

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

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

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

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

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

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

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

    196:    Logically Collective on da

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

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

    205:    Level: intermediate

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

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

    220:    Logically Collective on da

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

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

    228:    Level: intermediate

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

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

    242:   Not collective

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

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

    250:   Level: intermediate

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

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

    265:   Not collective

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

    271:   Note: This is NOT the same as DMCreateGlobalVector() since it does not change the view methods or perform other customization, but merely sets the DM member.

    273:   Level: intermediate

    275: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    276: @*/
    277: PetscErrorCode VecSetDM(Vec v, DM dm)
    278: {
    281:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
    282:   return 0;
    283: }

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

    288:    Logically Collective on dm

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

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

    297:    Level: intermediate

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

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

    312:    Logically Collective on dm

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

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

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

    323:    Level: intermediate

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

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

    338:    Logically Collective on dm

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

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

    347:    Level: intermediate

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

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

    362:    Logically Collective on dm

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

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

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

    373:    Level: intermediate

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

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

    387:   Not collective

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

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

    395:   Level: intermediate

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

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

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

    413:   Not collective

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

    419:   Level: intermediate

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

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

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

    438:    Logically Collective on dm

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

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

    448:    Level: advanced

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

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

    469:    Logically Collective on dm

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

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

    479:    Level: advanced

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

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

    494:    Not Collective

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

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

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

    506:    Level: advanced

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

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

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

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

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

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

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

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

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

    565:     Collective on dm

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

    570:     Level: developer

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

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

    580:   if (!*dm) return 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

    756:     Collective on dm

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

    761:     Level: developer

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

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

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

    780:     Collective on dm

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

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

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

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

    838:     Level: intermediate

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

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

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

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

    878:    Collective on DM

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

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

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

    898:     Collective on dm

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

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

    909:     Level: beginner

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

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

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

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

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

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

    957:     Collective on dm

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

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

    965:     Level: beginner

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

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

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

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

    988:     Not Collective

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

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

    996:     Level: beginner

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

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

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

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

    1019:    Collective on dm

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

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

    1027:    Level: intermediate

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

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

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

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

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

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

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

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

    1105:    Not Collective

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

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

    1113:    Level: intermediate

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

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

    1129:     Collective on dmc

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

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

    1139:     Level: developer

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

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

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

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

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

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

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

    1174:   Level: developer

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

    1180: .seealso: DMCreateInterpolation()

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

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

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

    1214:     Collective on dmc

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

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

    1223:     Level: developer

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

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

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

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

    1247:     Collective on dac

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

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

    1256:     Level: developer

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

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

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

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

    1280:   Collective on dac

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

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

    1289:   Level: developer

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

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

    1306:   Collective on dm

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

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

    1314:   Level: developer

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

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

    1330:     Collective on dm

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

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

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

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

    1345:     Level: developer

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

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

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

    1362:     Collective on dm

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

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

    1370:     Level: beginner

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

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

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

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

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

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

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

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

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

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

    1436:   Logically Collective on dm

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

    1442:   Level: developer

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

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

    1457:   Logically Collective on dm

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

    1463:   Level: developer

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

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

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

    1481:   Logically Collective on dm

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

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

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

    1500:   Not Collective

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

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

    1510:   Level: developer

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

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

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

    1546:   Not Collective

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

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

    1556:   Level: developer

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

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

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

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

    1584:   Logically collective on DM

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

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

    1600:   This function is currently not available from Fortran.

    1602:    Level: intermediate

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

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

    1617:   Not collective

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

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

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

    1635:   This function is currently not available from Fortran.

    1637:    Level: intermediate

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

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

    1653:   Logically collective on DM

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

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

    1669:   This function is currently not available from Fortran.

    1671:    Level: intermediate

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

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

    1686:   Not collective

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

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

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

    1704:   This function is currently not available from Fortran.

    1706:    Level: intermediate

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

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

    1722:   Not collective

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

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

    1732:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

    1847:   Not collective

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

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

    1858:   Level: intermediate

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

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

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

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

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

    1927:   Not collective

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

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

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

    1940:   Level: intermediate

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

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

    1958:   Not collective

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

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

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

    1970:   Level: intermediate

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

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

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

    1998:   Not collective

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

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

    2010:   Level: intermediate

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

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

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

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

    2055:   Not collective

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

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

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

    2073:   Level: developer

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

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

    2089:   Collective on dm

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

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

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

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

    2103:   Level: developer

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

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

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

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

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

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

    2138:    Logically Collective

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

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

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

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

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

    2161:    Level: advanced

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

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

    2168:    This function is currently not available from Fortran.

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

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

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

    2192:    Logically Collective

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

    2200:    Level: advanced

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

    2205:    This function is currently not available from Fortran.

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

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

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

    2228:    Collective if any hooks are

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

    2235:    Level: developer

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

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

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

    2254:    Collective on DM

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

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

    2267:    Level: developer

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

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

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

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

    2297:     Not Collective

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

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

    2305:     Level: developer

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

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

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

    2320:     Not Collective

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

    2326:     Level: advanced

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

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

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

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

    2344:   Collective on dm

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

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

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

    2355:   Level: developer

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

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

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

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

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

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

    2398:   Level: developer

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

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

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

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

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

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

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

    2475:    Logically Collective

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

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

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

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

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

    2498:    Level: advanced

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

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

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

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

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

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

    2552:     Neighbor-wise Collective on dm

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

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

    2564:     Level: beginner

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

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

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

    2579:     Neighbor-wise Collective on dm

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

    2587:     Level: intermediate

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

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

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

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

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

    2625:     Neighbor-wise Collective on dm

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

    2633:     Level: intermediate

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

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

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

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

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

    2673:    Logically Collective

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

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

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

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

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

    2699:    Level: advanced

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

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

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

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

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

    2757:     Neighbor-wise Collective on dm

    2759:     Input Parameters:
    2760: +   dm - the DM object
    2761: .   l - the local vector
    2762: .   mode - if INSERT_VALUES then no parallel communication is used, if ADD_VALUES then all ghost points from the same base point accumulate into that base point.
    2763: -   g - the global vector

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

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

    2772:     Level: beginner

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

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

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

    2787:     Neighbor-wise Collective on dm

    2789:     Input Parameters:
    2790: +   dm - the DM object
    2791: .   l - the local vector
    2792: .   mode - if INSERT_VALUES then no parallel communication is used, if ADD_VALUES then all ghost points from the same base point accumulate into that base point.
    2793: -   g - the global vector

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

    2799:     Level: intermediate

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

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

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

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

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

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

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

    2914:     Neighbor-wise Collective on dm

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

    2922:     Level: intermediate

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

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

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

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

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

    2984:    Neighbor-wise Collective on dm

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

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

    2994:    Level: intermediate

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

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

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

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

    3018:    Neighbor-wise Collective on dm

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

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

    3028:    Level: intermediate

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

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

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

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

    3050:     Collective on dm

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

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

    3059:     Level: developer

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

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

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

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

    3093:    Logically Collective

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

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

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

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

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

    3118:    Level: advanced

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

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

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

    3128:    This function is currently not available from Fortran.

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

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

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

    3152:    Logically Collective

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

    3160:    Level: advanced

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

    3165:    This function is currently not available from Fortran.

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

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

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

    3188:    Collective if any hooks are

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

    3197:    Level: developer

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

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

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

    3216:    Logically Collective on global

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

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

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

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

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

    3240:    Level: advanced

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

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

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

    3250:    This function is currently not available from Fortran.

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

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

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

    3274:    Logically Collective

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

    3282:    Level: advanced

    3284:    Notes:

    3286:    This function is currently not available from Fortran.

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

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

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

    3309:    Collective if any hooks are

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

    3317:    Level: developer

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

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

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

    3336:     Not Collective

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

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

    3344:     Level: developer

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

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

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

    3360:     Not Collective

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

    3366:     Level: developer

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

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

    3380:     Collective on dm

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

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

    3389:     Level: developer

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

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

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

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

    3416:     Collective on dm

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

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

    3425:     Level: developer

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

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

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

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

    3452:     Not Collective

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

    3458:     Level: intermediate

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

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

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

    3473:     Not Collective

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

    3479:     Level: intermediate

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

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

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

    3494:     Not Collective

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

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

    3502:     Level: intermediate

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

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

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

    3517:     Logically Collective on dm

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

    3523:     Level: intermediate

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

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

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

    3539:     Not Collective

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

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

    3547:     Level: developer

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

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

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

    3563:     Logically Collective on dm

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

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

    3572:     Level: advanced

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

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

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

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

    3593:     Not Collective

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

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

    3601:     Level: developer

    3603: .seealso DMCreateColoring()

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

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

    3617:     Not Collective

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

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

    3625:     Level: developer

    3627: .seealso DMCreateRestriction()

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

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

    3641:     Not Collective

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

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

    3649:     Level: developer

    3651: .seealso DMCreateInjection()

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

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

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

    3672:   Collective on dm

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

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

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

    3684:   Level: intermediate

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

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

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

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

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

    3713:   Not Collective

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

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

    3721:   Level: intermediate

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

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

    3737:   Collective on dm

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

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

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

    3751:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

    3848:   Not Collective

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

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

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

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

    3872:   Level: advanced

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

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

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

    3887:   Collective on viewer

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

    3895:    Level: intermediate

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

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

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

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

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

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

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

    3944:   Not collective

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

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

    3953:   Level: beginner

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

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

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

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

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

    3996:   Collective

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

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

    4005:   Level: beginner

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

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

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

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

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

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

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

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

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

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

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

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

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

    4093:   Level: advanced

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

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

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

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

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

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

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

    4120:   Level: intermediate

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

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

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

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

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

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

    4165:   Level: advanced

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

    4170:   Any existing Section will be destroyed

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

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

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

    4187:   Level: intermediate

    4189:   Note: Any existing Section will be destroyed

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

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

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

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

    4223:   not collective

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

    4228:   Output Parameters:
    4229: + section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Returns NULL if there are no local constraints.
    4230: . mat - The Mat that interpolates local constraints: its width should be the layout size of the default section.  Returns NULL if there are no local constraints.
    4231: - bias - Vector containing bias to be added to constrained dofs

    4233:   Level: advanced

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

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

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

    4252:   If a constraint matrix is specified, then it is applied during DMGlobalToLocalEnd() when mode is INSERT_VALUES, INSERT_BC_VALUES, or INSERT_ALL_VALUES.  Without a constraint matrix, the local vector l returned by DMGlobalToLocalEnd() contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the PetscSection returned by DMGetDefaultConstraints().

    4254:   If a constraint matrix is specified, then its adjoint is applied during DMLocalToGlobalBegin() when mode is ADD_VALUES, ADD_BC_VALUES, or ADD_ALL_VALUES.  Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above.  Any bias, if specified, is ignored when accumulating.

    4256:   collective on dm

    4258:   Input Parameters:
    4259: + dm - The DM
    4260: . section - The PetscSection describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (PETSC_COMM_SELF or derivative).
    4261: . mat - The Mat that interpolates local constraints: its width should be the layout size of the default section:  NULL indicates no constraints.  Must have a local communicator (PETSC_COMM_SELF or derivative).
    4262: - bias - A bias vector to be added to constrained values in the local vector.  NULL indicates no bias.  Must have a local communicator (PETSC_COMM_SELF or derivative).

    4264:   Level: advanced

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

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

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

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

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

    4311:   Level: intermediate

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

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

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

    4352:         PetscFindInt(offset,size+1,ranges,&r);
    4353:         if (r < 0) r = -(r+2);
    4354:         if ((r < 0) || (r >= size)) {PetscSynchronizedPrintf(comm, "[%d]Point %d mapped to invalid process %d (%d, %d)\n", rank, p, r, gdof, goff); valid = PETSC_FALSE;break;}
    4355:       }
    4356:     }
    4357:   }
    4358:   PetscLayoutDestroy(&layout);
    4359:   PetscSynchronizedFlush(comm, NULL);
    4360:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
    4361:   if (!gvalid) {
    4362:     DMView(dm, NULL);
    4363:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
    4364:   }
    4365:   return 0;
    4366: }
    4367: #endif

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

    4372:   Collective on dm

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

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

    4380:   Level: intermediate

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

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

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

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

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

    4412:   Level: intermediate

    4414:   Note: Any existing Section will be destroyed

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

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

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

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

    4441:   Level: intermediate

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

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

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

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

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

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

    4480:   Level: intermediate

    4482:   Note: Any previous SF is destroyed

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

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

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

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

    4507:   Level: developer

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

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

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

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

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

    4531:   Level: intermediate

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

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

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

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

    4552:   Level: intermediate

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

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

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

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

    4575:   Level: intermediate

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

    4579: .seealso: DMSetNaturalSF(), DMSetUseNatural(), DMGetUseNatural(), DMPlexCreateGlobalToNaturalSF(), DMPlexDistribute()
    4580: @*/
    4581: PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
    4582: {
    4585:   *sf = dm->sfNatural;
    4586:   return 0;
    4587: }

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

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

    4596:   Level: intermediate

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

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

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

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

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

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

    4643:   Logically collective on dm

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

    4648:   Level: intermediate

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

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

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

    4670:   Not collective

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

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

    4678:   Level: intermediate

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

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

    4693:   Logically collective on dm

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

    4699:   Level: intermediate

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

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

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

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

    4722:   Not collective

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

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

    4732:   Level: intermediate

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

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

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

    4762:   Logically collective on dm

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

    4770:   Level: intermediate

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

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

    4789:   Logically collective on dm

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

    4796:   Level: intermediate

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

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

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

    4820:   Logically collective on dm

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

    4827:   Level: intermediate

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

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

    4841:   Logically collective on dm

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

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

    4850:   Level: intermediate

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

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

    4864:   Collective on dm

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

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

    4872:   Level: advanced

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

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

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

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

    4899:   Not collective

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

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

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

    4915:   Level: developer

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

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

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

    4941:   Not collective

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

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

    4955:   Level: developer

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

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

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

    4979:   Not collective

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

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

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

    4993:   Level: developer

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

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

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

    5016:   Not collective

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

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

    5028:   Level: developer

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

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

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

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

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

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

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

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

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

    5097:   Not collective

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

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

    5105:   Level: intermediate

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

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

    5120:   Logically collective on dm

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

    5125:   Level: intermediate

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

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

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

    5148:   Not collective

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

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

    5156:   Level: intermediate

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

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

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

    5179:   Not collective

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

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

    5188:   Level: developer

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

    5201:   *prob = NULL;
    5202:   for (s = 0; s < dm->Nds; ++s) {
    5203:     PetscInt val;

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

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

    5218:   Not collective

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

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

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

    5233:   Level: advanced

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

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

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

    5258:   Collective on dm

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

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

    5269:   Level: advanced

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

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

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

    5305:   Not collective

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

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

    5316:   Level: advanced

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

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

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

    5345:   Not collective

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

    5354:   Level: advanced

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

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

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

    5387:   Not collective

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

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

    5396:   Level: advanced

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

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

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

    5417:   Not collective

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

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

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

    5430:   Level: intermediate

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

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

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

    5454:   Collective on dm

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

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

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

    5464:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    5678:   Collective on DM

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

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

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

    5690:   Level: developer

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

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

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

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

    5765:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
    5766:   PetscDSCopyConstants(ds, dsNew);
    5767:   PetscDSCopyExactSolutions(ds, dsNew);
    5768:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
    5769:   PetscDSCopyEquations(ds, dsNew);
    5770:   PetscDSGetNumFields(ds, &Nf);
    5771:   for (f = 0; f < Nf; ++f) {
    5772:     PetscDSGetContext(ds, f, &ctx);
    5773:     PetscDSSetContext(dsNew, f, ctx);
    5774:     PetscDSGetCohesive(ds, f, &isCohesive);
    5775:     PetscDSSetCohesive(dsNew, f, isCohesive);
    5776:   }
    5777:   if (Nf) {
    5778:     PetscDSGetCoordinateDimension(ds, &cdim);
    5779:     PetscDSSetCoordinateDimension(dsNew, cdim);
    5780:   }
    5781:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
    5782:   for (b = dsNew->boundary; b; b = b->next) {
    5783:     DMGetLabel(dm, b->lname, &b->label);
    5784:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    5786:   }

    5788:   DMSetRegionDS(dm, label, fields, dsNew);
    5789:   PetscDSDestroy(&dsNew);
    5790:   return 0;
    5791: }

    5793: /*@
    5794:   DMCopyDS - Copy the discrete systems for the DM into another DM

    5796:   Collective on dm

    5798:   Input Parameter:
    5799: . dm - The DM

    5801:   Output Parameter:
    5802: . newdm - The DM

    5804:   Level: advanced

    5806: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5807: @*/
    5808: PetscErrorCode DMCopyDS(DM dm, DM newdm)
    5809: {
    5810:   PetscInt       Nds, s;

    5812:   if (dm == newdm) return 0;
    5813:   DMGetNumDS(dm, &Nds);
    5814:   DMClearDS(newdm);
    5815:   for (s = 0; s < Nds; ++s) {
    5816:     DMLabel  label;
    5817:     IS       fields;
    5818:     PetscDS  ds, newds;
    5819:     PetscInt Nbd, bd;

    5821:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
    5822:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
    5823:     DMTransferDS_Internal(newdm, label, fields, ds);
    5824:     /* Commplete new labels in the new DS */
    5825:     DMGetRegionDS(newdm, label, NULL, &newds);
    5826:     PetscDSGetNumBoundary(newds, &Nbd);
    5827:     for (bd = 0; bd < Nbd; ++bd) {
    5828:       PetscWeakForm wf;
    5829:       DMLabel       label;
    5830:       PetscInt      field;

    5832:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
    5833:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
    5834:       PetscWeakFormReplaceLabel(wf, label);
    5835:     }
    5836:   }
    5837:   return 0;
    5838: }

    5840: /*@
    5841:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

    5843:   Collective on dm

    5845:   Input Parameter:
    5846: . dm - The DM

    5848:   Output Parameter:
    5849: . newdm - The DM

    5851:   Level: advanced

    5853: .seealso: DMCopyFields(), DMCopyDS()
    5854: @*/
    5855: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
    5856: {
    5857:   DMCopyFields(dm, newdm);
    5858:   DMCopyDS(dm, newdm);
    5859:   return 0;
    5860: }

    5862: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
    5863: {
    5864:   DM dm_coord,dmc_coord;
    5865:   Vec coords,ccoords;
    5866:   Mat inject;
    5867:   DMGetCoordinateDM(dm,&dm_coord);
    5868:   DMGetCoordinateDM(dmc,&dmc_coord);
    5869:   DMGetCoordinates(dm,&coords);
    5870:   DMGetCoordinates(dmc,&ccoords);
    5871:   if (coords && !ccoords) {
    5872:     DMCreateGlobalVector(dmc_coord,&ccoords);
    5873:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5874:     DMCreateInjection(dmc_coord,dm_coord,&inject);
    5875:     MatRestrict(inject,coords,ccoords);
    5876:     MatDestroy(&inject);
    5877:     DMSetCoordinates(dmc,ccoords);
    5878:     VecDestroy(&ccoords);
    5879:   }
    5880:   return 0;
    5881: }

    5883: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
    5884: {
    5885:   DM dm_coord,subdm_coord;
    5886:   Vec coords,ccoords,clcoords;
    5887:   VecScatter *scat_i,*scat_g;
    5888:   DMGetCoordinateDM(dm,&dm_coord);
    5889:   DMGetCoordinateDM(subdm,&subdm_coord);
    5890:   DMGetCoordinates(dm,&coords);
    5891:   DMGetCoordinates(subdm,&ccoords);
    5892:   if (coords && !ccoords) {
    5893:     DMCreateGlobalVector(subdm_coord,&ccoords);
    5894:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5895:     DMCreateLocalVector(subdm_coord,&clcoords);
    5896:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
    5897:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
    5898:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5899:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5900:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5901:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5902:     DMSetCoordinates(subdm,ccoords);
    5903:     DMSetCoordinatesLocal(subdm,clcoords);
    5904:     VecScatterDestroy(&scat_i[0]);
    5905:     VecScatterDestroy(&scat_g[0]);
    5906:     VecDestroy(&ccoords);
    5907:     VecDestroy(&clcoords);
    5908:     PetscFree(scat_i);
    5909:     PetscFree(scat_g);
    5910:   }
    5911:   return 0;
    5912: }

    5914: /*@
    5915:   DMGetDimension - Return the topological dimension of the DM

    5917:   Not collective

    5919:   Input Parameter:
    5920: . dm - The DM

    5922:   Output Parameter:
    5923: . dim - The topological dimension

    5925:   Level: beginner

    5927: .seealso: DMSetDimension(), DMCreate()
    5928: @*/
    5929: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
    5930: {
    5933:   *dim = dm->dim;
    5934:   return 0;
    5935: }

    5937: /*@
    5938:   DMSetDimension - Set the topological dimension of the DM

    5940:   Collective on dm

    5942:   Input Parameters:
    5943: + dm - The DM
    5944: - dim - The topological dimension

    5946:   Level: beginner

    5948: .seealso: DMGetDimension(), DMCreate()
    5949: @*/
    5950: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
    5951: {
    5952:   PetscDS        ds;
    5953:   PetscInt       Nds, n;

    5957:   dm->dim = dim;
    5958:   if (dm->dim >= 0) {
    5959:     DMGetNumDS(dm, &Nds);
    5960:     for (n = 0; n < Nds; ++n) {
    5961:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
    5962:       if (ds->dimEmbed < 0) PetscDSSetCoordinateDimension(ds, dim);
    5963:     }
    5964:   }
    5965:   return 0;
    5966: }

    5968: /*@
    5969:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

    5971:   Collective on dm

    5973:   Input Parameters:
    5974: + dm - the DM
    5975: - dim - the dimension

    5977:   Output Parameters:
    5978: + pStart - The first point of the given dimension
    5979: - pEnd - The first point following points of the given dimension

    5981:   Note:
    5982:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
    5983:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
    5984:   then the interval is empty.

    5986:   Level: intermediate

    5988: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
    5989: @*/
    5990: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
    5991: {
    5992:   PetscInt       d;

    5995:   DMGetDimension(dm, &d);
    5998:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
    5999:   return 0;
    6000: }

    6002: /*@
    6003:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

    6005:   Collective on dm

    6007:   Input Parameters:
    6008: + dm - the DM
    6009: - c - coordinate vector

    6011:   Notes:
    6012:   The coordinates do include those for ghost points, which are in the local vector.

    6014:   The vector c should be destroyed by the caller.

    6016:   Level: intermediate

    6018: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    6019: @*/
    6020: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
    6021: {
    6024:   PetscObjectReference((PetscObject) c);
    6025:   VecDestroy(&dm->coordinates);
    6026:   dm->coordinates = c;
    6027:   VecDestroy(&dm->coordinatesLocal);
    6028:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
    6029:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
    6030:   return 0;
    6031: }

    6033: /*@
    6034:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

    6036:   Not collective

    6038:    Input Parameters:
    6039: +  dm - the DM
    6040: -  c - coordinate vector

    6042:   Notes:
    6043:   The coordinates of ghost points can be set using DMSetCoordinates()
    6044:   followed by DMGetCoordinatesLocal(). This is intended to enable the
    6045:   setting of ghost coordinates outside of the domain.

    6047:   The vector c should be destroyed by the caller.

    6049:   Level: intermediate

    6051: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
    6052: @*/
    6053: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
    6054: {
    6057:   PetscObjectReference((PetscObject) c);
    6058:   VecDestroy(&dm->coordinatesLocal);

    6060:   dm->coordinatesLocal = c;

    6062:   VecDestroy(&dm->coordinates);
    6063:   return 0;
    6064: }

    6066: /*@
    6067:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

    6069:   Collective on dm

    6071:   Input Parameter:
    6072: . dm - the DM

    6074:   Output Parameter:
    6075: . c - global coordinate vector

    6077:   Note:
    6078:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
    6079:   destroyed the array will no longer be valid.

    6081:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

    6083:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6084:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6086:   Level: intermediate

    6088: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    6089: @*/
    6090: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
    6091: {
    6094:   if (!dm->coordinates && dm->coordinatesLocal) {
    6095:     DM        cdm = NULL;
    6096:     PetscBool localized;

    6098:     DMGetCoordinateDM(dm, &cdm);
    6099:     DMCreateGlobalVector(cdm, &dm->coordinates);
    6100:     DMGetCoordinatesLocalized(dm, &localized);
    6101:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
    6102:     if (localized) {
    6103:       PetscInt cdim;

    6105:       DMGetCoordinateDim(dm, &cdim);
    6106:       VecSetBlockSize(dm->coordinates, cdim);
    6107:     }
    6108:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
    6109:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6110:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6111:   }
    6112:   *c = dm->coordinates;
    6113:   return 0;
    6114: }

    6116: /*@
    6117:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

    6119:   Collective on dm

    6121:   Input Parameter:
    6122: . dm - the DM

    6124:   Level: advanced

    6126: .seealso: DMGetCoordinatesLocalNoncollective()
    6127: @*/
    6128: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
    6129: {
    6131:   if (!dm->coordinatesLocal && dm->coordinates) {
    6132:     DM        cdm = NULL;
    6133:     PetscBool localized;

    6135:     DMGetCoordinateDM(dm, &cdm);
    6136:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
    6137:     DMGetCoordinatesLocalized(dm, &localized);
    6138:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
    6139:     if (localized) {
    6140:       PetscInt cdim;

    6142:       DMGetCoordinateDim(dm, &cdim);
    6143:       VecSetBlockSize(dm->coordinates, cdim);
    6144:     }
    6145:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
    6146:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6147:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6148:   }
    6149:   return 0;
    6150: }

    6152: /*@
    6153:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

    6155:   Collective on dm

    6157:   Input Parameter:
    6158: . dm - the DM

    6160:   Output Parameter:
    6161: . c - coordinate vector

    6163:   Note:
    6164:   This is a borrowed reference, so the user should NOT destroy this vector

    6166:   Each process has the local and ghost coordinates

    6168:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6169:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6171:   Level: intermediate

    6173: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
    6174: @*/
    6175: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
    6176: {
    6179:   DMGetCoordinatesLocalSetUp(dm);
    6180:   *c = dm->coordinatesLocal;
    6181:   return 0;
    6182: }

    6184: /*@
    6185:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

    6187:   Not collective

    6189:   Input Parameter:
    6190: . dm - the DM

    6192:   Output Parameter:
    6193: . c - coordinate vector

    6195:   Level: advanced

    6197: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6198: @*/
    6199: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
    6200: {
    6204:   *c = dm->coordinatesLocal;
    6205:   return 0;
    6206: }

    6208: /*@
    6209:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

    6211:   Not collective

    6213:   Input Parameters:
    6214: + dm - the DM
    6215: - p - the IS of points whose coordinates will be returned

    6217:   Output Parameters:
    6218: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
    6219: - pCoord - the Vec with coordinates of points in p

    6221:   Note:
    6222:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

    6224:   This creates a new vector, so the user SHOULD destroy this vector

    6226:   Each process has the local and ghost coordinates

    6228:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6229:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6231:   Level: advanced

    6233: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6234: @*/
    6235: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
    6236: {
    6237:   PetscSection        cs, newcs;
    6238:   Vec                 coords;
    6239:   const PetscScalar   *arr;
    6240:   PetscScalar         *newarr=NULL;
    6241:   PetscInt            n;

    6249:   cs = dm->coordinateDM->localSection;
    6250:   coords = dm->coordinatesLocal;
    6251:   VecGetArrayRead(coords, &arr);
    6252:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
    6253:   VecRestoreArrayRead(coords, &arr);
    6254:   if (pCoord) {
    6255:     PetscSectionGetStorageSize(newcs, &n);
    6256:     /* set array in two steps to mimic PETSC_OWN_POINTER */
    6257:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
    6258:     VecReplaceArray(*pCoord, newarr);
    6259:   } else {
    6260:     PetscFree(newarr);
    6261:   }
    6262:   if (pCoordSection) {*pCoordSection = newcs;}
    6263:   else               PetscSectionDestroy(&newcs);
    6264:   return 0;
    6265: }

    6267: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
    6268: {
    6271:   if (!dm->coordinateField) {
    6272:     if (dm->ops->createcoordinatefield) {
    6273:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
    6274:     }
    6275:   }
    6276:   *field = dm->coordinateField;
    6277:   return 0;
    6278: }

    6280: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
    6281: {
    6284:   PetscObjectReference((PetscObject)field);
    6285:   DMFieldDestroy(&dm->coordinateField);
    6286:   dm->coordinateField = field;
    6287:   return 0;
    6288: }

    6290: /*@
    6291:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6293:   Collective on dm

    6295:   Input Parameter:
    6296: . dm - the DM

    6298:   Output Parameter:
    6299: . cdm - coordinate DM

    6301:   Level: intermediate

    6303: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6304: @*/
    6305: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
    6306: {
    6309:   if (!dm->coordinateDM) {
    6310:     DM cdm;

    6313:     (*dm->ops->createcoordinatedm)(dm, &cdm);
    6314:     PetscObjectSetName((PetscObject)cdm, "coordinateDM");
    6315:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
    6316:      * until the call to CreateCoordinateDM) */
    6317:     DMDestroy(&dm->coordinateDM);
    6318:     dm->coordinateDM = cdm;
    6319:   }
    6320:   *cdm = dm->coordinateDM;
    6321:   return 0;
    6322: }

    6324: /*@
    6325:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6327:   Logically Collective on dm

    6329:   Input Parameters:
    6330: + dm - the DM
    6331: - cdm - coordinate DM

    6333:   Level: intermediate

    6335: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6336: @*/
    6337: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
    6338: {
    6341:   PetscObjectReference((PetscObject)cdm);
    6342:   DMDestroy(&dm->coordinateDM);
    6343:   dm->coordinateDM = cdm;
    6344:   return 0;
    6345: }

    6347: /*@
    6348:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

    6350:   Not Collective

    6352:   Input Parameter:
    6353: . dm - The DM object

    6355:   Output Parameter:
    6356: . dim - The embedding dimension

    6358:   Level: intermediate

    6360: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6361: @*/
    6362: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
    6363: {
    6366:   if (dm->dimEmbed == PETSC_DEFAULT) {
    6367:     dm->dimEmbed = dm->dim;
    6368:   }
    6369:   *dim = dm->dimEmbed;
    6370:   return 0;
    6371: }

    6373: /*@
    6374:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

    6376:   Not Collective

    6378:   Input Parameters:
    6379: + dm  - The DM object
    6380: - dim - The embedding dimension

    6382:   Level: intermediate

    6384: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6385: @*/
    6386: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
    6387: {
    6388:   PetscDS        ds;
    6389:   PetscInt       Nds, n;

    6392:   dm->dimEmbed = dim;
    6393:   if (dm->dim >= 0) {
    6394:     DMGetNumDS(dm, &Nds);
    6395:     for (n = 0; n < Nds; ++n) {
    6396:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
    6397:       PetscDSSetCoordinateDimension(ds, dim);
    6398:     }
    6399:   }
    6400:   return 0;
    6401: }

    6403: /*@
    6404:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

    6406:   Collective on dm

    6408:   Input Parameter:
    6409: . dm - The DM object

    6411:   Output Parameter:
    6412: . section - The PetscSection object

    6414:   Level: intermediate

    6416: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6417: @*/
    6418: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
    6419: {
    6420:   DM             cdm;

    6424:   DMGetCoordinateDM(dm, &cdm);
    6425:   DMGetLocalSection(cdm, section);
    6426:   return 0;
    6427: }

    6429: /*@
    6430:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

    6432:   Not Collective

    6434:   Input Parameters:
    6435: + dm      - The DM object
    6436: . dim     - The embedding dimension, or PETSC_DETERMINE
    6437: - section - The PetscSection object

    6439:   Level: intermediate

    6441: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6442: @*/
    6443: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
    6444: {
    6445:   DM             cdm;

    6449:   DMGetCoordinateDM(dm, &cdm);
    6450:   DMSetLocalSection(cdm, section);
    6451:   if (dim == PETSC_DETERMINE) {
    6452:     PetscInt d = PETSC_DEFAULT;
    6453:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

    6455:     PetscSectionGetChart(section, &pStart, &pEnd);
    6456:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
    6457:     pStart = PetscMax(vStart, pStart);
    6458:     pEnd   = PetscMin(vEnd, pEnd);
    6459:     for (v = pStart; v < pEnd; ++v) {
    6460:       PetscSectionGetDof(section, v, &dd);
    6461:       if (dd) {d = dd; break;}
    6462:     }
    6463:     if (d >= 0) DMSetCoordinateDim(dm, d);
    6464:   }
    6465:   return 0;
    6466: }

    6468: /*@
    6469:   DMProjectCoordinates - Project coordinates to a different space

    6471:   Input Parameters:
    6472: + dm      - The DM object
    6473: - disc    - The new coordinate discretization or NULL to ensure a coordinate discretization exists

    6475:   Level: intermediate

    6477: .seealso: DMGetCoordinateField()
    6478: @*/
    6479: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
    6480: {
    6481:   PetscFE        discOld;
    6482:   PetscClassId   classid;
    6483:   DM             cdmOld,cdmNew;
    6484:   Vec            coordsOld,coordsNew;
    6485:   Mat            matInterp;
    6486:   PetscBool      same_space = PETSC_TRUE;

    6491:   DMGetCoordinateDM(dm, &cdmOld);
    6492:   /* Check current discretization is compatible */
    6493:   DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
    6494:   PetscObjectGetClassId((PetscObject)discOld, &classid);
    6495:   if (classid != PETSCFE_CLASSID) {
    6496:     if (classid == PETSC_CONTAINER_CLASSID) {
    6497:       PetscFE        feLinear;
    6498:       DMPolytopeType ct;
    6499:       PetscInt       dim, dE, cStart, cEnd;
    6500:       PetscBool      simplex;

    6502:       /* Assume linear vertex coordinates */
    6503:       DMGetDimension(dm, &dim);
    6504:       DMGetCoordinateDim(dm, &dE);
    6505:       DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
    6506:       if (cEnd > cStart) {
    6507:         DMPlexGetCellType(dm, cStart, &ct);
    6508:         switch (ct) {
    6509:           case DM_POLYTOPE_TRI_PRISM:
    6510:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
    6511:             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
    6512:           default: break;
    6513:         }
    6514:       }
    6515:       DMPlexIsSimplex(dm, &simplex);
    6516:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
    6517:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
    6518:       PetscFEDestroy(&feLinear);
    6519:       DMCreateDS(cdmOld);
    6520:       DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld);
    6521:     } else {
    6522:       const char *discname;

    6524:       PetscObjectGetType((PetscObject)discOld, &discname);
    6525:       SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
    6526:     }
    6527:   }
    6528:   if (!disc) return 0;
    6529:   { // Check if the new space is the same as the old modulo quadrature
    6530:     PetscDualSpace dsOld, ds;
    6531:     PetscFEGetDualSpace(discOld, &dsOld);
    6532:     PetscFEGetDualSpace(disc, &ds);
    6533:     PetscDualSpaceEqual(dsOld, ds, &same_space);
    6534:   }
    6535:   /* Make a fresh clone of the coordinate DM */
    6536:   DMClone(cdmOld, &cdmNew);
    6537:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
    6538:   DMCreateDS(cdmNew);
    6539:   DMGetCoordinates(dm, &coordsOld);
    6540:   if (same_space) {
    6541:     PetscObjectReference((PetscObject)coordsOld);
    6542:     coordsNew = coordsOld;
    6543:   } else { // Project the coordinate vector from old to new space
    6544:     DMCreateGlobalVector(cdmNew, &coordsNew);
    6545:     DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
    6546:     MatInterpolate(matInterp, coordsOld, coordsNew);
    6547:     MatDestroy(&matInterp);
    6548:   }
    6549:   /* Set new coordinate structures */
    6550:   DMSetCoordinateField(dm, NULL);
    6551:   DMSetCoordinateDM(dm, cdmNew);
    6552:   DMSetCoordinates(dm, coordsNew);
    6553:   VecDestroy(&coordsNew);
    6554:   DMDestroy(&cdmNew);
    6555:   return 0;
    6556: }

    6558: /*@C
    6559:   DMGetPeriodicity - Get the description of mesh periodicity

    6561:   Input Parameter:
    6562: . dm      - The DM object

    6564:   Output Parameters:
    6565: + per     - Whether the DM is periodic or not
    6566: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
    6567: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6568: - bd      - This describes the type of periodicity in each topological dimension

    6570:   Level: developer

    6572: .seealso: DMGetPeriodicity()
    6573: @*/
    6574: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
    6575: {
    6577:   if (per)     *per     = dm->periodic;
    6578:   if (L)       *L       = dm->L;
    6579:   if (maxCell) *maxCell = dm->maxCell;
    6580:   if (bd)      *bd      = dm->bdtype;
    6581:   return 0;
    6582: }

    6584: /*@C
    6585:   DMSetPeriodicity - Set the description of mesh periodicity

    6587:   Input Parameters:
    6588: + dm      - The DM object
    6589: . per     - Whether the DM is periodic or not.
    6590: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates. Pass NULL to remove such information.
    6591: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6592: - bd      - This describes the type of periodicity in each topological dimension

    6594:   Notes: If per is PETSC_TRUE and maxCell is not provided, coordinates need to be already localized, or must be localized by hand by the user.

    6596:   Level: developer

    6598: .seealso: DMGetPeriodicity()
    6599: @*/
    6600: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
    6601: {
    6602:   PetscInt       dim, d;

    6609:   DMGetDimension(dm, &dim);
    6610:   if (maxCell) {
    6611:     if (!dm->maxCell) PetscMalloc1(dim, &dm->maxCell);
    6612:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
    6613:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
    6614:     PetscFree(dm->maxCell);
    6615:   }

    6617:   if (L) {
    6618:     if (!dm->L) PetscMalloc1(dim, &dm->L);
    6619:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
    6620:   }
    6621:   if (bd) {
    6622:     if (!dm->bdtype) PetscMalloc1(dim, &dm->bdtype);
    6623:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
    6624:   }
    6625:   dm->periodic = per;
    6626:   return 0;
    6627: }

    6629: /*@
    6630:   DMLocalizeCoordinate - If a mesh is periodic (a torus with lengths L_i, some of which can be infinite), project the coordinate onto [0, L_i) in each dimension.

    6632:   Input Parameters:
    6633: + dm     - The DM
    6634: . in     - The input coordinate point (dim numbers)
    6635: - endpoint - Include the endpoint L_i

    6637:   Output Parameter:
    6638: . out - The localized coordinate point

    6640:   Level: developer

    6642: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6643: @*/
    6644: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
    6645: {
    6646:   PetscInt       dim, d;

    6648:   DMGetCoordinateDim(dm, &dim);
    6649:   if (!dm->maxCell) {
    6650:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6651:   } else {
    6652:     if (endpoint) {
    6653:       for (d = 0; d < dim; ++d) {
    6654:         if ((PetscAbsReal(PetscRealPart(in[d])/dm->L[d] - PetscFloorReal(PetscRealPart(in[d])/dm->L[d])) < PETSC_SMALL) && (PetscRealPart(in[d])/dm->L[d] > PETSC_SMALL)) {
    6655:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
    6656:         } else {
    6657:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6658:         }
    6659:       }
    6660:     } else {
    6661:       for (d = 0; d < dim; ++d) {
    6662:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6663:       }
    6664:     }
    6665:   }
    6666:   return 0;
    6667: }

    6669: /*
    6670:   DMLocalizeCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

    6672:   Input Parameters:
    6673: + dm     - The DM
    6674: . dim    - The spatial dimension
    6675: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6676: - in     - The input coordinate point (dim numbers)

    6678:   Output Parameter:
    6679: . out - The localized coordinate point

    6681:   Level: developer

    6683:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

    6685: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6686: */
    6687: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6688: {
    6689:   PetscInt d;

    6691:   if (!dm->maxCell) {
    6692:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6693:   } else {
    6694:     for (d = 0; d < dim; ++d) {
    6695:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
    6696:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6697:       } else {
    6698:         out[d] = in[d];
    6699:       }
    6700:     }
    6701:   }
    6702:   return 0;
    6703: }

    6705: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
    6706: {
    6707:   PetscInt d;

    6709:   if (!dm->maxCell) {
    6710:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6711:   } else {
    6712:     for (d = 0; d < dim; ++d) {
    6713:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
    6714:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6715:       } else {
    6716:         out[d] = in[d];
    6717:       }
    6718:     }
    6719:   }
    6720:   return 0;
    6721: }

    6723: /*
    6724:   DMLocalizeAddCoordinate_Internal - If a mesh is periodic, and the input point is far from the anchor, pick the coordinate sheet of the torus which moves it closer.

    6726:   Input Parameters:
    6727: + dm     - The DM
    6728: . dim    - The spatial dimension
    6729: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6730: . in     - The input coordinate delta (dim numbers)
    6731: - out    - The input coordinate point (dim numbers)

    6733:   Output Parameter:
    6734: . out    - The localized coordinate in + out

    6736:   Level: developer

    6738:   Note: This is meant to get a set of coordinates close to each other, as in a cell. The anchor is usually the one of the vertices on a containing cell

    6740: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
    6741: */
    6742: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6743: {
    6744:   PetscInt d;

    6746:   if (!dm->maxCell) {
    6747:     for (d = 0; d < dim; ++d) out[d] += in[d];
    6748:   } else {
    6749:     for (d = 0; d < dim; ++d) {
    6750:       const PetscReal maxC = dm->maxCell[d];

    6752:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
    6753:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

    6755:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
    6756:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
    6757:         out[d] += newCoord;
    6758:       } else {
    6759:         out[d] += in[d];
    6760:       }
    6761:     }
    6762:   }
    6763:   return 0;
    6764: }

    6766: /*@
    6767:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

    6769:   Not collective

    6771:   Input Parameter:
    6772: . dm - The DM

    6774:   Output Parameter:
    6775:   areLocalized - True if localized

    6777:   Level: developer

    6779: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
    6780: @*/
    6781: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
    6782: {
    6783:   DM             cdm;
    6784:   PetscSection   coordSection;
    6785:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
    6786:   PetscBool      isPlex, alreadyLocalized;

    6790:   *areLocalized = PETSC_FALSE;

    6792:   /* We need some generic way of refering to cells/vertices */
    6793:   DMGetCoordinateDM(dm, &cdm);
    6794:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
    6795:   if (!isPlex) return 0;
    6796:   DMPlexGetDepth(cdm, &depth);
    6797:   if (!depth) return 0;

    6799:   DMGetCoordinateSection(dm, &coordSection);
    6800:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
    6801:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
    6802:   alreadyLocalized = PETSC_FALSE;
    6803:   for (c = cStart; c < cEnd; ++c) {
    6804:     if (c < sStart || c >= sEnd) continue;
    6805:     PetscSectionGetDof(coordSection, c, &dof);
    6806:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
    6807:   }
    6808:   *areLocalized = alreadyLocalized;
    6809:   return 0;
    6810: }

    6812: /*@
    6813:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

    6815:   Collective on dm

    6817:   Input Parameter:
    6818: . dm - The DM

    6820:   Output Parameter:
    6821:   areLocalized - True if localized

    6823:   Level: developer

    6825: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
    6826: @*/
    6827: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
    6828: {
    6829:   PetscBool      localized;

    6833:   DMGetCoordinatesLocalizedLocal(dm,&localized);
    6834:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
    6835:   return 0;
    6836: }

    6838: /*@
    6839:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

    6841:   Collective on dm

    6843:   Input Parameter:
    6844: . dm - The DM

    6846:   Level: developer

    6848: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
    6849: @*/
    6850: PetscErrorCode DMLocalizeCoordinates(DM dm)
    6851: {
    6852:   DM             cdm;
    6853:   PetscSection   coordSection, cSection;
    6854:   Vec            coordinates,  cVec;
    6855:   PetscScalar   *coords, *coords2, *anchor, *localized;
    6856:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
    6857:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
    6858:   PetscInt       maxHeight = 0, h;
    6859:   PetscInt       *pStart = NULL, *pEnd = NULL;

    6862:   if (!dm->periodic) return 0;
    6863:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
    6864:   if (alreadyLocalized) return 0;

    6866:   /* We need some generic way of refering to cells/vertices */
    6867:   DMGetCoordinateDM(dm, &cdm);
    6868:   {
    6869:     PetscBool isplex;

    6871:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
    6872:     if (isplex) {
    6873:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
    6874:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
    6875:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6876:       pEnd = &pStart[maxHeight + 1];
    6877:       newStart = vStart;
    6878:       newEnd   = vEnd;
    6879:       for (h = 0; h <= maxHeight; h++) {
    6880:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
    6881:         newStart = PetscMin(newStart,pStart[h]);
    6882:         newEnd   = PetscMax(newEnd,pEnd[h]);
    6883:       }
    6884:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
    6885:   }
    6886:   DMGetCoordinatesLocal(dm, &coordinates);
    6888:   DMGetCoordinateSection(dm, &coordSection);
    6889:   VecGetBlockSize(coordinates, &bs);
    6890:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

    6892:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
    6893:   PetscSectionSetNumFields(cSection, 1);
    6894:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
    6895:   PetscSectionSetFieldComponents(cSection, 0, Nc);
    6896:   PetscSectionSetChart(cSection, newStart, newEnd);

    6898:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6899:   localized = &anchor[bs];
    6900:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
    6901:   for (h = 0; h <= maxHeight; h++) {
    6902:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6904:     for (c = cStart; c < cEnd; ++c) {
    6905:       PetscScalar *cellCoords = NULL;
    6906:       PetscInt     b;

    6908:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
    6909:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6910:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6911:       for (d = 0; d < dof/bs; ++d) {
    6912:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
    6913:         for (b = 0; b < bs; b++) {
    6914:           if (cellCoords[d*bs + b] != localized[b]) break;
    6915:         }
    6916:         if (b < bs) break;
    6917:       }
    6918:       if (d < dof/bs) {
    6919:         if (c >= sStart && c < sEnd) {
    6920:           PetscInt cdof;

    6922:           PetscSectionGetDof(coordSection, c, &cdof);
    6923:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
    6924:         }
    6925:         PetscSectionSetDof(cSection, c, dof);
    6926:         PetscSectionSetFieldDof(cSection, c, 0, dof);
    6927:       }
    6928:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6929:     }
    6930:   }
    6931:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
    6932:   if (alreadyLocalizedGlobal) {
    6933:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6934:     PetscSectionDestroy(&cSection);
    6935:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6936:     return 0;
    6937:   }
    6938:   for (v = vStart; v < vEnd; ++v) {
    6939:     PetscSectionGetDof(coordSection, v, &dof);
    6940:     PetscSectionSetDof(cSection, v, dof);
    6941:     PetscSectionSetFieldDof(cSection, v, 0, dof);
    6942:   }
    6943:   PetscSectionSetUp(cSection);
    6944:   PetscSectionGetStorageSize(cSection, &coordSize);
    6945:   VecCreate(PETSC_COMM_SELF, &cVec);
    6946:   PetscObjectSetName((PetscObject)cVec,"coordinates");
    6947:   VecSetBlockSize(cVec, bs);
    6948:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
    6949:   VecSetType(cVec, VECSTANDARD);
    6950:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
    6951:   VecGetArray(cVec, &coords2);
    6952:   for (v = vStart; v < vEnd; ++v) {
    6953:     PetscSectionGetDof(coordSection, v, &dof);
    6954:     PetscSectionGetOffset(coordSection, v, &off);
    6955:     PetscSectionGetOffset(cSection,     v, &off2);
    6956:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
    6957:   }
    6958:   for (h = 0; h <= maxHeight; h++) {
    6959:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6961:     for (c = cStart; c < cEnd; ++c) {
    6962:       PetscScalar *cellCoords = NULL;
    6963:       PetscInt     b, cdof;

    6965:       PetscSectionGetDof(cSection,c,&cdof);
    6966:       if (!cdof) continue;
    6967:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6968:       PetscSectionGetOffset(cSection, c, &off2);
    6969:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6970:       for (d = 0; d < dof/bs; ++d) DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);
    6971:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6972:     }
    6973:   }
    6974:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6975:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6976:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
    6977:   VecRestoreArray(cVec, &coords2);
    6978:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
    6979:   DMSetCoordinatesLocal(dm, cVec);
    6980:   VecDestroy(&cVec);
    6981:   PetscSectionDestroy(&cSection);
    6982:   return 0;
    6983: }

    6985: /*@
    6986:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

    6988:   Collective on v (see explanation below)

    6990:   Input Parameters:
    6991: + dm - The DM
    6992: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

    6994:   Input/Output Parameters:
    6995: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
    6996: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
    6997:            on output, the PetscSF containing the ranks and local indices of the containing points

    6999:   Level: developer

    7001:   Notes:
    7002:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
    7003:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

    7005:   If *cellSF is NULL on input, a PetscSF will be created.
    7006:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

    7008:   An array that maps each point to its containing cell can be obtained with

    7010: $    const PetscSFNode *cells;
    7011: $    PetscInt           nFound;
    7012: $    const PetscInt    *found;
    7013: $
    7014: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

    7016:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
    7017:   the index of the cell in its rank's local numbering.

    7019: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
    7020: @*/
    7021: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
    7022: {
    7026:   if (*cellSF) {
    7027:     PetscMPIInt result;

    7030:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
    7032:   } else {
    7033:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
    7034:   }
    7036:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
    7037:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
    7038:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
    7039:   return 0;
    7040: }

    7042: /*@
    7043:   DMGetOutputDM - Retrieve the DM associated with the layout for output

    7045:   Collective on dm

    7047:   Input Parameter:
    7048: . dm - The original DM

    7050:   Output Parameter:
    7051: . odm - The DM which provides the layout for output

    7053:   Level: intermediate

    7055: .seealso: VecView(), DMGetGlobalSection()
    7056: @*/
    7057: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
    7058: {
    7059:   PetscSection   section;
    7060:   PetscBool      hasConstraints, ghasConstraints;

    7064:   DMGetLocalSection(dm, &section);
    7065:   PetscSectionHasConstraints(section, &hasConstraints);
    7066:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
    7067:   if (!ghasConstraints) {
    7068:     *odm = dm;
    7069:     return 0;
    7070:   }
    7071:   if (!dm->dmBC) {
    7072:     PetscSection newSection, gsection;
    7073:     PetscSF      sf;

    7075:     DMClone(dm, &dm->dmBC);
    7076:     DMCopyDisc(dm, dm->dmBC);
    7077:     PetscSectionClone(section, &newSection);
    7078:     DMSetLocalSection(dm->dmBC, newSection);
    7079:     PetscSectionDestroy(&newSection);
    7080:     DMGetPointSF(dm->dmBC, &sf);
    7081:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
    7082:     DMSetGlobalSection(dm->dmBC, gsection);
    7083:     PetscSectionDestroy(&gsection);
    7084:   }
    7085:   *odm = dm->dmBC;
    7086:   return 0;
    7087: }

    7089: /*@
    7090:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

    7092:   Input Parameter:
    7093: . dm - The original DM

    7095:   Output Parameters:
    7096: + num - The output sequence number
    7097: - val - The output sequence value

    7099:   Level: intermediate

    7101:   Note: This is intended for output that should appear in sequence, for instance
    7102:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7104: .seealso: VecView()
    7105: @*/
    7106: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
    7107: {
    7111:   return 0;
    7112: }

    7114: /*@
    7115:   DMSetOutputSequenceNumber - Set the sequence number/value for output

    7117:   Input Parameters:
    7118: + dm - The original DM
    7119: . num - The output sequence number
    7120: - val - The output sequence value

    7122:   Level: intermediate

    7124:   Note: This is intended for output that should appear in sequence, for instance
    7125:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7127: .seealso: VecView()
    7128: @*/
    7129: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
    7130: {
    7132:   dm->outputSequenceNum = num;
    7133:   dm->outputSequenceVal = val;
    7134:   return 0;
    7135: }

    7137: /*@C
    7138:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

    7140:   Input Parameters:
    7141: + dm   - The original DM
    7142: . name - The sequence name
    7143: - num  - The output sequence number

    7145:   Output Parameter:
    7146: . val  - The output sequence value

    7148:   Level: intermediate

    7150:   Note: This is intended for output that should appear in sequence, for instance
    7151:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7153: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
    7154: @*/
    7155: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
    7156: {
    7157:   PetscBool      ishdf5;

    7162:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    7163:   if (ishdf5) {
    7164: #if defined(PETSC_HAVE_HDF5)
    7165:     PetscScalar value;

    7167:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
    7168:     *val = PetscRealPart(value);
    7169: #endif
    7170:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
    7171:   return 0;
    7172: }

    7174: /*@
    7175:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

    7177:   Not collective

    7179:   Input Parameter:
    7180: . dm - The DM

    7182:   Output Parameter:
    7183: . useNatural - The flag to build the mapping to a natural order during distribution

    7185:   Level: beginner

    7187: .seealso: DMSetUseNatural(), DMCreate()
    7188: @*/
    7189: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
    7190: {
    7193:   *useNatural = dm->useNatural;
    7194:   return 0;
    7195: }

    7197: /*@
    7198:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

    7200:   Collective on dm

    7202:   Input Parameters:
    7203: + dm - The DM
    7204: - useNatural - The flag to build the mapping to a natural order during distribution

    7206:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

    7208:   Level: beginner

    7210: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
    7211: @*/
    7212: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
    7213: {
    7216:   dm->useNatural = useNatural;
    7217:   return 0;
    7218: }

    7220: /*@C
    7221:   DMCreateLabel - Create a label of the given name if it does not already exist

    7223:   Not Collective

    7225:   Input Parameters:
    7226: + dm   - The DM object
    7227: - name - The label name

    7229:   Level: intermediate

    7231: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7232: @*/
    7233: PetscErrorCode DMCreateLabel(DM dm, const char name[])
    7234: {
    7235:   PetscBool      flg;
    7236:   DMLabel        label;

    7240:   DMHasLabel(dm, name, &flg);
    7241:   if (!flg) {
    7242:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7243:     DMAddLabel(dm, label);
    7244:     DMLabelDestroy(&label);
    7245:   }
    7246:   return 0;
    7247: }

    7249: /*@C
    7250:   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists, move it to this index.

    7252:   Not Collective

    7254:   Input Parameters:
    7255: + dm   - The DM object
    7256: . l    - The index for the label
    7257: - name - The label name

    7259:   Level: intermediate

    7261: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7262: @*/
    7263: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
    7264: {
    7265:   DMLabelLink    orig, prev = NULL;
    7266:   DMLabel        label;
    7267:   PetscInt       Nl, m;
    7268:   PetscBool      flg, match;
    7269:   const char    *lname;

    7273:   DMHasLabel(dm, name, &flg);
    7274:   if (!flg) {
    7275:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7276:     DMAddLabel(dm, label);
    7277:     DMLabelDestroy(&label);
    7278:   }
    7279:   DMGetNumLabels(dm, &Nl);
    7281:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
    7282:     PetscObjectGetName((PetscObject) orig->label, &lname);
    7283:     PetscStrcmp(name, lname, &match);
    7284:     if (match) break;
    7285:   }
    7286:   if (m == l) return 0;
    7287:   if (!m) dm->labels = orig->next;
    7288:   else    prev->next = orig->next;
    7289:   if (!l) {
    7290:     orig->next = dm->labels;
    7291:     dm->labels = orig;
    7292:   } else {
    7293:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
    7294:     orig->next = prev->next;
    7295:     prev->next = orig;
    7296:   }
    7297:   return 0;
    7298: }

    7300: /*@C
    7301:   DMGetLabelValue - Get the value in a DMLabel for the given point, with -1 as the default

    7303:   Not Collective

    7305:   Input Parameters:
    7306: + dm   - The DM object
    7307: . name - The label name
    7308: - point - The mesh point

    7310:   Output Parameter:
    7311: . value - The label value for this point, or -1 if the point is not in the label

    7313:   Level: beginner

    7315: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
    7316: @*/
    7317: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
    7318: {
    7319:   DMLabel        label;

    7323:   DMGetLabel(dm, name, &label);
    7325:   DMLabelGetValue(label, point, value);
    7326:   return 0;
    7327: }

    7329: /*@C
    7330:   DMSetLabelValue - Add a point to a DMLabel with given value

    7332:   Not Collective

    7334:   Input Parameters:
    7335: + dm   - The DM object
    7336: . name - The label name
    7337: . point - The mesh point
    7338: - value - The label value for this point

    7340:   Output Parameter:

    7342:   Level: beginner

    7344: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
    7345: @*/
    7346: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7347: {
    7348:   DMLabel        label;

    7352:   DMGetLabel(dm, name, &label);
    7353:   if (!label) {
    7354:     DMCreateLabel(dm, name);
    7355:     DMGetLabel(dm, name, &label);
    7356:   }
    7357:   DMLabelSetValue(label, point, value);
    7358:   return 0;
    7359: }

    7361: /*@C
    7362:   DMClearLabelValue - Remove a point from a DMLabel with given value

    7364:   Not Collective

    7366:   Input Parameters:
    7367: + dm   - The DM object
    7368: . name - The label name
    7369: . point - The mesh point
    7370: - value - The label value for this point

    7372:   Output Parameter:

    7374:   Level: beginner

    7376: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
    7377: @*/
    7378: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7379: {
    7380:   DMLabel        label;

    7384:   DMGetLabel(dm, name, &label);
    7385:   if (!label) return 0;
    7386:   DMLabelClearValue(label, point, value);
    7387:   return 0;
    7388: }

    7390: /*@C
    7391:   DMGetLabelSize - Get the number of different integer ids in a Label

    7393:   Not Collective

    7395:   Input Parameters:
    7396: + dm   - The DM object
    7397: - name - The label name

    7399:   Output Parameter:
    7400: . size - The number of different integer ids, or 0 if the label does not exist

    7402:   Level: beginner

    7404: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
    7405: @*/
    7406: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
    7407: {
    7408:   DMLabel        label;

    7413:   DMGetLabel(dm, name, &label);
    7414:   *size = 0;
    7415:   if (!label) return 0;
    7416:   DMLabelGetNumValues(label, size);
    7417:   return 0;
    7418: }

    7420: /*@C
    7421:   DMGetLabelIdIS - Get the integer ids in a label

    7423:   Not Collective

    7425:   Input Parameters:
    7426: + mesh - The DM object
    7427: - name - The label name

    7429:   Output Parameter:
    7430: . ids - The integer ids, or NULL if the label does not exist

    7432:   Level: beginner

    7434: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
    7435: @*/
    7436: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
    7437: {
    7438:   DMLabel        label;

    7443:   DMGetLabel(dm, name, &label);
    7444:   *ids = NULL;
    7445:   if (label) {
    7446:     DMLabelGetValueIS(label, ids);
    7447:   } else {
    7448:     /* returning an empty IS */
    7449:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
    7450:   }
    7451:   return 0;
    7452: }

    7454: /*@C
    7455:   DMGetStratumSize - Get the number of points in a label stratum

    7457:   Not Collective

    7459:   Input Parameters:
    7460: + dm - The DM object
    7461: . name - The label name
    7462: - value - The stratum value

    7464:   Output Parameter:
    7465: . size - The stratum size

    7467:   Level: beginner

    7469: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
    7470: @*/
    7471: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
    7472: {
    7473:   DMLabel        label;

    7478:   DMGetLabel(dm, name, &label);
    7479:   *size = 0;
    7480:   if (!label) return 0;
    7481:   DMLabelGetStratumSize(label, value, size);
    7482:   return 0;
    7483: }

    7485: /*@C
    7486:   DMGetStratumIS - Get the points in a label stratum

    7488:   Not Collective

    7490:   Input Parameters:
    7491: + dm - The DM object
    7492: . name - The label name
    7493: - value - The stratum value

    7495:   Output Parameter:
    7496: . points - The stratum points, or NULL if the label does not exist or does not have that value

    7498:   Level: beginner

    7500: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
    7501: @*/
    7502: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
    7503: {
    7504:   DMLabel        label;

    7509:   DMGetLabel(dm, name, &label);
    7510:   *points = NULL;
    7511:   if (!label) return 0;
    7512:   DMLabelGetStratumIS(label, value, points);
    7513:   return 0;
    7514: }

    7516: /*@C
    7517:   DMSetStratumIS - Set the points in a label stratum

    7519:   Not Collective

    7521:   Input Parameters:
    7522: + dm - The DM object
    7523: . name - The label name
    7524: . value - The stratum value
    7525: - points - The stratum points

    7527:   Level: beginner

    7529: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
    7530: @*/
    7531: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
    7532: {
    7533:   DMLabel        label;

    7538:   DMGetLabel(dm, name, &label);
    7539:   if (!label) return 0;
    7540:   DMLabelSetStratumIS(label, value, points);
    7541:   return 0;
    7542: }

    7544: /*@C
    7545:   DMClearLabelStratum - Remove all points from a stratum from a DMLabel

    7547:   Not Collective

    7549:   Input Parameters:
    7550: + dm   - The DM object
    7551: . name - The label name
    7552: - value - The label value for this point

    7554:   Output Parameter:

    7556:   Level: beginner

    7558: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
    7559: @*/
    7560: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
    7561: {
    7562:   DMLabel        label;

    7566:   DMGetLabel(dm, name, &label);
    7567:   if (!label) return 0;
    7568:   DMLabelClearStratum(label, value);
    7569:   return 0;
    7570: }

    7572: /*@
    7573:   DMGetNumLabels - Return the number of labels defined by the mesh

    7575:   Not Collective

    7577:   Input Parameter:
    7578: . dm   - The DM object

    7580:   Output Parameter:
    7581: . numLabels - the number of Labels

    7583:   Level: intermediate

    7585: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7586: @*/
    7587: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
    7588: {
    7589:   DMLabelLink next = dm->labels;
    7590:   PetscInt  n    = 0;

    7594:   while (next) {++n; next = next->next;}
    7595:   *numLabels = n;
    7596:   return 0;
    7597: }

    7599: /*@C
    7600:   DMGetLabelName - Return the name of nth label

    7602:   Not Collective

    7604:   Input Parameters:
    7605: + dm - The DM object
    7606: - n  - the label number

    7608:   Output Parameter:
    7609: . name - the label name

    7611:   Level: intermediate

    7613: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7614: @*/
    7615: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
    7616: {
    7617:   DMLabelLink    next = dm->labels;
    7618:   PetscInt       l    = 0;

    7622:   while (next) {
    7623:     if (l == n) {
    7624:       PetscObjectGetName((PetscObject) next->label, name);
    7625:       return 0;
    7626:     }
    7627:     ++l;
    7628:     next = next->next;
    7629:   }
    7630:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7631: }

    7633: /*@C
    7634:   DMHasLabel - Determine whether the mesh has a label of a given name

    7636:   Not Collective

    7638:   Input Parameters:
    7639: + dm   - The DM object
    7640: - name - The label name

    7642:   Output Parameter:
    7643: . hasLabel - PETSC_TRUE if the label is present

    7645:   Level: intermediate

    7647: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7648: @*/
    7649: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
    7650: {
    7651:   DMLabelLink    next = dm->labels;
    7652:   const char    *lname;

    7657:   *hasLabel = PETSC_FALSE;
    7658:   while (next) {
    7659:     PetscObjectGetName((PetscObject) next->label, &lname);
    7660:     PetscStrcmp(name, lname, hasLabel);
    7661:     if (*hasLabel) break;
    7662:     next = next->next;
    7663:   }
    7664:   return 0;
    7665: }

    7667: /*@C
    7668:   DMGetLabel - Return the label of a given name, or NULL

    7670:   Not Collective

    7672:   Input Parameters:
    7673: + dm   - The DM object
    7674: - name - The label name

    7676:   Output Parameter:
    7677: . label - The DMLabel, or NULL if the label is absent

    7679:   Note: Some of the default labels in a DMPlex will be
    7680: $ "depth"       - Holds the depth (co-dimension) of each mesh point
    7681: $ "celltype"    - Holds the topological type of each cell
    7682: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
    7683: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
    7684: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
    7685: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

    7687:   Level: intermediate

    7689: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
    7690: @*/
    7691: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
    7692: {
    7693:   DMLabelLink    next = dm->labels;
    7694:   PetscBool      hasLabel;
    7695:   const char    *lname;

    7700:   *label = NULL;
    7701:   while (next) {
    7702:     PetscObjectGetName((PetscObject) next->label, &lname);
    7703:     PetscStrcmp(name, lname, &hasLabel);
    7704:     if (hasLabel) {
    7705:       *label = next->label;
    7706:       break;
    7707:     }
    7708:     next = next->next;
    7709:   }
    7710:   return 0;
    7711: }

    7713: /*@C
    7714:   DMGetLabelByNum - Return the nth label

    7716:   Not Collective

    7718:   Input Parameters:
    7719: + dm - The DM object
    7720: - n  - the label number

    7722:   Output Parameter:
    7723: . label - the label

    7725:   Level: intermediate

    7727: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7728: @*/
    7729: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
    7730: {
    7731:   DMLabelLink next = dm->labels;
    7732:   PetscInt    l    = 0;

    7736:   while (next) {
    7737:     if (l == n) {
    7738:       *label = next->label;
    7739:       return 0;
    7740:     }
    7741:     ++l;
    7742:     next = next->next;
    7743:   }
    7744:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7745: }

    7747: /*@C
    7748:   DMAddLabel - Add the label to this mesh

    7750:   Not Collective

    7752:   Input Parameters:
    7753: + dm   - The DM object
    7754: - label - The DMLabel

    7756:   Level: developer

    7758: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7759: @*/
    7760: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
    7761: {
    7762:   DMLabelLink    l, *p, tmpLabel;
    7763:   PetscBool      hasLabel;
    7764:   const char    *lname;
    7765:   PetscBool      flg;

    7768:   PetscObjectGetName((PetscObject) label, &lname);
    7769:   DMHasLabel(dm, lname, &hasLabel);
    7771:   PetscCalloc1(1, &tmpLabel);
    7772:   tmpLabel->label  = label;
    7773:   tmpLabel->output = PETSC_TRUE;
    7774:   for (p=&dm->labels; (l=*p); p=&l->next) {}
    7775:   *p = tmpLabel;
    7776:   PetscObjectReference((PetscObject)label);
    7777:   PetscStrcmp(lname, "depth", &flg);
    7778:   if (flg) dm->depthLabel = label;
    7779:   PetscStrcmp(lname, "celltype", &flg);
    7780:   if (flg) dm->celltypeLabel = label;
    7781:   return 0;
    7782: }

    7784: /*@C
    7785:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

    7787:   Not Collective

    7789:   Input Parameters:
    7790: + dm    - The DM object
    7791: - label - The DMLabel, having the same name, to substitute

    7793:   Note: Some of the default labels in a DMPlex will be
    7794: $ "depth"       - Holds the depth (co-dimension) of each mesh point
    7795: $ "celltype"    - Holds the topological type of each cell
    7796: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
    7797: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
    7798: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
    7799: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

    7801:   Level: intermediate

    7803: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
    7804: @*/
    7805: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
    7806: {
    7807:   DMLabelLink    next = dm->labels;
    7808:   PetscBool      hasLabel, flg;
    7809:   const char    *name, *lname;

    7813:   PetscObjectGetName((PetscObject) label, &name);
    7814:   while (next) {
    7815:     PetscObjectGetName((PetscObject) next->label, &lname);
    7816:     PetscStrcmp(name, lname, &hasLabel);
    7817:     if (hasLabel) {
    7818:       PetscObjectReference((PetscObject) label);
    7819:       PetscStrcmp(lname, "depth", &flg);
    7820:       if (flg) dm->depthLabel = label;
    7821:       PetscStrcmp(lname, "celltype", &flg);
    7822:       if (flg) dm->celltypeLabel = label;
    7823:       DMLabelDestroy(&next->label);
    7824:       next->label = label;
    7825:       break;
    7826:     }
    7827:     next = next->next;
    7828:   }
    7829:   return 0;
    7830: }

    7832: /*@C
    7833:   DMRemoveLabel - Remove the label given by name from this mesh

    7835:   Not Collective

    7837:   Input Parameters:
    7838: + dm   - The DM object
    7839: - name - The label name

    7841:   Output Parameter:
    7842: . label - The DMLabel, or NULL if the label is absent

    7844:   Level: developer

    7846:   Notes:
    7847:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
    7848:   DMLabelDestroy() on the label.

    7850:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
    7851:   call DMLabelDestroy(). Instead, the label is returned and the user is
    7852:   responsible of calling DMLabelDestroy() at some point.

    7854: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
    7855: @*/
    7856: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
    7857: {
    7858:   DMLabelLink    link, *pnext;
    7859:   PetscBool      hasLabel;
    7860:   const char    *lname;

    7864:   if (label) {
    7866:     *label = NULL;
    7867:   }
    7868:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7869:     PetscObjectGetName((PetscObject) link->label, &lname);
    7870:     PetscStrcmp(name, lname, &hasLabel);
    7871:     if (hasLabel) {
    7872:       *pnext = link->next; /* Remove from list */
    7873:       PetscStrcmp(name, "depth", &hasLabel);
    7874:       if (hasLabel) dm->depthLabel = NULL;
    7875:       PetscStrcmp(name, "celltype", &hasLabel);
    7876:       if (hasLabel) dm->celltypeLabel = NULL;
    7877:       if (label) *label = link->label;
    7878:       else       DMLabelDestroy(&link->label);
    7879:       PetscFree(link);
    7880:       break;
    7881:     }
    7882:   }
    7883:   return 0;
    7884: }

    7886: /*@
    7887:   DMRemoveLabelBySelf - Remove the label from this mesh

    7889:   Not Collective

    7891:   Input Parameters:
    7892: + dm   - The DM object
    7893: . label - The DMLabel to be removed from the DM
    7894: - failNotFound - Should it fail if the label is not found in the DM?

    7896:   Level: developer

    7898:   Notes:
    7899:   Only exactly the same instance is removed if found, name match is ignored.
    7900:   If the DM has an exclusive reference to the label, it gets destroyed and
    7901:   *label nullified.

    7903: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
    7904: @*/
    7905: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
    7906: {
    7907:   DMLabelLink    link, *pnext;
    7908:   PetscBool      hasLabel = PETSC_FALSE;

    7912:   if (!*label && !failNotFound) return 0;
    7915:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7916:     if (*label == link->label) {
    7917:       hasLabel = PETSC_TRUE;
    7918:       *pnext = link->next; /* Remove from list */
    7919:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
    7920:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    7921:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
    7922:       DMLabelDestroy(&link->label);
    7923:       PetscFree(link);
    7924:       break;
    7925:     }
    7926:   }
    7928:   return 0;
    7929: }

    7931: /*@C
    7932:   DMGetLabelOutput - Get the output flag for a given label

    7934:   Not Collective

    7936:   Input Parameters:
    7937: + dm   - The DM object
    7938: - name - The label name

    7940:   Output Parameter:
    7941: . output - The flag for output

    7943:   Level: developer

    7945: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7946: @*/
    7947: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
    7948: {
    7949:   DMLabelLink    next = dm->labels;
    7950:   const char    *lname;

    7955:   while (next) {
    7956:     PetscBool flg;

    7958:     PetscObjectGetName((PetscObject) next->label, &lname);
    7959:     PetscStrcmp(name, lname, &flg);
    7960:     if (flg) {*output = next->output; return 0;}
    7961:     next = next->next;
    7962:   }
    7963:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7964: }

    7966: /*@C
    7967:   DMSetLabelOutput - Set the output flag for a given label

    7969:   Not Collective

    7971:   Input Parameters:
    7972: + dm     - The DM object
    7973: . name   - The label name
    7974: - output - The flag for output

    7976:   Level: developer

    7978: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7979: @*/
    7980: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
    7981: {
    7982:   DMLabelLink    next = dm->labels;
    7983:   const char    *lname;

    7987:   while (next) {
    7988:     PetscBool flg;

    7990:     PetscObjectGetName((PetscObject) next->label, &lname);
    7991:     PetscStrcmp(name, lname, &flg);
    7992:     if (flg) {next->output = output; return 0;}
    7993:     next = next->next;
    7994:   }
    7995:   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7996: }

    7998: /*@
    7999:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

    8001:   Collective on dmA

    8003:   Input Parameters:
    8004: + dmA - The DM object with initial labels
    8005: . dmB - The DM object to which labels are copied
    8006: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
    8007: . all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
    8008: - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode)

    8010:   Level: intermediate

    8012:   Notes:
    8013:   This is typically used when interpolating or otherwise adding to a mesh, or testing.

    8015: .seealso: DMAddLabel(), DMCopyLabelsMode
    8016: @*/
    8017: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
    8018: {
    8019:   DMLabel        label, labelNew, labelOld;
    8020:   const char    *name;
    8021:   PetscBool      flg;
    8022:   DMLabelLink    link;

    8029:   if (dmA == dmB) return 0;
    8030:   for (link=dmA->labels; link; link=link->next) {
    8031:     label=link->label;
    8032:     PetscObjectGetName((PetscObject)label, &name);
    8033:     if (!all) {
    8034:       PetscStrcmp(name, "depth", &flg);
    8035:       if (flg) continue;
    8036:       PetscStrcmp(name, "dim", &flg);
    8037:       if (flg) continue;
    8038:       PetscStrcmp(name, "celltype", &flg);
    8039:       if (flg) continue;
    8040:     }
    8041:     DMGetLabel(dmB, name, &labelOld);
    8042:     if (labelOld) {
    8043:       switch (emode) {
    8044:         case DM_COPY_LABELS_KEEP:
    8045:           continue;
    8046:         case DM_COPY_LABELS_REPLACE:
    8047:           DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE);
    8048:           break;
    8049:         case DM_COPY_LABELS_FAIL:
    8050:           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
    8051:         default:
    8052:           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
    8053:       }
    8054:     }
    8055:     if (mode==PETSC_COPY_VALUES) {
    8056:       DMLabelDuplicate(label, &labelNew);
    8057:     } else {
    8058:       labelNew = label;
    8059:     }
    8060:     DMAddLabel(dmB, labelNew);
    8061:     if (mode==PETSC_COPY_VALUES) DMLabelDestroy(&labelNew);
    8062:   }
    8063:   return 0;
    8064: }

    8066: /*@C
    8067:   DMCompareLabels - Compare labels of two DMPlex meshes

    8069:   Collective

    8071:   Input Parameters:
    8072: + dm0 - First DM object
    8073: - dm1 - Second DM object

    8075:   Output Parameters
    8076: + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
    8077: - message - (Optional) Message describing the difference, or NULL if there is no difference

    8079:   Level: intermediate

    8081:   Notes:
    8082:   The output flag equal is the same on all processes.
    8083:   If it is passed as NULL and difference is found, an error is thrown on all processes.
    8084:   Make sure to pass NULL on all processes.

    8086:   The output message is set independently on each rank.
    8087:   It is set to NULL if no difference was found on the current rank. It must be freed by user.
    8088:   If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner.
    8089:   Make sure to pass NULL on all processes.

    8091:   Labels are matched by name. If the number of labels and their names are equal,
    8092:   DMLabelCompare() is used to compare each pair of labels with the same name.

    8094:   Fortran Notes:
    8095:   This function is currently not available from Fortran.

    8097: .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare()
    8098: @*/
    8099: PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
    8100: {
    8101:   PetscInt        n, i;
    8102:   char            msg[PETSC_MAX_PATH_LEN] = "";
    8103:   PetscBool       eq;
    8104:   MPI_Comm        comm;
    8105:   PetscMPIInt     rank;

    8112:   PetscObjectGetComm((PetscObject)dm0, &comm);
    8113:   MPI_Comm_rank(comm, &rank);
    8114:   {
    8115:     PetscInt n1;

    8117:     DMGetNumLabels(dm0, &n);
    8118:     DMGetNumLabels(dm1, &n1);
    8119:     eq = (PetscBool) (n == n1);
    8120:     if (!eq) {
    8121:       PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %D != %D = Number of labels in dm1", n, n1);
    8122:     }
    8123:     MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
    8124:     if (!eq) goto finish;
    8125:   }
    8126:   for (i=0; i<n; i++) {
    8127:     DMLabel     l0, l1;
    8128:     const char *name;
    8129:     char       *msgInner;

    8131:     /* Ignore label order */
    8132:     DMGetLabelByNum(dm0, i, &l0);
    8133:     PetscObjectGetName((PetscObject)l0, &name);
    8134:     DMGetLabel(dm1, name, &l1);
    8135:     if (!l1) {
    8136:       PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%D in dm0) not found in dm1", name, i);
    8137:       eq = PETSC_FALSE;
    8138:       break;
    8139:     }
    8140:     DMLabelCompare(comm, l0, l1, &eq, &msgInner);
    8141:     PetscStrncpy(msg, msgInner, sizeof(msg));
    8142:     PetscFree(msgInner);
    8143:     if (!eq) break;
    8144:   }
    8145:   MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm);
    8146: finish:
    8147:   /* If message output arg not set, print to stderr */
    8148:   if (message) {
    8149:     *message = NULL;
    8150:     if (msg[0]) {
    8151:       PetscStrallocpy(msg, message);
    8152:     }
    8153:   } else {
    8154:     if (msg[0]) {
    8155:       PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg);
    8156:     }
    8157:     PetscSynchronizedFlush(comm, PETSC_STDERR);
    8158:   }
    8159:   /* If same output arg not ser and labels are not equal, throw error */
    8160:   if (equal) *equal = eq;
    8162:   return 0;
    8163: }

    8165: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
    8166: {
    8168:   if (!*label) {
    8169:     DMCreateLabel(dm, name);
    8170:     DMGetLabel(dm, name, label);
    8171:   }
    8172:   DMLabelSetValue(*label, point, value);
    8173:   return 0;
    8174: }

    8176: /*
    8177:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
    8178:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
    8179:   (label, id) pair in the DM.

    8181:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
    8182:   each label.
    8183: */
    8184: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
    8185: {
    8186:   DMUniversalLabel ul;
    8187:   PetscBool       *active;
    8188:   PetscInt         pStart, pEnd, p, Nl, l, m;

    8190:   PetscMalloc1(1, &ul);
    8191:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
    8192:   DMGetNumLabels(dm, &Nl);
    8193:   PetscCalloc1(Nl, &active);
    8194:   ul->Nl = 0;
    8195:   for (l = 0; l < Nl; ++l) {
    8196:     PetscBool   isdepth, iscelltype;
    8197:     const char *name;

    8199:     DMGetLabelName(dm, l, &name);
    8200:     PetscStrncmp(name, "depth", 6, &isdepth);
    8201:     PetscStrncmp(name, "celltype", 9, &iscelltype);
    8202:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
    8203:     if (active[l]) ++ul->Nl;
    8204:   }
    8205:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
    8206:   ul->Nv = 0;
    8207:   for (l = 0, m = 0; l < Nl; ++l) {
    8208:     DMLabel     label;
    8209:     PetscInt    nv;
    8210:     const char *name;

    8212:     if (!active[l]) continue;
    8213:     DMGetLabelName(dm, l, &name);
    8214:     DMGetLabelByNum(dm, l, &label);
    8215:     DMLabelGetNumValues(label, &nv);
    8216:     PetscStrallocpy(name, &ul->names[m]);
    8217:     ul->indices[m]   = l;
    8218:     ul->Nv          += nv;
    8219:     ul->offsets[m+1] = nv;
    8220:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
    8221:     ++m;
    8222:   }
    8223:   for (l = 1; l <= ul->Nl; ++l) {
    8224:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
    8225:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
    8226:   }
    8227:   for (l = 0; l < ul->Nl; ++l) {
    8228:     PetscInt b;

    8230:     ul->masks[l] = 0;
    8231:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
    8232:   }
    8233:   PetscMalloc1(ul->Nv, &ul->values);
    8234:   for (l = 0, m = 0; l < Nl; ++l) {
    8235:     DMLabel         label;
    8236:     IS              valueIS;
    8237:     const PetscInt *varr;
    8238:     PetscInt        nv, v;

    8240:     if (!active[l]) continue;
    8241:     DMGetLabelByNum(dm, l, &label);
    8242:     DMLabelGetNumValues(label, &nv);
    8243:     DMLabelGetValueIS(label, &valueIS);
    8244:     ISGetIndices(valueIS, &varr);
    8245:     for (v = 0; v < nv; ++v) {
    8246:       ul->values[ul->offsets[m]+v] = varr[v];
    8247:     }
    8248:     ISRestoreIndices(valueIS, &varr);
    8249:     ISDestroy(&valueIS);
    8250:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
    8251:     ++m;
    8252:   }
    8253:   DMPlexGetChart(dm, &pStart, &pEnd);
    8254:   for (p = pStart; p < pEnd; ++p) {
    8255:     PetscInt  uval = 0;
    8256:     PetscBool marked = PETSC_FALSE;

    8258:     for (l = 0, m = 0; l < Nl; ++l) {
    8259:       DMLabel  label;
    8260:       PetscInt val, defval, loc, nv;

    8262:       if (!active[l]) continue;
    8263:       DMGetLabelByNum(dm, l, &label);
    8264:       DMLabelGetValue(label, p, &val);
    8265:       DMLabelGetDefaultValue(label, &defval);
    8266:       if (val == defval) {++m; continue;}
    8267:       nv = ul->offsets[m+1]-ul->offsets[m];
    8268:       marked = PETSC_TRUE;
    8269:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
    8271:       uval += (loc+1) << ul->bits[m];
    8272:       ++m;
    8273:     }
    8274:     if (marked) DMLabelSetValue(ul->label, p, uval);
    8275:   }
    8276:   PetscFree(active);
    8277:   *universal = ul;
    8278:   return 0;
    8279: }

    8281: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
    8282: {
    8283:   PetscInt       l;

    8285:   for (l = 0; l < (*universal)->Nl; ++l) PetscFree((*universal)->names[l]);
    8286:   DMLabelDestroy(&(*universal)->label);
    8287:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
    8288:   PetscFree((*universal)->values);
    8289:   PetscFree(*universal);
    8290:   *universal = NULL;
    8291:   return 0;
    8292: }

    8294: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
    8295: {
    8297:   *ulabel = ul->label;
    8298:   return 0;
    8299: }

    8301: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
    8302: {
    8303:   PetscInt       Nl = ul->Nl, l;

    8306:   for (l = 0; l < Nl; ++l) {
    8307:     if (preserveOrder) DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);
    8308:     else               DMCreateLabel(dm, ul->names[l]);
    8309:   }
    8310:   if (preserveOrder) {
    8311:     for (l = 0; l < ul->Nl; ++l) {
    8312:       const char *name;
    8313:       PetscBool   match;

    8315:       DMGetLabelName(dm, ul->indices[l], &name);
    8316:       PetscStrcmp(name, ul->names[l], &match);
    8318:     }
    8319:   }
    8320:   return 0;
    8321: }

    8323: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
    8324: {
    8325:   PetscInt       l;

    8327:   for (l = 0; l < ul->Nl; ++l) {
    8328:     DMLabel  label;
    8329:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

    8331:     if (lval) {
    8332:       if (useIndex) DMGetLabelByNum(dm, ul->indices[l], &label);
    8333:       else          DMGetLabel(dm, ul->names[l], &label);
    8334:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
    8335:     }
    8336:   }
    8337:   return 0;
    8338: }

    8340: /*@
    8341:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

    8343:   Input Parameter:
    8344: . dm - The DM object

    8346:   Output Parameter:
    8347: . cdm - The coarse DM

    8349:   Level: intermediate

    8351: .seealso: DMSetCoarseDM()
    8352: @*/
    8353: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
    8354: {
    8357:   *cdm = dm->coarseMesh;
    8358:   return 0;
    8359: }

    8361: /*@
    8362:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

    8364:   Input Parameters:
    8365: + dm - The DM object
    8366: - cdm - The coarse DM

    8368:   Level: intermediate

    8370: .seealso: DMGetCoarseDM()
    8371: @*/
    8372: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
    8373: {
    8376:   PetscObjectReference((PetscObject)cdm);
    8377:   DMDestroy(&dm->coarseMesh);
    8378:   dm->coarseMesh = cdm;
    8379:   return 0;
    8380: }

    8382: /*@
    8383:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

    8385:   Input Parameter:
    8386: . dm - The DM object

    8388:   Output Parameter:
    8389: . fdm - The fine DM

    8391:   Level: intermediate

    8393: .seealso: DMSetFineDM()
    8394: @*/
    8395: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
    8396: {
    8399:   *fdm = dm->fineMesh;
    8400:   return 0;
    8401: }

    8403: /*@
    8404:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

    8406:   Input Parameters:
    8407: + dm - The DM object
    8408: - fdm - The fine DM

    8410:   Level: intermediate

    8412: .seealso: DMGetFineDM()
    8413: @*/
    8414: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
    8415: {
    8418:   PetscObjectReference((PetscObject)fdm);
    8419:   DMDestroy(&dm->fineMesh);
    8420:   dm->fineMesh = fdm;
    8421:   return 0;
    8422: }

    8424: /*=== DMBoundary code ===*/

    8426: /*@C
    8427:   DMAddBoundary - Add a boundary condition to the model

    8429:   Collective on dm

    8431:   Input Parameters:
    8432: + dm       - The DM, with a PetscDS that matches the problem being constrained
    8433: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8434: . name     - The BC name
    8435: . label    - The label defining constrained points
    8436: . Nv       - The number of DMLabel values for constrained points
    8437: . values   - An array of values for constrained points
    8438: . field    - The field to constrain
    8439: . Nc       - The number of constrained field components (0 will constrain all fields)
    8440: . comps    - An array of constrained component numbers
    8441: . bcFunc   - A pointwise function giving boundary values
    8442: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
    8443: - ctx      - An optional user context for bcFunc

    8445:   Output Parameter:
    8446: . bd          - (Optional) Boundary number

    8448:   Options Database Keys:
    8449: + -bc_<boundary name> <num> - Overrides the boundary ids
    8450: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8452:   Note:
    8453:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

    8455: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

    8457:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    8459: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8460: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8461: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8462: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    8464: + dim - the spatial dimension
    8465: . Nf - the number of fields
    8466: . uOff - the offset into u[] and u_t[] for each field
    8467: . uOff_x - the offset into u_x[] for each field
    8468: . u - each field evaluated at the current point
    8469: . u_t - the time derivative of each field evaluated at the current point
    8470: . u_x - the gradient of each field evaluated at the current point
    8471: . aOff - the offset into a[] and a_t[] for each auxiliary field
    8472: . aOff_x - the offset into a_x[] for each auxiliary field
    8473: . a - each auxiliary field evaluated at the current point
    8474: . a_t - the time derivative of each auxiliary field evaluated at the current point
    8475: . a_x - the gradient of auxiliary each field evaluated at the current point
    8476: . t - current time
    8477: . x - coordinates of the current point
    8478: . numConstants - number of constant parameters
    8479: . constants - constant parameters
    8480: - bcval - output values at the current point

    8482:   Level: intermediate

    8484: .seealso: DSGetBoundary(), PetscDSAddBoundary()
    8485: @*/
    8486: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
    8487: {
    8488:   PetscDS        ds;

    8496:   DMGetDS(dm, &ds);
    8497:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
    8498:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
    8499:   return 0;
    8500: }

    8502: /* TODO Remove this since now the structures are the same */
    8503: static PetscErrorCode DMPopulateBoundary(DM dm)
    8504: {
    8505:   PetscDS        ds;
    8506:   DMBoundary    *lastnext;
    8507:   DSBoundary     dsbound;

    8509:   DMGetDS(dm, &ds);
    8510:   dsbound = ds->boundary;
    8511:   if (dm->boundary) {
    8512:     DMBoundary next = dm->boundary;

    8514:     /* quick check to see if the PetscDS has changed */
    8515:     if (next->dsboundary == dsbound) return 0;
    8516:     /* the PetscDS has changed: tear down and rebuild */
    8517:     while (next) {
    8518:       DMBoundary b = next;

    8520:       next = b->next;
    8521:       PetscFree(b);
    8522:     }
    8523:     dm->boundary = NULL;
    8524:   }

    8526:   lastnext = &(dm->boundary);
    8527:   while (dsbound) {
    8528:     DMBoundary dmbound;

    8530:     PetscNew(&dmbound);
    8531:     dmbound->dsboundary = dsbound;
    8532:     dmbound->label      = dsbound->label;
    8533:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
    8534:     *lastnext = dmbound;
    8535:     lastnext = &(dmbound->next);
    8536:     dsbound = dsbound->next;
    8537:   }
    8538:   return 0;
    8539: }

    8541: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
    8542: {
    8543:   DMBoundary     b;

    8547:   *isBd = PETSC_FALSE;
    8548:   DMPopulateBoundary(dm);
    8549:   b = dm->boundary;
    8550:   while (b && !(*isBd)) {
    8551:     DMLabel    label = b->label;
    8552:     DSBoundary dsb   = b->dsboundary;
    8553:     PetscInt   i;

    8555:     if (label) {
    8556:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);
    8557:     }
    8558:     b = b->next;
    8559:   }
    8560:   return 0;
    8561: }

    8563: /*@C
    8564:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

    8566:   Collective on DM

    8568:   Input Parameters:
    8569: + dm      - The DM
    8570: . time    - The time
    8571: . funcs   - The coordinate functions to evaluate, one per field
    8572: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8573: - mode    - The insertion mode for values

    8575:   Output Parameter:
    8576: . X - vector

    8578:    Calling sequence of func:
    8579: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8581: +  dim - The spatial dimension
    8582: .  time - The time at which to sample
    8583: .  x   - The coordinates
    8584: .  Nc  - The number of components
    8585: .  u   - The output field values
    8586: -  ctx - optional user-defined function context

    8588:   Level: developer

    8590: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8591: @*/
    8592: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
    8593: {
    8594:   Vec            localX;

    8597:   DMGetLocalVector(dm, &localX);
    8598:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
    8599:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8600:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8601:   DMRestoreLocalVector(dm, &localX);
    8602:   return 0;
    8603: }

    8605: /*@C
    8606:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

    8608:   Not collective

    8610:   Input Parameters:
    8611: + dm      - The DM
    8612: . time    - The time
    8613: . funcs   - The coordinate functions to evaluate, one per field
    8614: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8615: - mode    - The insertion mode for values

    8617:   Output Parameter:
    8618: . localX - vector

    8620:    Calling sequence of func:
    8621: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8623: +  dim - The spatial dimension
    8624: .  x   - The coordinates
    8625: .  Nc  - The number of components
    8626: .  u   - The output field values
    8627: -  ctx - optional user-defined function context

    8629:   Level: developer

    8631: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8632: @*/
    8633: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
    8634: {
    8638:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
    8639:   return 0;
    8640: }

    8642: /*@C
    8643:   DMProjectFunctionLabel - This projects the given function into the function space provided, putting the coefficients in a global vector, setting values only for points in the given label.

    8645:   Collective on DM

    8647:   Input Parameters:
    8648: + dm      - The DM
    8649: . time    - The time
    8650: . label   - The DMLabel selecting the portion of the mesh for projection
    8651: . funcs   - The coordinate functions to evaluate, one per field
    8652: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8653: - mode    - The insertion mode for values

    8655:   Output Parameter:
    8656: . X - vector

    8658:    Calling sequence of func:
    8659: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8661: +  dim - The spatial dimension
    8662: .  x   - The coordinates
    8663: .  Nc  - The number of components
    8664: .  u   - The output field values
    8665: -  ctx - optional user-defined function context

    8667:   Level: developer

    8669: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
    8670: @*/
    8671: PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
    8672: {
    8673:   Vec            localX;

    8676:   DMGetLocalVector(dm, &localX);
    8677:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8678:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8679:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8680:   DMRestoreLocalVector(dm, &localX);
    8681:   return 0;
    8682: }

    8684: /*@C
    8685:   DMProjectFunctionLabelLocal - This projects the given function into the function space provided, putting the coefficients in a local vector, setting values only for points in the given label.

    8687:   Not collective

    8689:   Input Parameters:
    8690: + dm      - The DM
    8691: . time    - The time
    8692: . label   - The DMLabel selecting the portion of the mesh for projection
    8693: . funcs   - The coordinate functions to evaluate, one per field
    8694: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8695: - mode    - The insertion mode for values

    8697:   Output Parameter:
    8698: . localX - vector

    8700:    Calling sequence of func:
    8701: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8703: +  dim - The spatial dimension
    8704: .  x   - The coordinates
    8705: .  Nc  - The number of components
    8706: .  u   - The output field values
    8707: -  ctx - optional user-defined function context

    8709:   Level: developer

    8711: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8712: @*/
    8713: PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
    8714: {
    8718:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8719:   return 0;
    8720: }

    8722: /*@C
    8723:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

    8725:   Not collective

    8727:   Input Parameters:
    8728: + dm      - The DM
    8729: . time    - The time
    8730: . localU  - The input field vector
    8731: . funcs   - The functions to evaluate, one per field
    8732: - mode    - The insertion mode for values

    8734:   Output Parameter:
    8735: . localX  - The output vector

    8737:    Calling sequence of func:
    8738: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8739: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8740: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8741: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8743: +  dim          - The spatial dimension
    8744: .  Nf           - The number of input fields
    8745: .  NfAux        - The number of input auxiliary fields
    8746: .  uOff         - The offset of each field in u[]
    8747: .  uOff_x       - The offset of each field in u_x[]
    8748: .  u            - The field values at this point in space
    8749: .  u_t          - The field time derivative at this point in space (or NULL)
    8750: .  u_x          - The field derivatives at this point in space
    8751: .  aOff         - The offset of each auxiliary field in u[]
    8752: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8753: .  a            - The auxiliary field values at this point in space
    8754: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8755: .  a_x          - The auxiliary field derivatives at this point in space
    8756: .  t            - The current time
    8757: .  x            - The coordinates of this point
    8758: .  numConstants - The number of constants
    8759: .  constants    - The value of each constant
    8760: -  f            - The value of the function at this point in space

    8762:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8763:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
    8764:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8765:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8767:   Level: intermediate

    8769: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8770: @*/
    8771: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
    8772:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
    8773:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8774:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8775:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8776:                                    InsertMode mode, Vec localX)
    8777: {
    8782:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
    8783:   return 0;
    8784: }

    8786: /*@C
    8787:   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.

    8789:   Not collective

    8791:   Input Parameters:
    8792: + dm      - The DM
    8793: . time    - The time
    8794: . label   - The DMLabel marking the portion of the domain to output
    8795: . numIds  - The number of label ids to use
    8796: . ids     - The label ids to use for marking
    8797: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8798: . comps   - The components to set in the output, or NULL for all components
    8799: . localU  - The input field vector
    8800: . funcs   - The functions to evaluate, one per field
    8801: - mode    - The insertion mode for values

    8803:   Output Parameter:
    8804: . localX  - The output vector

    8806:    Calling sequence of func:
    8807: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8808: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8809: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8810: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8812: +  dim          - The spatial dimension
    8813: .  Nf           - The number of input fields
    8814: .  NfAux        - The number of input auxiliary fields
    8815: .  uOff         - The offset of each field in u[]
    8816: .  uOff_x       - The offset of each field in u_x[]
    8817: .  u            - The field values at this point in space
    8818: .  u_t          - The field time derivative at this point in space (or NULL)
    8819: .  u_x          - The field derivatives at this point in space
    8820: .  aOff         - The offset of each auxiliary field in u[]
    8821: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8822: .  a            - The auxiliary field values at this point in space
    8823: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8824: .  a_x          - The auxiliary field derivatives at this point in space
    8825: .  t            - The current time
    8826: .  x            - The coordinates of this point
    8827: .  numConstants - The number of constants
    8828: .  constants    - The value of each constant
    8829: -  f            - The value of the function at this point in space

    8831:   Note: There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8832:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
    8833:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8834:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8836:   Level: intermediate

    8838: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8839: @*/
    8840: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8841:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
    8842:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8843:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8844:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8845:                                         InsertMode mode, Vec localX)
    8846: {
    8851:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8852:   return 0;
    8853: }

    8855: /*@C
    8856:   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.

    8858:   Not collective

    8860:   Input Parameters:
    8861: + dm      - The DM
    8862: . time    - The time
    8863: . label   - The DMLabel marking the portion of the domain boundary to output
    8864: . numIds  - The number of label ids to use
    8865: . ids     - The label ids to use for marking
    8866: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8867: . comps   - The components to set in the output, or NULL for all components
    8868: . localU  - The input field vector
    8869: . funcs   - The functions to evaluate, one per field
    8870: - mode    - The insertion mode for values

    8872:   Output Parameter:
    8873: . localX  - The output vector

    8875:    Calling sequence of func:
    8876: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8877: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8878: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8879: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8881: +  dim          - The spatial dimension
    8882: .  Nf           - The number of input fields
    8883: .  NfAux        - The number of input auxiliary fields
    8884: .  uOff         - The offset of each field in u[]
    8885: .  uOff_x       - The offset of each field in u_x[]
    8886: .  u            - The field values at this point in space
    8887: .  u_t          - The field time derivative at this point in space (or NULL)
    8888: .  u_x          - The field derivatives at this point in space
    8889: .  aOff         - The offset of each auxiliary field in u[]
    8890: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8891: .  a            - The auxiliary field values at this point in space
    8892: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8893: .  a_x          - The auxiliary field derivatives at this point in space
    8894: .  t            - The current time
    8895: .  x            - The coordinates of this point
    8896: .  n            - The face normal
    8897: .  numConstants - The number of constants
    8898: .  constants    - The value of each constant
    8899: -  f            - The value of the function at this point in space

    8901:   Note:
    8902:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8903:   The input DM, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
    8904:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8905:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8907:   Level: intermediate

    8909: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8910: @*/
    8911: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8912:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
    8913:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8914:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8915:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8916:                                           InsertMode mode, Vec localX)
    8917: {
    8922:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8923:   return 0;
    8924: }

    8926: /*@C
    8927:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

    8929:   Input Parameters:
    8930: + dm    - The DM
    8931: . time  - The time
    8932: . funcs - The functions to evaluate for each field component
    8933: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8934: - X     - The coefficient vector u_h, a global vector

    8936:   Output Parameter:
    8937: . diff - The diff ||u - u_h||_2

    8939:   Level: developer

    8941: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8942: @*/
    8943: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
    8944: {
    8948:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
    8949:   return 0;
    8950: }

    8952: /*@C
    8953:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

    8955:   Collective on dm

    8957:   Input Parameters:
    8958: + dm    - The DM
    8959: , time  - The time
    8960: . funcs - The gradient functions to evaluate for each field component
    8961: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8962: . X     - The coefficient vector u_h, a global vector
    8963: - n     - The vector to project along

    8965:   Output Parameter:
    8966: . diff - The diff ||(grad u - grad u_h) . n||_2

    8968:   Level: developer

    8970: .seealso: DMProjectFunction(), DMComputeL2Diff()
    8971: @*/
    8972: PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
    8973: {
    8977:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
    8978:   return 0;
    8979: }

    8981: /*@C
    8982:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

    8984:   Collective on dm

    8986:   Input Parameters:
    8987: + dm    - The DM
    8988: . time  - The time
    8989: . funcs - The functions to evaluate for each field component
    8990: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8991: - X     - The coefficient vector u_h, a global vector

    8993:   Output Parameter:
    8994: . diff - The array of differences, ||u^f - u^f_h||_2

    8996:   Level: developer

    8998: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8999: @*/
    9000: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
    9001: {
    9005:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
    9006:   return 0;
    9007: }

    9009: /*@C
    9010:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

    9012:  Not Collective

    9014:  Input Parameter:
    9015: .  dm    - The DM

    9017:  Output Parameters:
    9018: +  nranks - the number of neighbours
    9019: -  ranks - the neighbors ranks

    9021:  Notes:
    9022:  Do not free the array, it is freed when the DM is destroyed.

    9024:  Level: beginner

    9026:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
    9027: @*/
    9028: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
    9029: {
    9032:   (dm->ops->getneighbors)(dm,nranks,ranks);
    9033:   return 0;
    9034: }

    9036: #include <petsc/private/matimpl.h>

    9038: /*
    9039:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
    9040:     This has be a different function because it requires DM which is not defined in the Mat library
    9041: */
    9042: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
    9043: {
    9044:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9045:     Vec x1local;
    9046:     DM  dm;
    9047:     MatGetDM(J,&dm);
    9049:     DMGetLocalVector(dm,&x1local);
    9050:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
    9051:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
    9052:     x1   = x1local;
    9053:   }
    9054:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
    9055:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9056:     DM  dm;
    9057:     MatGetDM(J,&dm);
    9058:     DMRestoreLocalVector(dm,&x1);
    9059:   }
    9060:   return 0;
    9061: }

    9063: /*@
    9064:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

    9066:     Input Parameter:
    9067: .    coloring - the MatFDColoring object

    9069:     Developer Notes:
    9070:     this routine exists because the PETSc Mat library does not know about the DM objects

    9072:     Level: advanced

    9074: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
    9075: @*/
    9076: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
    9077: {
    9078:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
    9079:   return 0;
    9080: }

    9082: /*@
    9083:     DMGetCompatibility - determine if two DMs are compatible

    9085:     Collective

    9087:     Input Parameters:
    9088: +    dm1 - the first DM
    9089: -    dm2 - the second DM

    9091:     Output Parameters:
    9092: +    compatible - whether or not the two DMs are compatible
    9093: -    set - whether or not the compatible value was set

    9095:     Notes:
    9096:     Two DMs are deemed compatible if they represent the same parallel decomposition
    9097:     of the same topology. This implies that the section (field data) on one
    9098:     "makes sense" with respect to the topology and parallel decomposition of the other.
    9099:     Loosely speaking, compatible DMs represent the same domain and parallel
    9100:     decomposition, but hold different data.

    9102:     Typically, one would confirm compatibility if intending to simultaneously iterate
    9103:     over a pair of vectors obtained from different DMs.

    9105:     For example, two DMDA objects are compatible if they have the same local
    9106:     and global sizes and the same stencil width. They can have different numbers
    9107:     of degrees of freedom per node. Thus, one could use the node numbering from
    9108:     either DM in bounds for a loop over vectors derived from either DM.

    9110:     Consider the operation of summing data living on a 2-dof DMDA to data living
    9111:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
    9112: .vb
    9113:   ...
    9114:   DMGetCompatibility(da1,da2,&compatible,&set);
    9115:   if (set && compatible)  {
    9116:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
    9117:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
    9118:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
    9119:     for (j=y; j<y+n; ++j) {
    9120:       for (i=x; i<x+m, ++i) {
    9121:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
    9122:       }
    9123:     }
    9124:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
    9125:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
    9126:   } else {
    9127:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
    9128:   }
    9129:   ...
    9130: .ve

    9132:     Checking compatibility might be expensive for a given implementation of DM,
    9133:     or might be impossible to unambiguously confirm or deny. For this reason,
    9134:     this function may decline to determine compatibility, and hence users should
    9135:     always check the "set" output parameter.

    9137:     A DM is always compatible with itself.

    9139:     In the current implementation, DMs which live on "unequal" communicators
    9140:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
    9141:     incompatible.

    9143:     This function is labeled "Collective," as information about all subdomains
    9144:     is required on each rank. However, in DM implementations which store all this
    9145:     information locally, this function may be merely "Logically Collective".

    9147:     Developer Notes:
    9148:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
    9149:     iff B is compatible with A. Thus, this function checks the implementations
    9150:     of both dm and dmc (if they are of different types), attempting to determine
    9151:     compatibility. It is left to DM implementers to ensure that symmetry is
    9152:     preserved. The simplest way to do this is, when implementing type-specific
    9153:     logic for this function, is to check for existing logic in the implementation
    9154:     of other DM types and let *set = PETSC_FALSE if found.

    9156:     Level: advanced

    9158: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
    9159: @*/

    9161: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
    9162: {
    9163:   PetscMPIInt    compareResult;
    9164:   DMType         type,type2;
    9165:   PetscBool      sameType;

    9170:   /* Declare a DM compatible with itself */
    9171:   if (dm1 == dm2) {
    9172:     *set = PETSC_TRUE;
    9173:     *compatible = PETSC_TRUE;
    9174:     return 0;
    9175:   }

    9177:   /* Declare a DM incompatible with a DM that lives on an "unequal"
    9178:      communicator. Note that this does not preclude compatibility with
    9179:      DMs living on "congruent" or "similar" communicators, but this must be
    9180:      determined by the implementation-specific logic */
    9181:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
    9182:   if (compareResult == MPI_UNEQUAL) {
    9183:     *set = PETSC_TRUE;
    9184:     *compatible = PETSC_FALSE;
    9185:     return 0;
    9186:   }

    9188:   /* Pass to the implementation-specific routine, if one exists. */
    9189:   if (dm1->ops->getcompatibility) {
    9190:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
    9191:     if (*set) return 0;
    9192:   }

    9194:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
    9195:      with an implementation of this function from dm2 */
    9196:   DMGetType(dm1,&type);
    9197:   DMGetType(dm2,&type2);
    9198:   PetscStrcmp(type,type2,&sameType);
    9199:   if (!sameType && dm2->ops->getcompatibility) {
    9200:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
    9201:   } else {
    9202:     *set = PETSC_FALSE;
    9203:   }
    9204:   return 0;
    9205: }

    9207: /*@C
    9208:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

    9210:   Logically Collective on DM

    9212:   Input Parameters:
    9213: + DM - the DM
    9214: . f - the monitor function
    9215: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
    9216: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

    9218:   Options Database Keys:
    9219: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
    9220:                             does not cancel those set via the options database.

    9222:   Notes:
    9223:   Several different monitoring routines may be set by calling
    9224:   DMMonitorSet() multiple times; all will be called in the
    9225:   order in which they were set.

    9227:   Fortran Notes:
    9228:   Only a single monitor function can be set for each DM object

    9230:   Level: intermediate

    9232: .seealso: DMMonitorCancel()
    9233: @*/
    9234: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
    9235: {
    9236:   PetscInt       m;

    9239:   for (m = 0; m < dm->numbermonitors; ++m) {
    9240:     PetscBool identical;

    9242:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
    9243:     if (identical) return 0;
    9244:   }
    9246:   dm->monitor[dm->numbermonitors]          = f;
    9247:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
    9248:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
    9249:   return 0;
    9250: }

    9252: /*@
    9253:   DMMonitorCancel - Clears all the monitor functions for a DM object.

    9255:   Logically Collective on DM

    9257:   Input Parameter:
    9258: . dm - the DM

    9260:   Options Database Key:
    9261: . -dm_monitor_cancel - cancels all monitors that have been hardwired
    9262:   into a code by calls to DMonitorSet(), but does not cancel those
    9263:   set via the options database

    9265:   Notes:
    9266:   There is no way to clear one specific monitor from a DM object.

    9268:   Level: intermediate

    9270: .seealso: DMMonitorSet()
    9271: @*/
    9272: PetscErrorCode DMMonitorCancel(DM dm)
    9273: {
    9274:   PetscInt       m;

    9277:   for (m = 0; m < dm->numbermonitors; ++m) {
    9278:     if (dm->monitordestroy[m]) (*dm->monitordestroy[m])(&dm->monitorcontext[m]);
    9279:   }
    9280:   dm->numbermonitors = 0;
    9281:   return 0;
    9282: }

    9284: /*@C
    9285:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

    9287:   Collective on DM

    9289:   Input Parameters:
    9290: + dm   - DM object you wish to monitor
    9291: . name - the monitor type one is seeking
    9292: . help - message indicating what monitoring is done
    9293: . manual - manual page for the monitor
    9294: . monitor - the monitor function
    9295: - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the DM or PetscViewer objects

    9297:   Output Parameter:
    9298: . flg - Flag set if the monitor was created

    9300:   Level: developer

    9302: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
    9303:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
    9304:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
    9305:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
    9306:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
    9307:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
    9308:           PetscOptionsFList(), PetscOptionsEList()
    9309: @*/
    9310: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
    9311: {
    9312:   PetscViewer       viewer;
    9313:   PetscViewerFormat format;

    9316:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
    9317:   if (*flg) {
    9318:     PetscViewerAndFormat *vf;

    9320:     PetscViewerAndFormatCreate(viewer, format, &vf);
    9321:     PetscObjectDereference((PetscObject) viewer);
    9322:     if (monitorsetup) (*monitorsetup)(dm, vf);
    9323:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
    9324:   }
    9325:   return 0;
    9326: }

    9328: /*@
    9329:    DMMonitor - runs the user provided monitor routines, if they exist

    9331:    Collective on DM

    9333:    Input Parameters:
    9334: .  dm - The DM

    9336:    Level: developer

    9338: .seealso: DMMonitorSet()
    9339: @*/
    9340: PetscErrorCode DMMonitor(DM dm)
    9341: {
    9342:   PetscInt       m;

    9344:   if (!dm) return 0;
    9346:   for (m = 0; m < dm->numbermonitors; ++m) {
    9347:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
    9348:   }
    9349:   return 0;
    9350: }

    9352: /*@
    9353:   DMComputeError - Computes the error assuming the user has given exact solution functions

    9355:   Collective on DM

    9357:   Input Parameters:
    9358: + dm     - The DM
    9359: - sol    - The solution vector

    9361:   Input/Output Parameter:
    9362: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
    9363:            contains the error in each field

    9365:   Output Parameter:
    9366: . errorVec - A vector to hold the cellwise error (may be NULL)

    9368:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

    9370:   Level: developer

    9372: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
    9373: @*/
    9374: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
    9375: {
    9376:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
    9377:   void            **ctxs;
    9378:   PetscReal         time;
    9379:   PetscInt          Nf, f, Nds, s;

    9381:   DMGetNumFields(dm, &Nf);
    9382:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
    9383:   DMGetNumDS(dm, &Nds);
    9384:   for (s = 0; s < Nds; ++s) {
    9385:     PetscDS         ds;
    9386:     DMLabel         label;
    9387:     IS              fieldIS;
    9388:     const PetscInt *fields;
    9389:     PetscInt        dsNf;

    9391:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    9392:     PetscDSGetNumFields(ds, &dsNf);
    9393:     if (fieldIS) ISGetIndices(fieldIS, &fields);
    9394:     for (f = 0; f < dsNf; ++f) {
    9395:       const PetscInt field = fields[f];
    9396:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
    9397:     }
    9398:     if (fieldIS) ISRestoreIndices(fieldIS, &fields);
    9399:   }
    9400:   for (f = 0; f < Nf; ++f) {
    9402:   }
    9403:   DMGetOutputSequenceNumber(dm, NULL, &time);
    9404:   if (errors) DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);
    9405:   if (errorVec) {
    9406:     DM             edm;
    9407:     DMPolytopeType ct;
    9408:     PetscBool      simplex;
    9409:     PetscInt       dim, cStart, Nf;

    9411:     DMClone(dm, &edm);
    9412:     DMGetDimension(edm, &dim);
    9413:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
    9414:     DMPlexGetCellType(dm, cStart, &ct);
    9415:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
    9416:     DMGetNumFields(dm, &Nf);
    9417:     for (f = 0; f < Nf; ++f) {
    9418:       PetscFE         fe, efe;
    9419:       PetscQuadrature q;
    9420:       const char     *name;

    9422:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
    9423:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
    9424:       PetscObjectGetName((PetscObject) fe, &name);
    9425:       PetscObjectSetName((PetscObject) efe, name);
    9426:       PetscFEGetQuadrature(fe, &q);
    9427:       PetscFESetQuadrature(efe, q);
    9428:       DMSetField(edm, f, NULL, (PetscObject) efe);
    9429:       PetscFEDestroy(&efe);
    9430:     }
    9431:     DMCreateDS(edm);

    9433:     DMCreateGlobalVector(edm, errorVec);
    9434:     PetscObjectSetName((PetscObject) *errorVec, "Error");
    9435:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
    9436:     DMDestroy(&edm);
    9437:   }
    9438:   PetscFree2(exactSol, ctxs);
    9439:   return 0;
    9440: }

    9442: /*@
    9443:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

    9445:   Not collective

    9447:   Input Parameter:
    9448: . dm     - The DM

    9450:   Output Parameter:
    9451: . numAux - The number of auxiliary data vectors

    9453:   Level: advanced

    9455: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9456: @*/
    9457: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
    9458: {
    9460:   PetscHMapAuxGetSize(dm->auxData, numAux);
    9461:   return 0;
    9462: }

    9464: /*@
    9465:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part

    9467:   Not collective

    9469:   Input Parameters:
    9470: + dm     - The DM
    9471: . label  - The DMLabel
    9472: . value  - The label value indicating the region
    9473: - part   - The equation part, or 0 if unused

    9475:   Output Parameter:
    9476: . aux    - The Vec holding auxiliary field data

    9478:   Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.

    9480:   Level: advanced

    9482: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
    9483: @*/
    9484: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
    9485: {
    9486:   PetscHashAuxKey key, wild = {NULL, 0, 0};
    9487:   PetscBool       has;

    9491:   key.label = label;
    9492:   key.value = value;
    9493:   key.part  = part;
    9494:   PetscHMapAuxHas(dm->auxData, key, &has);
    9495:   if (has) PetscHMapAuxGet(dm->auxData, key,  aux);
    9496:   else     PetscHMapAuxGet(dm->auxData, wild, aux);
    9497:   return 0;
    9498: }

    9500: /*@
    9501:   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part

    9503:   Not collective

    9505:   Input Parameters:
    9506: + dm     - The DM
    9507: . label  - The DMLabel
    9508: . value  - The label value indicating the region
    9509: . part   - The equation part, or 0 if unused
    9510: - aux    - The Vec holding auxiliary field data

    9512:   Level: advanced

    9514: .seealso: DMGetAuxiliaryVec()
    9515: @*/
    9516: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
    9517: {
    9518:   Vec             old;
    9519:   PetscHashAuxKey key;

    9523:   key.label = label;
    9524:   key.value = value;
    9525:   key.part  = part;
    9526:   PetscHMapAuxGet(dm->auxData, key, &old);
    9527:   PetscObjectReference((PetscObject) aux);
    9528:   PetscObjectDereference((PetscObject) old);
    9529:   if (!aux) PetscHMapAuxDel(dm->auxData, key);
    9530:   else      PetscHMapAuxSet(dm->auxData, key, aux);
    9531:   return 0;
    9532: }

    9534: /*@C
    9535:   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM

    9537:   Not collective

    9539:   Input Parameter:
    9540: . dm      - The DM

    9542:   Output Parameters:
    9543: + labels  - The DMLabels for each Vec
    9544: . values  - The label values for each Vec
    9545: - parts   - The equation parts for each Vec

    9547:   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().

    9549:   Level: advanced

    9551: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9552: @*/
    9553: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
    9554: {
    9555:   PetscHashAuxKey *keys;
    9556:   PetscInt         n, i, off = 0;

    9562:   DMGetNumAuxiliaryVec(dm, &n);
    9563:   PetscMalloc1(n, &keys);
    9564:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
    9565:   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;}
    9566:   PetscFree(keys);
    9567:   return 0;
    9568: }

    9570: /*@
    9571:   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM

    9573:   Not collective

    9575:   Input Parameter:
    9576: . dm    - The DM

    9578:   Output Parameter:
    9579: . dmNew - The new DM, now with the same auxiliary data

    9581:   Level: advanced

    9583: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9584: @*/
    9585: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
    9586: {
    9588:   PetscHMapAuxDestroy(&dmNew->auxData);
    9589:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
    9590:   return 0;
    9591: }

    9593: /*@C
    9594:   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

    9596:   Not collective

    9598:   Input Parameters:
    9599: + ct         - The DMPolytopeType
    9600: . sourceCone - The source arrangement of faces
    9601: - targetCone - The target arrangement of faces

    9603:   Output Parameters:
    9604: + ornt  - The orientation which will take the source arrangement to the target arrangement
    9605: - found - Flag indicating that a suitable orientation was found

    9607:   Level: advanced

    9609: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
    9610: @*/
    9611: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
    9612: {
    9613:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
    9614:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
    9615:   PetscInt       o, c;

    9617:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return 0;}
    9618:   for (o = -nO; o < nO; ++o) {
    9619:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

    9621:     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
    9622:     if (c == cS) {*ornt = o; break;}
    9623:   }
    9624:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
    9625:   return 0;
    9626: }

    9628: /*@C
    9629:   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

    9631:   Not collective

    9633:   Input Parameters:
    9634: + ct         - The DMPolytopeType
    9635: . sourceCone - The source arrangement of faces
    9636: - targetCone - The target arrangement of faces

    9638:   Output Parameters:
    9639: . ornt  - The orientation which will take the source arrangement to the target arrangement

    9641:   Note: This function will fail if no suitable orientation can be found.

    9643:   Level: advanced

    9645: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
    9646: @*/
    9647: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
    9648: {
    9649:   PetscBool      found;

    9651:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
    9653:   return 0;
    9654: }

    9656: /*@C
    9657:   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

    9659:   Not collective

    9661:   Input Parameters:
    9662: + ct         - The DMPolytopeType
    9663: . sourceVert - The source arrangement of vertices
    9664: - targetVert - The target arrangement of vertices

    9666:   Output Parameters:
    9667: + ornt  - The orientation which will take the source arrangement to the target arrangement
    9668: - found - Flag indicating that a suitable orientation was found

    9670:   Level: advanced

    9672: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
    9673: @*/
    9674: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
    9675: {
    9676:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
    9677:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
    9678:   PetscInt       o, c;

    9680:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return 0;}
    9681:   for (o = -nO; o < nO; ++o) {
    9682:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

    9684:     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
    9685:     if (c == cS) {*ornt = o; break;}
    9686:   }
    9687:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
    9688:   return 0;
    9689: }

    9691: /*@C
    9692:   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

    9694:   Not collective

    9696:   Input Parameters:
    9697: + ct         - The DMPolytopeType
    9698: . sourceCone - The source arrangement of vertices
    9699: - targetCone - The target arrangement of vertices

    9701:   Output Parameters:
    9702: . ornt  - The orientation which will take the source arrangement to the target arrangement

    9704:   Note: This function will fail if no suitable orientation can be found.

    9706:   Level: advanced

    9708: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
    9709: @*/
    9710: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
    9711: {
    9712:   PetscBool      found;

    9714:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
    9716:   return 0;
    9717: }

    9719: /*@C
    9720:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

    9722:   Not collective

    9724:   Input Parameters:
    9725: + ct    - The DMPolytopeType
    9726: - point - Coordinates of the point

    9728:   Output Parameters:
    9729: . inside  - Flag indicating whether the point is inside the reference cell of given type

    9731:   Level: advanced

    9733: .seealso: DMLocatePoints()
    9734: @*/
    9735: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
    9736: {
    9737:   PetscReal sum = 0.0;
    9738:   PetscInt  d;

    9740:   *inside = PETSC_TRUE;
    9741:   switch (ct) {
    9742:   case DM_POLYTOPE_TRIANGLE:
    9743:   case DM_POLYTOPE_TETRAHEDRON:
    9744:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
    9745:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
    9746:       sum += point[d];
    9747:     }
    9748:     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
    9749:     break;
    9750:   case DM_POLYTOPE_QUADRILATERAL:
    9751:   case DM_POLYTOPE_HEXAHEDRON:
    9752:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
    9753:       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
    9754:     break;
    9755:   default:
    9756:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
    9757:   }
    9758:   return 0;
    9759: }