Date: 2022-03-04T17:38:36+00:00

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};

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

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

     32:   Collective

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

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

     40:   Level: beginner

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

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

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

     57:   v->setupcalled              = PETSC_FALSE;
     58:   v->setfromoptionscalled     = PETSC_FALSE;
     59:   v->ltogmap                  = NULL;
     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->defaultConstraintSection = NULL;
     72:   v->defaultConstraintMat     = NULL;
     73:   v->L                        = NULL;
     74:   v->maxCell                  = NULL;
     75:   v->bdtype                   = NULL;
     76:   v->dimEmbed                 = PETSC_DEFAULT;
     77:   v->dim                      = PETSC_DETERMINE;
     78:   {
     79:     PetscInt i;
     80:     for (i = 0; i < 10; ++i) {
     81:       v->nullspaceConstructors[i] = NULL;
     82:       v->nearnullspaceConstructors[i] = NULL;
     83:     }
     84:   }
     85:   PetscDSCreate(PETSC_COMM_SELF, &ds);
     86:   DMSetRegionDS(v, NULL, NULL, ds);
     87:   PetscDSDestroy(&ds);
     88:   PetscHMapAuxCreate(&v->auxData);
     89:   v->dmBC = NULL;
     90:   v->coarseMesh = NULL;
     91:   v->outputSequenceNum = -1;
     92:   v->outputSequenceVal = 0.0;
     93:   DMSetVecType(v,VECSTANDARD);
     94:   DMSetMatType(v,MATAIJ);

     96:   *dm = v;
     97:   return(0);
     98: }

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

    103:   Collective

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

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

    111:   Level: beginner

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

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

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

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

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

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

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

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

    197:    Logically Collective on da

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

    203:    Options Database:
    204: .   -dm_vec_type ctype

    206:    Level: intermediate

    208: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
    209: @*/
    210: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
    211: {

    216:   PetscFree(da->vectype);
    217:   PetscStrallocpy(ctype,(char**)&da->vectype);
    218:   return(0);
    219: }

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

    224:    Logically Collective on da

    226:    Input Parameter:
    227: .  da - initial distributed array

    229:    Output Parameter:
    230: .  ctype - the vector type

    232:    Level: intermediate

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

    244: /*@
    245:   VecGetDM - Gets the DM defining the data layout of the vector

    247:   Not collective

    249:   Input Parameter:
    250: . v - The Vec

    252:   Output Parameter:
    253: . dm - The DM

    255:   Level: intermediate

    257: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    258: @*/
    259: PetscErrorCode VecGetDM(Vec v, DM *dm)
    260: {

    266:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
    267:   return(0);
    268: }

    270: /*@
    271:   VecSetDM - Sets the DM defining the data layout of the vector.

    273:   Not collective

    275:   Input Parameters:
    276: + v - The Vec
    277: - dm - The DM

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

    281:   Level: intermediate

    283: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    284: @*/
    285: PetscErrorCode VecSetDM(Vec v, DM dm)
    286: {

    292:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
    293:   return(0);
    294: }

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

    299:    Logically Collective on dm

    301:    Input Parameters:
    302: +  dm - the DM context
    303: -  ctype - the matrix type

    305:    Options Database:
    306: .   -dm_is_coloring_type - global or local

    308:    Level: intermediate

    310: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
    311:           DMGetISColoringType()
    312: @*/
    313: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
    314: {
    317:   dm->coloringtype = ctype;
    318:   return(0);
    319: }

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

    324:    Logically Collective on dm

    326:    Input Parameter:
    327: .  dm - the DM context

    329:    Output Parameter:
    330: .  ctype - the matrix type

    332:    Options Database:
    333: .   -dm_is_coloring_type - global or local

    335:    Level: intermediate

    337: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
    338:           DMGetISColoringType()
    339: @*/
    340: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
    341: {
    344:   *ctype = dm->coloringtype;
    345:   return(0);
    346: }

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

    351:    Logically Collective on dm

    353:    Input Parameters:
    354: +  dm - the DM context
    355: -  ctype - the matrix type

    357:    Options Database:
    358: .   -dm_mat_type ctype

    360:    Level: intermediate

    362: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
    363: @*/
    364: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
    365: {

    370:   PetscFree(dm->mattype);
    371:   PetscStrallocpy(ctype,(char**)&dm->mattype);
    372:   return(0);
    373: }

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

    378:    Logically Collective on dm

    380:    Input Parameter:
    381: .  dm - the DM context

    383:    Output Parameter:
    384: .  ctype - the matrix type

    386:    Options Database:
    387: .   -dm_mat_type ctype

    389:    Level: intermediate

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

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

    404:   Not collective

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

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

    412:   Level: intermediate

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

    417: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
    418: @*/
    419: PetscErrorCode MatGetDM(Mat A, DM *dm)
    420: {

    426:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
    427:   return(0);
    428: }

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

    433:   Not collective

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

    439:   Level: intermediate

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

    444: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
    445: @*/
    446: PetscErrorCode MatSetDM(Mat A, DM dm)
    447: {

    453:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
    454:   return(0);
    455: }

    457: /*@C
    458:    DMSetOptionsPrefix - Sets the prefix used for searching for all
    459:    DM options in the database.

    461:    Logically Collective on dm

    463:    Input Parameters:
    464: +  da - the DM context
    465: -  prefix - the prefix to prepend to all option names

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

    471:    Level: advanced

    473: .seealso: DMSetFromOptions()
    474: @*/
    475: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
    476: {

    481:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
    482:   if (dm->sf) {
    483:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
    484:   }
    485:   if (dm->sectionSF) {
    486:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
    487:   }
    488:   return(0);
    489: }

    491: /*@C
    492:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
    493:    DM options in the database.

    495:    Logically Collective on dm

    497:    Input Parameters:
    498: +  dm - the DM context
    499: -  prefix - the prefix string to prepend to all DM option requests

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

    505:    Level: advanced

    507: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
    508: @*/
    509: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
    510: {

    515:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
    516:   return(0);
    517: }

    519: /*@C
    520:    DMGetOptionsPrefix - Gets the prefix used for searching for all
    521:    DM options in the database.

    523:    Not Collective

    525:    Input Parameters:
    526: .  dm - the DM context

    528:    Output Parameters:
    529: .  prefix - pointer to the prefix string used is returned

    531:    Notes:
    532:     On the fortran side, the user should pass in a string 'prefix' of
    533:    sufficient length to hold the prefix.

    535:    Level: advanced

    537: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
    538: @*/
    539: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
    540: {

    545:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
    546:   return(0);
    547: }

    549: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
    550: {
    551:   PetscInt       refct = ((PetscObject) dm)->refct;

    555:   *ncrefct = 0;
    556:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
    557:     refct--;
    558:     if (recurseCoarse) {
    559:       PetscInt coarseCount;

    561:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
    562:       refct += coarseCount;
    563:     }
    564:   }
    565:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
    566:     refct--;
    567:     if (recurseFine) {
    568:       PetscInt fineCount;

    570:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
    571:       refct += fineCount;
    572:     }
    573:   }
    574:   *ncrefct = refct;
    575:   return(0);
    576: }

    578: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
    579: {
    580:   DMLabelLink    next = dm->labels;

    584:   /* destroy the labels */
    585:   while (next) {
    586:     DMLabelLink tmp = next->next;

    588:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
    589:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    590:     DMLabelDestroy(&next->label);
    591:     PetscFree(next);
    592:     next = tmp;
    593:   }
    594:   dm->labels = NULL;
    595:   return(0);
    596: }

    598: /*@C
    599:     DMDestroy - Destroys a vector packer or DM.

    601:     Collective on dm

    603:     Input Parameter:
    604: .   dm - the DM object to destroy

    606:     Level: developer

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

    610: @*/
    611: PetscErrorCode  DMDestroy(DM *dm)
    612: {
    613:   PetscInt       cnt;
    614:   DMNamedVecLink nlink,nnext;

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

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

    628:   DMClearGlobalVectors(*dm);
    629:   DMClearLocalVectors(*dm);

    631:   nnext=(*dm)->namedglobal;
    632:   (*dm)->namedglobal = NULL;
    633:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
    634:     nnext = nlink->next;
    635:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
    636:     PetscFree(nlink->name);
    637:     VecDestroy(&nlink->X);
    638:     PetscFree(nlink);
    639:   }
    640:   nnext=(*dm)->namedlocal;
    641:   (*dm)->namedlocal = NULL;
    642:   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
    643:     nnext = nlink->next;
    644:     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
    645:     PetscFree(nlink->name);
    646:     VecDestroy(&nlink->X);
    647:     PetscFree(nlink);
    648:   }

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

    712:       next = b->next;
    713:       PetscFree(b);
    714:     }
    715:   }

    717:   PetscObjectDestroy(&(*dm)->dmksp);
    718:   PetscObjectDestroy(&(*dm)->dmsnes);
    719:   PetscObjectDestroy(&(*dm)->dmts);

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

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

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

    757:   DMDestroy(&(*dm)->coarseMesh);
    758:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
    759:     DMSetCoarseDM((*dm)->fineMesh,NULL);
    760:   }
    761:   DMDestroy(&(*dm)->fineMesh);
    762:   DMFieldDestroy(&(*dm)->coordinateField);
    763:   DMDestroy(&(*dm)->coordinateDM);
    764:   VecDestroy(&(*dm)->coordinates);
    765:   VecDestroy(&(*dm)->coordinatesLocal);
    766:   PetscFree((*dm)->L);
    767:   PetscFree((*dm)->maxCell);
    768:   PetscFree((*dm)->bdtype);
    769:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
    770:   DMDestroy(&(*dm)->transformDM);
    771:   VecDestroy(&(*dm)->transform);

    773:   DMClearDS(*dm);
    774:   DMDestroy(&(*dm)->dmBC);
    775:   /* if memory was published with SAWs then destroy it */
    776:   PetscObjectSAWsViewOff((PetscObject)*dm);

    778:   if ((*dm)->ops->destroy) {
    779:     (*(*dm)->ops->destroy)(*dm);
    780:   }
    781:   DMMonitorCancel(*dm);
    782: #ifdef PETSC_HAVE_LIBCEED
    783:   CeedElemRestrictionDestroy(&(*dm)->ceedERestrict);
    784:   CeedDestroy(&(*dm)->ceed);
    785: #endif
    786:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
    787:   PetscHeaderDestroy(dm);
    788:   return(0);
    789: }

    791: /*@
    792:     DMSetUp - sets up the data structures inside a DM object

    794:     Collective on dm

    796:     Input Parameter:
    797: .   dm - the DM object to setup

    799:     Level: developer

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

    803: @*/
    804: PetscErrorCode  DMSetUp(DM dm)
    805: {

    810:   if (dm->setupcalled) return(0);
    811:   if (dm->ops->setup) {
    812:     (*dm->ops->setup)(dm);
    813:   }
    814:   dm->setupcalled = PETSC_TRUE;
    815:   return(0);
    816: }

    818: /*@
    819:     DMSetFromOptions - sets parameters in a DM from the options database

    821:     Collective on dm

    823:     Input Parameter:
    824: .   dm - the DM object to set options for

    826:     Options Database:
    827: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
    828: .   -dm_vec_type <type>  - type of vector to create inside DM
    829: .   -dm_mat_type <type>  - type of matrix to create inside DM
    830: -   -dm_is_coloring_type - <global or local>

    832:     DMPLEX Specific creation options
    833: + -dm_plex_filename <str>           - File containing a mesh
    834: . -dm_plex_boundary_filename <str>  - File containing a mesh boundary
    835: . -dm_plex_shape <shape>            - The domain shape, such as DM_SHAPE_BOX, DM_SHAPE_SPHERE, etc.
    836: . -dm_plex_cell <ct>                - Cell shape
    837: . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain
    838: . -dm_plex_dim <dim>                - Set the topological dimension
    839: . -dm_plex_simplex <bool>           - PETSC_TRUE for simplex elements, PETSC_FALSE for tensor elements
    840: . -dm_plex_interpolate <bool>       - PETSC_TRUE turns on topological interpolation (creating edges and faces)
    841: . -dm_plex_scale <sc>               - Scale factor for mesh coordinates
    842: . -dm_plex_box_faces <m,n,p>        - Number of faces along each dimension
    843: . -dm_plex_box_lower <x,y,z>        - Specify lower-left-bottom coordinates for the box
    844: . -dm_plex_box_upper <x,y,z>        - Specify upper-right-top coordinates for the box
    845: . -dm_plex_box_bd <bx,by,bz>        - Specify the DMBoundaryType for each direction
    846: . -dm_plex_sphere_radius <r>        - The sphere radius
    847: . -dm_plex_ball_radius <r>          - Radius of the ball
    848: . -dm_plex_cylinder_bd <bz>         - Boundary type in the z direction
    849: . -dm_plex_cylinder_num_wedges <n>  - Number of wedges around the cylinder
    850: . -dm_refine_pre <n>                - The number of refinements before distribution
    851: . -dm_refine_uniform_pre <bool>     - Flag for uniform refinement before distribution
    852: . -dm_refine_volume_limit_pre <v>   - The maximum cell volume after refinement before distribution
    853: . -dm_refine <n>                    - The number of refinements after distribution
    854: . -dm_extrude_layers <l>            - The number of layers to extrude
    855: . -dm_extrude_thickness <t>         - The thickness of the layer to be extruded
    856: . -dm_extrude_column_first <bool>   - Order the cells in a vertical column first
    857: . -dm_plex_create_fv_ghost_cells    - Flag to create finite volume ghost cells on the boundary
    858: . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary
    859: . -dm_distribute <bool>             - Flag to redistribute a mesh among processes
    860: . -dm_distribute_overlap <n>        - The size of the overlap halo
    861: . -dm_plex_adj_cone <bool>          - Set adjacency direction
    862: - -dm_plex_adj_closure <bool>       - Set adjacency size

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

    873:     Level: intermediate

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

    878: @*/
    879: PetscErrorCode DMSetFromOptions(DM dm)
    880: {
    881:   char           typeName[256];
    882:   PetscBool      flg;

    887:   dm->setfromoptionscalled = PETSC_TRUE;
    888:   if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
    889:   if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
    890:   PetscObjectOptionsBegin((PetscObject)dm);
    891:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
    892:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
    893:   if (flg) {
    894:     DMSetVecType(dm,typeName);
    895:   }
    896:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
    897:   if (flg) {
    898:     DMSetMatType(dm,typeName);
    899:   }
    900:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
    901:   if (dm->ops->setfromoptions) {
    902:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
    903:   }
    904:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    905:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
    906:   PetscOptionsEnd();
    907:   return(0);
    908: }

    910: /*@C
    911:    DMViewFromOptions - View from Options

    913:    Collective on DM

    915:    Input Parameters:
    916: +  dm - the DM object
    917: .  obj - Optional object
    918: -  name - command line option

    920:    Level: intermediate
    921: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
    922: @*/
    923: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
    924: {

    929:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
    930:   return(0);
    931: }

    933: /*@C
    934:     DMView - Views a DM

    936:     Collective on dm

    938:     Input Parameters:
    939: +   dm - the DM object to view
    940: -   v - the viewer

    942:     Level: beginner

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

    946: @*/
    947: PetscErrorCode  DMView(DM dm,PetscViewer v)
    948: {
    949:   PetscErrorCode    ierr;
    950:   PetscBool         isbinary;
    951:   PetscMPIInt       size;
    952:   PetscViewerFormat format;

    956:   if (!v) {
    957:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
    958:   }
    960:   /* Ideally, we would like to have this test on.
    961:      However, it currently breaks socket viz via GLVis.
    962:      During DMView(parallel_mesh,glvis_viewer), each
    963:      process opens a sequential ASCII socket to visualize
    964:      the local mesh, and PetscObjectView(dm,local_socket)
    965:      is internally called inside VecView_GLVis, incurring
    966:      in an error here */
    968:   PetscViewerCheckWritable(v);

    970:   PetscViewerGetFormat(v,&format);
    971:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
    972:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
    973:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
    974:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
    975:   if (isbinary) {
    976:     PetscInt classid = DM_FILE_CLASSID;
    977:     char     type[256];

    979:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
    980:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
    981:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
    982:   }
    983:   if (dm->ops->view) {
    984:     (*dm->ops->view)(dm,v);
    985:   }
    986:   return(0);
    987: }

    989: /*@
    990:     DMCreateGlobalVector - Creates a global vector from a DM object

    992:     Collective on dm

    994:     Input Parameter:
    995: .   dm - the DM object

    997:     Output Parameter:
    998: .   vec - the global vector

    1000:     Level: beginner

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

    1004: @*/
    1005: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
    1006: {

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

    1017:     VecGetDM(*vec,&vdm);
    1018:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
    1019:   }
    1020:   return(0);
    1021: }

    1023: /*@
    1024:     DMCreateLocalVector - Creates a local vector from a DM object

    1026:     Not Collective

    1028:     Input Parameter:
    1029: .   dm - the DM object

    1031:     Output Parameter:
    1032: .   vec - the local vector

    1034:     Level: beginner

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

    1038: @*/
    1039: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
    1040: {

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

    1051:     VecGetDM(*vec,&vdm);
    1052:     if (!vdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"DM type '%s' did not attach the DM to the vector\n",((PetscObject)dm)->type_name);
    1053:   }
    1054:   return(0);
    1055: }

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

    1060:    Collective on dm

    1062:    Input Parameter:
    1063: .  dm - the DM that provides the mapping

    1065:    Output Parameter:
    1066: .  ltog - the mapping

    1068:    Level: intermediate

    1070:    Notes:
    1071:    This mapping can then be used by VecSetLocalToGlobalMapping() or
    1072:    MatSetLocalToGlobalMapping().

    1074: .seealso: DMCreateLocalVector()
    1075: @*/
    1076: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
    1077: {
    1078:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

    1084:   if (!dm->ltogmap) {
    1085:     PetscSection section, sectionGlobal;

    1087:     DMGetLocalSection(dm, &section);
    1088:     if (section) {
    1089:       const PetscInt *cdofs;
    1090:       PetscInt       *ltog;
    1091:       PetscInt        pStart, pEnd, n, p, k, l;

    1093:       DMGetGlobalSection(dm, &sectionGlobal);
    1094:       PetscSectionGetChart(section, &pStart, &pEnd);
    1095:       PetscSectionGetStorageSize(section, &n);
    1096:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
    1097:       for (p = pStart, l = 0; p < pEnd; ++p) {
    1098:         PetscInt bdof, cdof, dof, off, c, cind = 0;

    1100:         /* Should probably use constrained dofs */
    1101:         PetscSectionGetDof(section, p, &dof);
    1102:         PetscSectionGetConstraintDof(section, p, &cdof);
    1103:         PetscSectionGetConstraintIndices(section, p, &cdofs);
    1104:         PetscSectionGetOffset(sectionGlobal, p, &off);
    1105:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
    1106:         bdof = cdof && (dof-cdof) ? 1 : dof;
    1107:         if (dof) {
    1108:           if (bs < 0)          {bs = bdof;}
    1109:           else if (bs != bdof) {bs = 1;}
    1110:         }
    1111:         for (c = 0; c < dof; ++c, ++l) {
    1112:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
    1113:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
    1114:         }
    1115:       }
    1116:       /* Must have same blocksize on all procs (some might have no points) */
    1117:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
    1118:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
    1119:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
    1120:       else                            {bs = bsMinMax[0];}
    1121:       bs = bs < 0 ? 1 : bs;
    1122:       /* Must reduce indices by blocksize */
    1123:       if (bs > 1) {
    1124:         for (l = 0, k = 0; l < n; l += bs, ++k) {
    1125:           // Integer division of negative values truncates toward zero(!), not toward negative infinity
    1126:           ltog[k] = ltog[l] >= 0 ? ltog[l]/bs : -(-(ltog[l]+1)/bs + 1);
    1127:         }
    1128:         n /= bs;
    1129:       }
    1130:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
    1131:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
    1132:     } else {
    1133:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
    1134:       (*dm->ops->getlocaltoglobalmapping)(dm);
    1135:     }
    1136:   }
    1137:   *ltog = dm->ltogmap;
    1138:   return(0);
    1139: }

    1141: /*@
    1142:    DMGetBlockSize - Gets the inherent block size associated with a DM

    1144:    Not Collective

    1146:    Input Parameter:
    1147: .  dm - the DM with block structure

    1149:    Output Parameter:
    1150: .  bs - the block size, 1 implies no exploitable block structure

    1152:    Level: intermediate

    1154: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
    1155: @*/
    1156: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
    1157: {
    1161:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
    1162:   *bs = dm->bs;
    1163:   return(0);
    1164: }

    1166: /*@C
    1167:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

    1169:     Collective on dmc

    1171:     Input Parameters:
    1172: +   dmc - the DM object
    1173: -   dmf - the second, finer DM object

    1175:     Output Parameters:
    1176: +  mat - the interpolation
    1177: -  vec - the scaling (optional)

    1179:     Level: developer

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

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

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

    1190: @*/
    1191: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
    1192: {

    1199:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
    1200:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
    1201:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
    1202:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
    1203:   return(0);
    1204: }

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

    1209:   Input Parameters:
    1210: +      dac - DM that defines a coarse mesh
    1211: .      daf - DM that defines a fine mesh
    1212: -      mat - the restriction (or interpolation operator) from fine to coarse

    1214:   Output Parameter:
    1215: .    scale - the scaled vector

    1217:   Level: developer

    1219: .seealso: DMCreateInterpolation()

    1221: @*/
    1222: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
    1223: {
    1225:   Vec            fine;
    1226:   PetscScalar    one = 1.0;

    1229:   DMCreateGlobalVector(daf,&fine);
    1230:   DMCreateGlobalVector(dac,scale);
    1231:   VecSet(fine,one);
    1232:   MatRestrict(mat,fine,*scale);
    1233:   VecDestroy(&fine);
    1234:   VecReciprocal(*scale);
    1235:   return(0);
    1236: }

    1238: /*@
    1239:     DMCreateRestriction - Gets restriction matrix between two DM objects

    1241:     Collective on dmc

    1243:     Input Parameters:
    1244: +   dmc - the DM object
    1245: -   dmf - the second, finer DM object

    1247:     Output Parameter:
    1248: .  mat - the restriction

    1250:     Level: developer

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

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

    1258: @*/
    1259: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
    1260: {

    1267:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
    1268:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
    1269:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
    1270:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
    1271:   return(0);
    1272: }

    1274: /*@
    1275:     DMCreateInjection - Gets injection matrix between two DM objects

    1277:     Collective on dac

    1279:     Input Parameters:
    1280: +   dac - the DM object
    1281: -   daf - the second, finer DM object

    1283:     Output Parameter:
    1284: .   mat - the injection

    1286:     Level: developer

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

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

    1294: @*/
    1295: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
    1296: {

    1303:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
    1304:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
    1305:   (*dac->ops->createinjection)(dac,daf,mat);
    1306:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
    1307:   return(0);
    1308: }

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

    1313:   Collective on dac

    1315:   Input Parameters:
    1316: + dac - the DM object
    1317: - daf - the second, finer DM object

    1319:   Output Parameter:
    1320: . mat - the interpolation

    1322:   Level: developer

    1324: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
    1325: @*/
    1326: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
    1327: {

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

    1339: /*@
    1340:     DMCreateColoring - Gets coloring for a DM

    1342:     Collective on dm

    1344:     Input Parameters:
    1345: +   dm - the DM object
    1346: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

    1348:     Output Parameter:
    1349: .   coloring - the coloring

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

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

    1357:     Level: developer

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

    1361: @*/
    1362: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
    1363: {

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

    1374: /*@
    1375:     DMCreateMatrix - Gets empty Jacobian for a DM

    1377:     Collective on dm

    1379:     Input Parameter:
    1380: .   dm - the DM object

    1382:     Output Parameter:
    1383: .   mat - the empty Jacobian

    1385:     Level: beginner

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

    1390:     Notes:
    1391:     This properly preallocates the number of nonzeros in the sparse matrix so you
    1392:        do not need to do it yourself.

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

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

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

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

    1405: @*/
    1406: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
    1407: {

    1413:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
    1414:   MatInitializePackage();
    1415:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
    1416:   (*dm->ops->creatematrix)(dm,mat);
    1417:   if (PetscDefined(USE_DEBUG)) {
    1418:     DM mdm;

    1420:     MatGetDM(*mat,&mdm);
    1421:     if (!mdm) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"DM type '%s' did not attach the DM to the matrix\n",((PetscObject)dm)->type_name);
    1422:   }
    1423:   /* Handle nullspace and near nullspace */
    1424:   if (dm->Nf) {
    1425:     MatNullSpace nullSpace;
    1426:     PetscInt     Nf, f;

    1428:     DMGetNumFields(dm, &Nf);
    1429:     for (f = 0; f < Nf; ++f) {
    1430:       if (dm->nullspaceConstructors[f]) {
    1431:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
    1432:         MatSetNullSpace(*mat, nullSpace);
    1433:         MatNullSpaceDestroy(&nullSpace);
    1434:         break;
    1435:       }
    1436:     }
    1437:     for (f = 0; f < Nf; ++f) {
    1438:       if (dm->nearnullspaceConstructors[f]) {
    1439:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
    1440:         MatSetNearNullSpace(*mat, nullSpace);
    1441:         MatNullSpaceDestroy(&nullSpace);
    1442:       }
    1443:     }
    1444:   }
    1445:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
    1446:   return(0);
    1447: }

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

    1453:   Logically Collective on dm

    1455:   Input Parameters:
    1456: + dm - the DM
    1457: - only - PETSC_TRUE if only want preallocation

    1459:   Level: developer

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

    1464: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
    1465: @*/
    1466: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
    1467: {
    1470:   dm->prealloc_only = only;
    1471:   return(0);
    1472: }

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

    1478:   Logically Collective on dm

    1480:   Input Parameters:
    1481: + dm - the DM
    1482: - only - PETSC_TRUE if only want matrix stucture

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

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

    1498:   Not Collective

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

    1505:   Output Parameter:
    1506: . array - the work array

    1508:   Level: developer

    1510: .seealso DMDestroy(), DMCreate()
    1511: @*/
    1512: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1513: {
    1515:   DMWorkLink     link;
    1516:   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()
    1560: .seealso DMDestroy(), DMCreate()
    1561: @*/
    1562: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1563: {
    1564:   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

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

    1599:   This function is currently not available from Fortran.

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

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

    1615:   Not collective

    1617:   Input Parameters:
    1618: + dm     - The DM
    1619: - field  - The field number for the nullspace

    1621:   Output Parameter:
    1622: . nullsp - A callback to create the nullspace

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

    1632:   This function is currently not available from Fortran.

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

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

    1649:   Logically collective on DM

    1651:   Input Parameters:
    1652: + dm     - The DM
    1653: . field  - The field number for the nullspace
    1654: - nullsp - A callback to create the near-nullspace

    1656:   Notes:
    1657:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1658: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1659: $ dm        - The present DM
    1660: $ origField - The field number given above, in the original DM
    1661: $ field     - The field number in dm
    1662: $ nullSpace - The nullspace for the given field

    1664:   This function is currently not available from Fortran.

    1666: .seealso: DMGetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
    1667: */
    1668: PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
    1669: {
    1672:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
    1673:   dm->nearnullspaceConstructors[field] = nullsp;
    1674:   return(0);
    1675: }

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

    1680:   Not collective

    1682:   Input Parameters:
    1683: + dm     - The DM
    1684: - field  - The field number for the nullspace

    1686:   Output Parameter:
    1687: . nullsp - A callback to create the near-nullspace

    1689:   Notes:
    1690:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1691: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1692: $ dm        - The present DM
    1693: $ origField - The field number given above, in the original DM
    1694: $ field     - The field number in dm
    1695: $ nullSpace - The nullspace for the given field

    1697:   This function is currently not available from Fortran.

    1699: .seealso: DMSetNearNullSpaceConstructor(), DMSetNullSpaceConstructor(), DMGetNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
    1700: */
    1701: PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
    1702: {
    1706:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
    1707:   *nullsp = dm->nearnullspaceConstructors[field];
    1708:   return(0);
    1709: }

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

    1714:   Not collective

    1716:   Input Parameter:
    1717: . dm - the DM object

    1719:   Output Parameters:
    1720: + numFields  - The number of fields (or NULL if not requested)
    1721: . fieldNames - The name for each field (or NULL if not requested)
    1722: - fields     - The global indices for each field (or NULL if not requested)

    1724:   Level: intermediate

    1726:   Notes:
    1727:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
    1728:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
    1729:   PetscFree().

    1731: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
    1732: @*/
    1733: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
    1734: {
    1735:   PetscSection   section, sectionGlobal;

    1740:   if (numFields) {
    1742:     *numFields = 0;
    1743:   }
    1744:   if (fieldNames) {
    1746:     *fieldNames = NULL;
    1747:   }
    1748:   if (fields) {
    1750:     *fields = NULL;
    1751:   }
    1752:   DMGetLocalSection(dm, &section);
    1753:   if (section) {
    1754:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
    1755:     PetscInt nF, f, pStart, pEnd, p;

    1757:     DMGetGlobalSection(dm, &sectionGlobal);
    1758:     PetscSectionGetNumFields(section, &nF);
    1759:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
    1760:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
    1761:     for (f = 0; f < nF; ++f) {
    1762:       fieldSizes[f] = 0;
    1763:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
    1764:     }
    1765:     for (p = pStart; p < pEnd; ++p) {
    1766:       PetscInt gdof;

    1768:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1769:       if (gdof > 0) {
    1770:         for (f = 0; f < nF; ++f) {
    1771:           PetscInt fdof, fcdof, fpdof;

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

    1791:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1792:       if (gdof > 0) {
    1793:         PetscSectionGetOffset(sectionGlobal, p, &goff);
    1794:         for (f = 0; f < nF; ++f) {
    1795:           PetscInt fdof, fcdof, fc;

    1797:           PetscSectionGetFieldDof(section, p, f, &fdof);
    1798:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    1799:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
    1800:             fieldIndices[f][fieldSizes[f]] = goff++;
    1801:           }
    1802:         }
    1803:       }
    1804:     }
    1805:     if (numFields) *numFields = nF;
    1806:     if (fieldNames) {
    1807:       PetscMalloc1(nF, fieldNames);
    1808:       for (f = 0; f < nF; ++f) {
    1809:         const char *fieldName;

    1811:         PetscSectionGetFieldName(section, f, &fieldName);
    1812:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
    1813:       }
    1814:     }
    1815:     if (fields) {
    1816:       PetscMalloc1(nF, fields);
    1817:       for (f = 0; f < nF; ++f) {
    1818:         PetscInt bs, in[2], out[2];

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

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

    1841:   Not collective

    1843:   Input Parameter:
    1844: . dm - the DM object

    1846:   Output Parameters:
    1847: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
    1848: . namelist  - The name for each field (or NULL if not requested)
    1849: . islist    - The global indices for each field (or NULL if not requested)
    1850: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

    1852:   Level: intermediate

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

    1859: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1860: @*/
    1861: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
    1862: {

    1867:   if (len) {
    1869:     *len = 0;
    1870:   }
    1871:   if (namelist) {
    1873:     *namelist = NULL;
    1874:   }
    1875:   if (islist) {
    1877:     *islist = NULL;
    1878:   }
    1879:   if (dmlist) {
    1881:     *dmlist = NULL;
    1882:   }
    1883:   /*
    1884:    Is it a good idea to apply the following check across all impls?
    1885:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
    1886:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
    1887:    */
    1888:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
    1889:   if (!dm->ops->createfielddecomposition) {
    1890:     PetscSection section;
    1891:     PetscInt     numFields, f;

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

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

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

    1924:   Not collective

    1926:   Input Parameters:
    1927: + dm        - The DM object
    1928: . numFields - The number of fields in this subproblem
    1929: - fields    - The field numbers of the selected fields

    1931:   Output Parameters:
    1932: + is - The global indices for the subproblem
    1933: - subdm - The DM for the subproblem

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

    1937:   Level: intermediate

    1939: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1940: @*/
    1941: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1942: {

    1950:   if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
    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;

    1984:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
    1985:   if (len) {
    1986:     DM dm = dms[0];
    1987:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
    1988:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
    1989:   }
    1990:   return(0);
    1991: }

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

    2000:   Not collective

    2002:   Input Parameter:
    2003: . dm - the DM object

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

    2012:   Level: intermediate

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

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

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

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

    2059:   Not collective

    2061:   Input Parameters:
    2062: + dm - the DM object
    2063: . n  - the number of subdomain scatters
    2064: - subdms - the local subdomains

    2066:   Output Parameters:
    2067: + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
    2068: . oscat - scatter from global vector to overlapping global vector entries on subdomain
    2069: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

    2077:   Level: developer

    2079: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    2080: @*/
    2081: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
    2082: {

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

    2093: /*@
    2094:   DMRefine - Refines a DM object

    2096:   Collective on dm

    2098:   Input Parameters:
    2099: + dm   - the DM object
    2100: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    2102:   Output Parameter:
    2103: . dmf - the refined DM, or NULL

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

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

    2110:   Level: developer

    2112: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    2113: @*/
    2114: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
    2115: {
    2116:   PetscErrorCode   ierr;
    2117:   DMRefineHookLink link;

    2121:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
    2122:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
    2123:   (*dm->ops->refine)(dm,comm,dmf);
    2124:   if (*dmf) {
    2125:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

    2129:     (*dmf)->ctx       = dm->ctx;
    2130:     (*dmf)->leveldown = dm->leveldown;
    2131:     (*dmf)->levelup   = dm->levelup + 1;

    2133:     DMSetMatType(*dmf,dm->mattype);
    2134:     for (link=dm->refinehook; link; link=link->next) {
    2135:       if (link->refinehook) {
    2136:         (*link->refinehook)(dm,*dmf,link->ctx);
    2137:       }
    2138:     }
    2139:   }
    2140:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
    2141:   return(0);
    2142: }

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

    2147:    Logically Collective

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

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

    2158: +  coarse - coarse level DM
    2159: .  fine - fine level DM to interpolate problem to
    2160: -  ctx - optional user-defined function context

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

    2165: +  coarse - coarse level DM
    2166: .  interp - matrix interpolating a coarse-level solution to the finer grid
    2167: .  fine - fine level DM to update
    2168: -  ctx - optional user-defined function context

    2170:    Level: advanced

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

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

    2177:    This function is currently not available from Fortran.

    2179: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2180: @*/
    2181: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2182: {
    2183:   PetscErrorCode   ierr;
    2184:   DMRefineHookLink link,*p;

    2188:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    2189:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
    2190:   }
    2191:   PetscNew(&link);
    2192:   link->refinehook = refinehook;
    2193:   link->interphook = interphook;
    2194:   link->ctx        = ctx;
    2195:   link->next       = NULL;
    2196:   *p               = link;
    2197:   return(0);
    2198: }

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

    2203:    Logically Collective

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

    2211:    Level: advanced

    2213:    Notes:
    2214:    This function does nothing if the hook is not in the list.

    2216:    This function is currently not available from Fortran.

    2218: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2219: @*/
    2220: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2221: {
    2222:   PetscErrorCode   ierr;
    2223:   DMRefineHookLink link,*p;

    2227:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    2228:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
    2229:       link = *p;
    2230:       *p = link->next;
    2231:       PetscFree(link);
    2232:       break;
    2233:     }
    2234:   }
    2235:   return(0);
    2236: }

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

    2241:    Collective if any hooks are

    2243:    Input Parameters:
    2244: +  coarse - coarser DM to use as a base
    2245: .  interp - interpolation matrix, apply using MatInterpolate()
    2246: -  fine - finer DM to update

    2248:    Level: developer

    2250: .seealso: DMRefineHookAdd(), MatInterpolate()
    2251: @*/
    2252: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
    2253: {
    2254:   PetscErrorCode   ierr;
    2255:   DMRefineHookLink link;

    2258:   for (link=fine->refinehook; link; link=link->next) {
    2259:     if (link->interphook) {
    2260:       (*link->interphook)(coarse,interp,fine,link->ctx);
    2261:     }
    2262:   }
    2263:   return(0);
    2264: }

    2266: /*@
    2267:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

    2269:    Collective on DM

    2271:    Input Parameters:
    2272: +  coarse - coarse DM
    2273: .  fine   - fine DM
    2274: .  interp - (optional) the matrix computed by DMCreateInterpolation().  Implementations may not need this, but if it
    2275:             is available it can avoid some recomputation.  If it is provided, MatInterpolate() will be used if
    2276:             the coarse DM does not have a specialized implementation.
    2277: -  coarseSol - solution on the coarse mesh

    2279:    Output Parameter:
    2280: .  fineSol - the interpolation of coarseSol to the fine mesh

    2282:    Level: developer

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

    2289: .seealso DMInterpolate(), DMCreateInterpolation()
    2290: @*/
    2291: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
    2292: {
    2293:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;

    2302:   PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
    2303:   if (interpsol) {
    2304:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
    2305:   } else if (interp) {
    2306:     MatInterpolate(interp, coarseSol, fineSol);
    2307:   } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
    2308:   return(0);
    2309: }

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

    2314:     Not Collective

    2316:     Input Parameter:
    2317: .   dm - the DM object

    2319:     Output Parameter:
    2320: .   level - number of refinements

    2322:     Level: developer

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

    2326: @*/
    2327: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
    2328: {
    2331:   *level = dm->levelup;
    2332:   return(0);
    2333: }

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

    2338:     Not Collective

    2340:     Input Parameters:
    2341: +   dm - the DM object
    2342: -   level - number of refinements

    2344:     Level: advanced

    2346:     Notes:
    2347:     This value is used by PCMG to determine how many multigrid levels to use

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

    2351: @*/
    2352: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
    2353: {
    2356:   dm->levelup = level;
    2357:   return(0);
    2358: }

    2360: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
    2361: {
    2365:   *tdm = dm->transformDM;
    2366:   return(0);
    2367: }

    2369: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
    2370: {
    2374:   *tv = dm->transform;
    2375:   return(0);
    2376: }

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

    2381:   Input Parameter:
    2382: . dm - The DM

    2384:   Output Parameter:
    2385: . flg - PETSC_TRUE if a basis transformation should be done

    2387:   Level: developer

    2389: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
    2390: @*/
    2391: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
    2392: {
    2393:   Vec            tv;

    2399:   DMGetBasisTransformVec_Internal(dm, &tv);
    2400:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
    2401:   return(0);
    2402: }

    2404: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
    2405: {
    2406:   PetscSection   s, ts;
    2407:   PetscScalar   *ta;
    2408:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

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

    2442:         /* TODO Get quadrature point for this dual basis vector for coordinate */
    2443:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
    2444:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
    2445:         PetscArraycpy(tva, A, PetscSqr(cdim));
    2446:       }
    2447:     }
    2448:   }
    2449:   VecRestoreArray(dm->transform, &ta);
    2450:   return(0);
    2451: }

    2453: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
    2454: {

    2460:   newdm->transformCtx       = dm->transformCtx;
    2461:   newdm->transformSetUp     = dm->transformSetUp;
    2462:   newdm->transformDestroy   = NULL;
    2463:   newdm->transformGetMatrix = dm->transformGetMatrix;
    2464:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
    2465:   return(0);
    2466: }

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

    2471:    Logically Collective

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

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

    2482: +  dm - global DM
    2483: .  g - global vector
    2484: .  mode - mode
    2485: .  l - local vector
    2486: -  ctx - optional user-defined function context

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

    2491: +  global - global DM
    2492: -  ctx - optional user-defined function context

    2494:    Level: advanced

    2496: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2497: @*/
    2498: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
    2499: {
    2500:   PetscErrorCode          ierr;
    2501:   DMGlobalToLocalHookLink link,*p;

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

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

    2525:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    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:     PetscSectionGetChart(cSec,&pStart,&pEnd);
    2535:     for (p = pStart; p < pEnd; p++) {
    2536:       PetscSectionGetDof(cSec,p,&dof);
    2537:       if (dof) {
    2538:         PetscScalar *vals;
    2539:         VecGetValuesSection(cVec,cSec,p,&vals);
    2540:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
    2541:       }
    2542:     }
    2543:     VecDestroy(&cVec);
    2544:   }
    2545:   return(0);
    2546: }

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

    2551:     Neighbor-wise Collective on dm

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

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

    2563:     Level: beginner

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

    2567: @*/
    2568: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
    2569: {

    2573:   DMGlobalToLocalBegin(dm,g,mode,l);
    2574:   DMGlobalToLocalEnd(dm,g,mode,l);
    2575:   return(0);
    2576: }

    2578: /*@
    2579:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

    2581:     Neighbor-wise Collective on dm

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

    2589:     Level: intermediate

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

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

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

    2613:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2614:     VecGetArrayAndMemType(l, &lArray, &lmtype);
    2615:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
    2616:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
    2617:     VecRestoreArrayAndMemType(l, &lArray);
    2618:     VecRestoreArrayReadAndMemType(g, &gArray);
    2619:   } else {
    2620:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
    2621:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2622:   }
    2623:   return(0);
    2624: }

    2626: /*@
    2627:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

    2629:     Neighbor-wise Collective on dm

    2631:     Input Parameters:
    2632: +   dm - the DM object
    2633: .   g - the global vector
    2634: .   mode - INSERT_VALUES or ADD_VALUES
    2635: -   l - the local vector

    2637:     Level: intermediate

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

    2641: @*/
    2642: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    2643: {
    2644:   PetscSF                 sf;
    2645:   PetscErrorCode          ierr;
    2646:   const PetscScalar      *gArray;
    2647:   PetscScalar            *lArray;
    2648:   PetscBool               transform;
    2649:   DMGlobalToLocalHookLink link;
    2650:   PetscMemType            lmtype,gmtype;

    2654:   DMGetSectionSF(dm, &sf);
    2655:   DMHasBasisTransform(dm, &transform);
    2656:   if (sf) {
    2657:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

    2659:     VecGetArrayAndMemType(l, &lArray, &lmtype);
    2660:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
    2661:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
    2662:     VecRestoreArrayAndMemType(l, &lArray);
    2663:     VecRestoreArrayReadAndMemType(g, &gArray);
    2664:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
    2665:   } else {
    2666:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
    2667:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2668:   }
    2669:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
    2670:   for (link=dm->gtolhook; link; link=link->next) {
    2671:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2672:   }
    2673:   return(0);
    2674: }

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

    2679:    Logically Collective

    2681:    Input Parameters:
    2682: +  dm - the DM
    2683: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
    2684: .  endhook - function to run after DMLocalToGlobalEnd() has completed
    2685: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    2690: +  dm - global DM
    2691: .  l - local vector
    2692: .  mode - mode
    2693: .  g - global vector
    2694: -  ctx - optional user-defined function context

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

    2699: +  global - global DM
    2700: .  l - local vector
    2701: .  mode - mode
    2702: .  g - global vector
    2703: -  ctx - optional user-defined function context

    2705:    Level: advanced

    2707: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2708: @*/
    2709: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
    2710: {
    2711:   PetscErrorCode          ierr;
    2712:   DMLocalToGlobalHookLink link,*p;

    2716:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
    2717:   PetscNew(&link);
    2718:   link->beginhook = beginhook;
    2719:   link->endhook   = endhook;
    2720:   link->ctx       = ctx;
    2721:   link->next      = NULL;
    2722:   *p              = link;
    2723:   return(0);
    2724: }

    2726: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
    2727: {
    2728:   Mat cMat;
    2729:   Vec cVec;
    2730:   PetscSection section, cSec;
    2731:   PetscInt pStart, pEnd, p, dof;

    2736:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    2737:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
    2738:     PetscInt nRows;

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

    2767:     Neighbor-wise Collective on dm

    2769:     Input Parameters:
    2770: +   dm - the DM object
    2771: .   l - the local vector
    2772: .   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.
    2773: -   g - the global vector

    2775:     Notes:
    2776:     The communication involved in this update can be overlapped with computation by using
    2777:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

    2782:     Level: beginner

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

    2786: @*/
    2787: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
    2788: {

    2792:   DMLocalToGlobalBegin(dm,l,mode,g);
    2793:   DMLocalToGlobalEnd(dm,l,mode,g);
    2794:   return(0);
    2795: }

    2797: /*@
    2798:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

    2800:     Neighbor-wise Collective on dm

    2802:     Input Parameters:
    2803: +   dm - the DM object
    2804: .   l - the local vector
    2805: .   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.
    2806: -   g - the global vector

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

    2812:     Level: intermediate

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

    2816: @*/
    2817: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
    2818: {
    2819:   PetscSF                 sf;
    2820:   PetscSection            s, gs;
    2821:   DMLocalToGlobalHookLink link;
    2822:   Vec                     tmpl;
    2823:   const PetscScalar      *lArray;
    2824:   PetscScalar            *gArray;
    2825:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
    2826:   PetscErrorCode          ierr;
    2827:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

    2831:   for (link=dm->ltoghook; link; link=link->next) {
    2832:     if (link->beginhook) {
    2833:       (*link->beginhook)(dm,l,mode,g,link->ctx);
    2834:     }
    2835:   }
    2836:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
    2837:   DMGetSectionSF(dm, &sf);
    2838:   DMGetLocalSection(dm, &s);
    2839:   switch (mode) {
    2840:   case INSERT_VALUES:
    2841:   case INSERT_ALL_VALUES:
    2842:   case INSERT_BC_VALUES:
    2843:     isInsert = PETSC_TRUE; break;
    2844:   case ADD_VALUES:
    2845:   case ADD_ALL_VALUES:
    2846:   case ADD_BC_VALUES:
    2847:     isInsert = PETSC_FALSE; break;
    2848:   default:
    2849:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2850:   }
    2851:   if ((sf && !isInsert) || (s && isInsert)) {
    2852:     DMHasBasisTransform(dm, &transform);
    2853:     if (transform) {
    2854:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2855:       VecCopy(l, tmpl);
    2856:       DMPlexLocalToGlobalBasis(dm, tmpl);
    2857:       VecGetArrayRead(tmpl, &lArray);
    2858:     } else if (isInsert) {
    2859:       VecGetArrayRead(l, &lArray);
    2860:     } else {
    2861:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
    2862:       l_inplace = PETSC_TRUE;
    2863:     }
    2864:     if (s && isInsert) {
    2865:       VecGetArray(g, &gArray);
    2866:     } else {
    2867:       VecGetArrayAndMemType(g, &gArray, &gmtype);
    2868:       g_inplace = PETSC_TRUE;
    2869:     }
    2870:     if (sf && !isInsert) {
    2871:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
    2872:     } else if (s && isInsert) {
    2873:       PetscInt gStart, pStart, pEnd, p;

    2875:       DMGetGlobalSection(dm, &gs);
    2876:       PetscSectionGetChart(s, &pStart, &pEnd);
    2877:       VecGetOwnershipRange(g, &gStart, NULL);
    2878:       for (p = pStart; p < pEnd; ++p) {
    2879:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

    2881:         PetscSectionGetDof(s, p, &dof);
    2882:         PetscSectionGetDof(gs, p, &gdof);
    2883:         PetscSectionGetConstraintDof(s, p, &cdof);
    2884:         PetscSectionGetConstraintDof(gs, p, &gcdof);
    2885:         PetscSectionGetOffset(s, p, &off);
    2886:         PetscSectionGetOffset(gs, p, &goff);
    2887:         /* Ignore off-process data and points with no global data */
    2888:         if (!gdof || goff < 0) continue;
    2889:         if (dof != gdof) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
    2890:         /* If no constraints are enforced in the global vector */
    2891:         if (!gcdof) {
    2892:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
    2893:           /* If constraints are enforced in the global vector */
    2894:         } else if (cdof == gcdof) {
    2895:           const PetscInt *cdofs;
    2896:           PetscInt        cind = 0;

    2898:           PetscSectionGetConstraintIndices(s, p, &cdofs);
    2899:           for (d = 0, e = 0; d < dof; ++d) {
    2900:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
    2901:             gArray[goff-gStart+e++] = lArray[off+d];
    2902:           }
    2903:         } else SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %d dof: %d gdof: %d cdof: %d gcdof: %d", p, dof, gdof, cdof, gcdof);
    2904:       }
    2905:     }
    2906:     if (g_inplace) {
    2907:       VecRestoreArrayAndMemType(g, &gArray);
    2908:     } else {
    2909:       VecRestoreArray(g, &gArray);
    2910:     }
    2911:     if (transform) {
    2912:       VecRestoreArrayRead(tmpl, &lArray);
    2913:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2914:     } else if (l_inplace) {
    2915:       VecRestoreArrayReadAndMemType(l, &lArray);
    2916:     } else {
    2917:       VecRestoreArrayRead(l, &lArray);
    2918:     }
    2919:   } else {
    2920:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
    2921:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2922:   }
    2923:   return(0);
    2924: }

    2926: /*@
    2927:     DMLocalToGlobalEnd - updates global vectors from local vectors

    2929:     Neighbor-wise Collective on dm

    2931:     Input Parameters:
    2932: +   dm - the DM object
    2933: .   l - the local vector
    2934: .   mode - INSERT_VALUES or ADD_VALUES
    2935: -   g - the global vector

    2937:     Level: intermediate

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

    2941: @*/
    2942: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
    2943: {
    2944:   PetscSF                 sf;
    2945:   PetscSection            s;
    2946:   DMLocalToGlobalHookLink link;
    2947:   PetscBool               isInsert, transform;
    2948:   PetscErrorCode          ierr;

    2952:   DMGetSectionSF(dm, &sf);
    2953:   DMGetLocalSection(dm, &s);
    2954:   switch (mode) {
    2955:   case INSERT_VALUES:
    2956:   case INSERT_ALL_VALUES:
    2957:     isInsert = PETSC_TRUE; break;
    2958:   case ADD_VALUES:
    2959:   case ADD_ALL_VALUES:
    2960:     isInsert = PETSC_FALSE; break;
    2961:   default:
    2962:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2963:   }
    2964:   if (sf && !isInsert) {
    2965:     const PetscScalar *lArray;
    2966:     PetscScalar       *gArray;
    2967:     Vec                tmpl;

    2969:     DMHasBasisTransform(dm, &transform);
    2970:     if (transform) {
    2971:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2972:       VecGetArrayRead(tmpl, &lArray);
    2973:     } else {
    2974:       VecGetArrayReadAndMemType(l, &lArray, NULL);
    2975:     }
    2976:     VecGetArrayAndMemType(g, &gArray, NULL);
    2977:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
    2978:     if (transform) {
    2979:       VecRestoreArrayRead(tmpl, &lArray);
    2980:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2981:     } else {
    2982:       VecRestoreArrayReadAndMemType(l, &lArray);
    2983:     }
    2984:     VecRestoreArrayAndMemType(g, &gArray);
    2985:   } else if (s && isInsert) {
    2986:   } else {
    2987:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
    2988:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2989:   }
    2990:   for (link=dm->ltoghook; link; link=link->next) {
    2991:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2992:   }
    2993:   return(0);
    2994: }

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

    3001:    Neighbor-wise Collective on dm

    3003:    Input Parameters:
    3004: +  dm - the DM object
    3005: .  g - the original local vector
    3006: -  mode - one of INSERT_VALUES or ADD_VALUES

    3008:    Output Parameter:
    3009: .  l  - the local vector with correct ghost values

    3011:    Level: intermediate

    3013:    Notes:
    3014:    The local vectors used here need not be the same as those
    3015:    obtained from DMCreateLocalVector(), BUT they
    3016:    must have the same parallel data layout; they could, for example, be
    3017:    obtained with VecDuplicate() from the DM originating vectors.

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

    3021: @*/
    3022: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
    3023: {
    3024:   PetscErrorCode          ierr;

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

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

    3038:    Neighbor-wise Collective on dm

    3040:    Input Parameters:
    3041: +  da - the DM object
    3042: .  g - the original local vector
    3043: -  mode - one of INSERT_VALUES or ADD_VALUES

    3045:    Output Parameter:
    3046: .  l  - the local vector with correct ghost values

    3048:    Level: intermediate

    3050:    Notes:
    3051:    The local vectors used here need not be the same as those
    3052:    obtained from DMCreateLocalVector(), BUT they
    3053:    must have the same parallel data layout; they could, for example, be
    3054:    obtained with VecDuplicate() from the DM originating vectors.

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

    3058: @*/
    3059: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    3060: {
    3061:   PetscErrorCode          ierr;

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

    3070: /*@
    3071:     DMCoarsen - Coarsens a DM object

    3073:     Collective on dm

    3075:     Input Parameters:
    3076: +   dm - the DM object
    3077: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    3079:     Output Parameter:
    3080: .   dmc - the coarsened DM

    3082:     Level: developer

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

    3086: @*/
    3087: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
    3088: {
    3089:   PetscErrorCode    ierr;
    3090:   DMCoarsenHookLink link;

    3094:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
    3095:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
    3096:   (*dm->ops->coarsen)(dm, comm, dmc);
    3097:   if (*dmc) {
    3098:     DMSetCoarseDM(dm,*dmc);
    3099:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
    3100:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
    3101:     (*dmc)->ctx               = dm->ctx;
    3102:     (*dmc)->levelup           = dm->levelup;
    3103:     (*dmc)->leveldown         = dm->leveldown + 1;
    3104:     DMSetMatType(*dmc,dm->mattype);
    3105:     for (link=dm->coarsenhook; link; link=link->next) {
    3106:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
    3107:     }
    3108:   }
    3109:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
    3110:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
    3111:   return(0);
    3112: }

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

    3117:    Logically Collective

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

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

    3128: +  fine - fine level DM
    3129: .  coarse - coarse level DM to restrict problem to
    3130: -  ctx - optional user-defined function context

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

    3135: +  fine - fine level DM
    3136: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
    3137: .  rscale - scaling vector for restriction
    3138: .  inject - matrix restricting by injection
    3139: .  coarse - coarse level DM to update
    3140: -  ctx - optional user-defined function context

    3142:    Level: advanced

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

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

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

    3152:    This function is currently not available from Fortran.

    3154: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3155: @*/
    3156: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3157: {
    3158:   PetscErrorCode    ierr;
    3159:   DMCoarsenHookLink link,*p;

    3163:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3164:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3165:   }
    3166:   PetscNew(&link);
    3167:   link->coarsenhook  = coarsenhook;
    3168:   link->restricthook = restricthook;
    3169:   link->ctx          = ctx;
    3170:   link->next         = NULL;
    3171:   *p                 = link;
    3172:   return(0);
    3173: }

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

    3178:    Logically Collective

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

    3186:    Level: advanced

    3188:    Notes:
    3189:    This function does nothing if the hook is not in the list.

    3191:    This function is currently not available from Fortran.

    3193: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3194: @*/
    3195: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3196: {
    3197:   PetscErrorCode    ierr;
    3198:   DMCoarsenHookLink link,*p;

    3202:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3203:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3204:       link = *p;
    3205:       *p = link->next;
    3206:       PetscFree(link);
    3207:       break;
    3208:     }
    3209:   }
    3210:   return(0);
    3211: }

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

    3216:    Collective if any hooks are

    3218:    Input Parameters:
    3219: +  fine - finer DM to use as a base
    3220: .  restrct - restriction matrix, apply using MatRestrict()
    3221: .  rscale - scaling vector for restriction
    3222: .  inject - injection matrix, also use MatRestrict()
    3223: -  coarse - coarser DM to update

    3225:    Level: developer

    3227: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3228: @*/
    3229: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
    3230: {
    3231:   PetscErrorCode    ierr;
    3232:   DMCoarsenHookLink link;

    3235:   for (link=fine->coarsenhook; link; link=link->next) {
    3236:     if (link->restricthook) {
    3237:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
    3238:     }
    3239:   }
    3240:   return(0);
    3241: }

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

    3246:    Logically Collective on global

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

    3254:    Calling sequence for ddhook:
    3255: $    ddhook(DM global,DM block,void *ctx)

    3257: +  global - global DM
    3258: .  block  - block DM
    3259: -  ctx - optional user-defined function context

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

    3264: +  global - global DM
    3265: .  out    - scatter to the outer (with ghost and overlap points) block vector
    3266: .  in     - scatter to block vector values only owned locally
    3267: .  block  - block DM
    3268: -  ctx - optional user-defined function context

    3270:    Level: advanced

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

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

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

    3280:    This function is currently not available from Fortran.

    3282: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3283: @*/
    3284: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3285: {
    3286:   PetscErrorCode      ierr;
    3287:   DMSubDomainHookLink link,*p;

    3291:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3292:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3293:   }
    3294:   PetscNew(&link);
    3295:   link->restricthook = restricthook;
    3296:   link->ddhook       = ddhook;
    3297:   link->ctx          = ctx;
    3298:   link->next         = NULL;
    3299:   *p                 = link;
    3300:   return(0);
    3301: }

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

    3306:    Logically Collective

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

    3314:    Level: advanced

    3316:    Notes:

    3318:    This function is currently not available from Fortran.

    3320: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3321: @*/
    3322: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3323: {
    3324:   PetscErrorCode      ierr;
    3325:   DMSubDomainHookLink link,*p;

    3329:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3330:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3331:       link = *p;
    3332:       *p = link->next;
    3333:       PetscFree(link);
    3334:       break;
    3335:     }
    3336:   }
    3337:   return(0);
    3338: }

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

    3343:    Collective if any hooks are

    3345:    Input Parameters:
    3346: +  fine - finer DM to use as a base
    3347: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
    3348: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
    3349: -  coarse - coarer DM to update

    3351:    Level: developer

    3353: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3354: @*/
    3355: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
    3356: {
    3357:   PetscErrorCode      ierr;
    3358:   DMSubDomainHookLink link;

    3361:   for (link=global->subdomainhook; link; link=link->next) {
    3362:     if (link->restricthook) {
    3363:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
    3364:     }
    3365:   }
    3366:   return(0);
    3367: }

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

    3372:     Not Collective

    3374:     Input Parameter:
    3375: .   dm - the DM object

    3377:     Output Parameter:
    3378: .   level - number of coarsenings

    3380:     Level: developer

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

    3384: @*/
    3385: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
    3386: {
    3390:   *level = dm->leveldown;
    3391:   return(0);
    3392: }

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

    3397:     Not Collective

    3399:     Input Parameters:
    3400: +   dm - the DM object
    3401: -   level - number of coarsenings

    3403:     Level: developer

    3405: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    3406: @*/
    3407: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
    3408: {
    3411:   dm->leveldown = level;
    3412:   return(0);
    3413: }

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

    3418:     Collective on dm

    3420:     Input Parameters:
    3421: +   dm - the DM object
    3422: -   nlevels - the number of levels of refinement

    3424:     Output Parameter:
    3425: .   dmf - the refined DM hierarchy

    3427:     Level: developer

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

    3431: @*/
    3432: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
    3433: {

    3438:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3439:   if (nlevels == 0) return(0);
    3441:   if (dm->ops->refinehierarchy) {
    3442:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
    3443:   } else if (dm->ops->refine) {
    3444:     PetscInt i;

    3446:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
    3447:     for (i=1; i<nlevels; i++) {
    3448:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
    3449:     }
    3450:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
    3451:   return(0);
    3452: }

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

    3457:     Collective on dm

    3459:     Input Parameters:
    3460: +   dm - the DM object
    3461: -   nlevels - the number of levels of coarsening

    3463:     Output Parameter:
    3464: .   dmc - the coarsened DM hierarchy

    3466:     Level: developer

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

    3470: @*/
    3471: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
    3472: {

    3477:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3478:   if (nlevels == 0) return(0);
    3480:   if (dm->ops->coarsenhierarchy) {
    3481:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
    3482:   } else if (dm->ops->coarsen) {
    3483:     PetscInt i;

    3485:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
    3486:     for (i=1; i<nlevels; i++) {
    3487:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
    3488:     }
    3489:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
    3490:   return(0);
    3491: }

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

    3496:     Not Collective

    3498:     Input Parameters:
    3499: +   dm - the DM object
    3500: -   destroy - the destroy function

    3502:     Level: intermediate

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

    3506: @*/
    3507: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
    3508: {
    3511:   dm->ctxdestroy = destroy;
    3512:   return(0);
    3513: }

    3515: /*@
    3516:     DMSetApplicationContext - Set a user context into a DM object

    3518:     Not Collective

    3520:     Input Parameters:
    3521: +   dm - the DM object
    3522: -   ctx - the user context

    3524:     Level: intermediate

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

    3528: @*/
    3529: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
    3530: {
    3533:   dm->ctx = ctx;
    3534:   return(0);
    3535: }

    3537: /*@
    3538:     DMGetApplicationContext - Gets a user context from a DM object

    3540:     Not Collective

    3542:     Input Parameter:
    3543: .   dm - the DM object

    3545:     Output Parameter:
    3546: .   ctx - the user context

    3548:     Level: intermediate

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

    3552: @*/
    3553: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
    3554: {
    3557:   *(void**)ctx = dm->ctx;
    3558:   return(0);
    3559: }

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

    3564:     Logically Collective on dm

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

    3570:     Level: intermediate

    3572: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
    3573:          DMSetJacobian()

    3575: @*/
    3576: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
    3577: {
    3580:   dm->ops->computevariablebounds = f;
    3581:   return(0);
    3582: }

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

    3587:     Not Collective

    3589:     Input Parameter:
    3590: .   dm - the DM object to destroy

    3592:     Output Parameter:
    3593: .   flg - PETSC_TRUE if the variable bounds function exists

    3595:     Level: developer

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

    3599: @*/
    3600: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
    3601: {
    3605:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
    3606:   return(0);
    3607: }

    3609: /*@C
    3610:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

    3612:     Logically Collective on dm

    3614:     Input Parameter:
    3615: .   dm - the DM object

    3617:     Output parameters:
    3618: +   xl - lower bound
    3619: -   xu - upper bound

    3621:     Level: advanced

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

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

    3628: @*/
    3629: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
    3630: {

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

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

    3645:     Not Collective

    3647:     Input Parameter:
    3648: .   dm - the DM object

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

    3653:     Level: developer

    3655: .seealso DMCreateColoring()

    3657: @*/
    3658: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
    3659: {
    3663:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
    3664:   return(0);
    3665: }

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

    3670:     Not Collective

    3672:     Input Parameter:
    3673: .   dm - the DM object

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

    3678:     Level: developer

    3680: .seealso DMCreateRestriction()

    3682: @*/
    3683: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
    3684: {
    3688:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
    3689:   return(0);
    3690: }

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

    3695:     Not Collective

    3697:     Input Parameter:
    3698: .   dm - the DM object

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

    3703:     Level: developer

    3705: .seealso DMCreateInjection()

    3707: @*/
    3708: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
    3709: {

    3715:   if (dm->ops->hascreateinjection) {
    3716:     (*dm->ops->hascreateinjection)(dm,flg);
    3717:   } else {
    3718:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
    3719:   }
    3720:   return(0);
    3721: }

    3723: PetscFunctionList DMList              = NULL;
    3724: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

    3726: /*@C
    3727:   DMSetType - Builds a DM, for a particular DM implementation.

    3729:   Collective on dm

    3731:   Input Parameters:
    3732: + dm     - The DM object
    3733: - method - The name of the DM type

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

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

    3741:   Level: intermediate

    3743: .seealso: DMGetType(), DMCreate()
    3744: @*/
    3745: PetscErrorCode  DMSetType(DM dm, DMType method)
    3746: {
    3747:   PetscErrorCode (*r)(DM);
    3748:   PetscBool      match;

    3753:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
    3754:   if (match) return(0);

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

    3760:   if (dm->ops->destroy) {
    3761:     (*dm->ops->destroy)(dm);
    3762:   }
    3763:   PetscMemzero(dm->ops,sizeof(*dm->ops));
    3764:   PetscObjectChangeTypeName((PetscObject)dm,method);
    3765:   (*r)(dm);
    3766:   return(0);
    3767: }

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

    3772:   Not Collective

    3774:   Input Parameter:
    3775: . dm  - The DM

    3777:   Output Parameter:
    3778: . type - The DM type name

    3780:   Level: intermediate

    3782: .seealso: DMSetType(), DMCreate()
    3783: @*/
    3784: PetscErrorCode  DMGetType(DM dm, DMType *type)
    3785: {

    3791:   DMRegisterAll();
    3792:   *type = ((PetscObject)dm)->type_name;
    3793:   return(0);
    3794: }

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

    3799:   Collective on dm

    3801:   Input Parameters:
    3802: + dm - the DM
    3803: - newtype - new DM type (use "same" for the same type)

    3805:   Output Parameter:
    3806: . M - pointer to new DM

    3808:   Notes:
    3809:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
    3810:   the MPI communicator of the generated DM is always the same as the communicator
    3811:   of the input DM.

    3813:   Level: intermediate

    3815: .seealso: DMCreate()
    3816: @*/
    3817: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
    3818: {
    3819:   DM             B;
    3820:   char           convname[256];
    3821:   PetscBool      sametype/*, issame */;

    3828:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
    3829:   /* PetscStrcmp(newtype, "same", &issame); */
    3830:   if (sametype) {
    3831:     *M   = dm;
    3832:     PetscObjectReference((PetscObject) dm);
    3833:     return(0);
    3834:   } else {
    3835:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

    3837:     /*
    3838:        Order of precedence:
    3839:        1) See if a specialized converter is known to the current DM.
    3840:        2) See if a specialized converter is known to the desired DM class.
    3841:        3) See if a good general converter is registered for the desired class
    3842:        4) See if a good general converter is known for the current matrix.
    3843:        5) Use a really basic converter.
    3844:     */

    3846:     /* 1) See if a specialized converter is known to the current DM and the desired class */
    3847:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3848:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3849:     PetscStrlcat(convname,"_",sizeof(convname));
    3850:     PetscStrlcat(convname,newtype,sizeof(convname));
    3851:     PetscStrlcat(convname,"_C",sizeof(convname));
    3852:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
    3853:     if (conv) goto foundconv;

    3855:     /* 2)  See if a specialized converter is known to the desired DM class. */
    3856:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
    3857:     DMSetType(B, newtype);
    3858:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3859:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3860:     PetscStrlcat(convname,"_",sizeof(convname));
    3861:     PetscStrlcat(convname,newtype,sizeof(convname));
    3862:     PetscStrlcat(convname,"_C",sizeof(convname));
    3863:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
    3864:     if (conv) {
    3865:       DMDestroy(&B);
    3866:       goto foundconv;
    3867:     }

    3869: #if 0
    3870:     /* 3) See if a good general converter is registered for the desired class */
    3871:     conv = B->ops->convertfrom;
    3872:     DMDestroy(&B);
    3873:     if (conv) goto foundconv;

    3875:     /* 4) See if a good general converter is known for the current matrix */
    3876:     if (dm->ops->convert) {
    3877:       conv = dm->ops->convert;
    3878:     }
    3879:     if (conv) goto foundconv;
    3880: #endif

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

    3885: foundconv:
    3886:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
    3887:     (*conv)(dm,newtype,M);
    3888:     /* Things that are independent of DM type: We should consult DMClone() here */
    3889:     {
    3890:       PetscBool             isper;
    3891:       const PetscReal      *maxCell, *L;
    3892:       const DMBoundaryType *bd;
    3893:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
    3894:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
    3895:       (*M)->prealloc_only = dm->prealloc_only;
    3896:       PetscFree((*M)->vectype);
    3897:       PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
    3898:       PetscFree((*M)->mattype);
    3899:       PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
    3900:     }
    3901:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
    3902:   }
    3903:   PetscObjectStateIncrease((PetscObject) *M);
    3904:   return(0);
    3905: }

    3907: /*--------------------------------------------------------------------------------------------------------------------*/

    3909: /*@C
    3910:   DMRegister -  Adds a new DM component implementation

    3912:   Not Collective

    3914:   Input Parameters:
    3915: + name        - The name of a new user-defined creation routine
    3916: - create_func - The creation routine itself

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

    3921:   Sample usage:
    3922: .vb
    3923:     DMRegister("my_da", MyDMCreate);
    3924: .ve

    3926:   Then, your DM type can be chosen with the procedural interface via
    3927: .vb
    3928:     DMCreate(MPI_Comm, DM *);
    3929:     DMSetType(DM,"my_da");
    3930: .ve
    3931:    or at runtime via the option
    3932: .vb
    3933:     -da_type my_da
    3934: .ve

    3936:   Level: advanced

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

    3940: @*/
    3941: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
    3942: {

    3946:   DMInitializePackage();
    3947:   PetscFunctionListAdd(&DMList,sname,function);
    3948:   return(0);
    3949: }

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

    3954:   Collective on viewer

    3956:   Input Parameters:
    3957: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
    3958:            some related function before a call to DMLoad().
    3959: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
    3960:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

    3962:    Level: intermediate

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

    3967:   Notes for advanced users:
    3968:   Most users should not need to know the details of the binary storage
    3969:   format, since DMLoad() and DMView() completely hide these details.
    3970:   But for anyone who's interested, the standard binary matrix storage
    3971:   format is
    3972: .vb
    3973:      has not yet been determined
    3974: .ve

    3976: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
    3977: @*/
    3978: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
    3979: {
    3980:   PetscBool      isbinary, ishdf5;

    3986:   PetscViewerCheckReadable(viewer);
    3987:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
    3988:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
    3989:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
    3990:   if (isbinary) {
    3991:     PetscInt classid;
    3992:     char     type[256];

    3994:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
    3995:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
    3996:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
    3997:     DMSetType(newdm, type);
    3998:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    3999:   } else if (ishdf5) {
    4000:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    4001:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
    4002:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
    4003:   return(0);
    4004: }

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

    4009:   Not collective

    4011:   Input Parameter:
    4012: . dm - the DM

    4014:   Output Parameters:
    4015: + lmin - local minimum coordinates (length coord dim, optional)
    4016: - lmax - local maximim coordinates (length coord dim, optional)

    4018:   Level: beginner

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

    4022: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
    4023: @*/
    4024: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
    4025: {
    4026:   Vec                coords = NULL;
    4027:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
    4028:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
    4029:   const PetscScalar *local_coords;
    4030:   PetscInt           N, Ni;
    4031:   PetscInt           cdim, i, j;
    4032:   PetscErrorCode     ierr;

    4036:   DMGetCoordinateDim(dm, &cdim);
    4037:   DMGetCoordinates(dm, &coords);
    4038:   if (coords) {
    4039:     VecGetArrayRead(coords, &local_coords);
    4040:     VecGetLocalSize(coords, &N);
    4041:     Ni   = N/cdim;
    4042:     for (i = 0; i < Ni; ++i) {
    4043:       for (j = 0; j < 3; ++j) {
    4044:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    4045:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    4046:       }
    4047:     }
    4048:     VecRestoreArrayRead(coords, &local_coords);
    4049:   } else {
    4050:     PetscBool isda;

    4052:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
    4053:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
    4054:   }
    4055:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
    4056:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
    4057:   return(0);
    4058: }

    4060: /*@
    4061:   DMGetBoundingBox - Returns the global bounding box for the DM.

    4063:   Collective

    4065:   Input Parameter:
    4066: . dm - the DM

    4068:   Output Parameters:
    4069: + gmin - global minimum coordinates (length coord dim, optional)
    4070: - gmax - global maximim coordinates (length coord dim, optional)

    4072:   Level: beginner

    4074: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
    4075: @*/
    4076: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
    4077: {
    4078:   PetscReal      lmin[3], lmax[3];
    4079:   PetscInt       cdim;
    4080:   PetscMPIInt    count;

    4085:   DMGetCoordinateDim(dm, &cdim);
    4086:   PetscMPIIntCast(cdim, &count);
    4087:   DMGetLocalBoundingBox(dm, lmin, lmax);
    4088:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
    4089:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
    4090:   return(0);
    4091: }

    4093: /******************************** FEM Support **********************************/

    4095: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
    4096: {
    4097:   PetscInt       f;

    4101:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
    4102:   for (f = 0; f < len; ++f) {
    4103:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
    4104:   }
    4105:   return(0);
    4106: }

    4108: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
    4109: {
    4110:   PetscInt       f, g;

    4114:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
    4115:   for (f = 0; f < rows; ++f) {
    4116:     PetscPrintf(PETSC_COMM_SELF, "  |");
    4117:     for (g = 0; g < cols; ++g) {
    4118:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
    4119:     }
    4120:     PetscPrintf(PETSC_COMM_SELF, " |\n");
    4121:   }
    4122:   return(0);
    4123: }

    4125: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
    4126: {
    4127:   PetscInt          localSize, bs;
    4128:   PetscMPIInt       size;
    4129:   Vec               x, xglob;
    4130:   const PetscScalar *xarray;
    4131:   PetscErrorCode    ierr;

    4134:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
    4135:   VecDuplicate(X, &x);
    4136:   VecCopy(X, x);
    4137:   VecChop(x, tol);
    4138:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
    4139:   if (size > 1) {
    4140:     VecGetLocalSize(x,&localSize);
    4141:     VecGetArrayRead(x,&xarray);
    4142:     VecGetBlockSize(x,&bs);
    4143:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
    4144:   } else {
    4145:     xglob = x;
    4146:   }
    4147:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
    4148:   if (size > 1) {
    4149:     VecDestroy(&xglob);
    4150:     VecRestoreArrayRead(x,&xarray);
    4151:   }
    4152:   VecDestroy(&x);
    4153:   return(0);
    4154: }

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

    4159:   Input Parameter:
    4160: . dm - The DM

    4162:   Output Parameter:
    4163: . section - The PetscSection

    4165:   Options Database Keys:
    4166: . -dm_petscsection_view - View the Section created by the DM

    4168:   Level: advanced

    4170:   Notes:
    4171:   Use DMGetLocalSection() in new code.

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

    4175: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
    4176: @*/
    4177: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
    4178: {

    4182:   DMGetLocalSection(dm,section);
    4183:   return(0);
    4184: }

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

    4189:   Input Parameter:
    4190: . dm - The DM

    4192:   Output Parameter:
    4193: . section - The PetscSection

    4195:   Options Database Keys:
    4196: . -dm_petscsection_view - View the Section created by the DM

    4198:   Level: intermediate

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

    4202: .seealso: DMSetLocalSection(), DMGetGlobalSection()
    4203: @*/
    4204: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
    4205: {

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

    4214:     if (dm->setfromoptionscalled) {
    4215:       PetscObject       obj = (PetscObject) dm;
    4216:       PetscViewer       viewer;
    4217:       PetscViewerFormat format;
    4218:       PetscBool         flg;

    4220:       PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg);
    4221:       if (flg) {PetscViewerPushFormat(viewer, format);}
    4222:       for (d = 0; d < dm->Nds; ++d) {
    4223:         PetscDSSetFromOptions(dm->probs[d].ds);
    4224:         if (flg) {PetscDSView(dm->probs[d].ds, viewer);}
    4225:       }
    4226:       if (flg) {
    4227:         PetscViewerFlush(viewer);
    4228:         PetscViewerPopFormat(viewer);
    4229:         PetscViewerDestroy(&viewer);
    4230:       }
    4231:     }
    4232:     (*dm->ops->createlocalsection)(dm);
    4233:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
    4234:   }
    4235:   *section = dm->localSection;
    4236:   return(0);
    4237: }

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

    4242:   Input Parameters:
    4243: + dm - The DM
    4244: - section - The PetscSection

    4246:   Level: advanced

    4248:   Notes:
    4249:   Use DMSetLocalSection() in new code.

    4251:   Any existing Section will be destroyed

    4253: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
    4254: @*/
    4255: PetscErrorCode DMSetSection(DM dm, PetscSection section)
    4256: {

    4260:   DMSetLocalSection(dm,section);
    4261:   return(0);
    4262: }

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

    4267:   Input Parameters:
    4268: + dm - The DM
    4269: - section - The PetscSection

    4271:   Level: intermediate

    4273:   Note: Any existing Section will be destroyed

    4275: .seealso: DMGetLocalSection(), DMSetGlobalSection()
    4276: @*/
    4277: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
    4278: {
    4279:   PetscInt       numFields = 0;
    4280:   PetscInt       f;

    4286:   PetscObjectReference((PetscObject)section);
    4287:   PetscSectionDestroy(&dm->localSection);
    4288:   dm->localSection = section;
    4289:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
    4290:   if (numFields) {
    4291:     DMSetNumFields(dm, numFields);
    4292:     for (f = 0; f < numFields; ++f) {
    4293:       PetscObject disc;
    4294:       const char *name;

    4296:       PetscSectionGetFieldName(dm->localSection, f, &name);
    4297:       DMGetField(dm, f, NULL, &disc);
    4298:       PetscObjectSetName(disc, name);
    4299:     }
    4300:   }
    4301:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
    4302:   PetscSectionDestroy(&dm->globalSection);
    4303:   return(0);
    4304: }

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

    4309:   not collective

    4311:   Input Parameter:
    4312: . dm - The DM

    4314:   Output Parameters:
    4315: + 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.
    4316: - 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.

    4318:   Level: advanced

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

    4322: .seealso: DMSetDefaultConstraints()
    4323: @*/
    4324: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
    4325: {

    4330:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
    4331:   if (section) {*section = dm->defaultConstraintSection;}
    4332:   if (mat) {*mat = dm->defaultConstraintMat;}
    4333:   return(0);
    4334: }

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

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

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

    4343:   collective on dm

    4345:   Input Parameters:
    4346: + dm - The DM
    4347: + 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).
    4348: - 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).

    4350:   Level: advanced

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

    4354: .seealso: DMGetDefaultConstraints()
    4355: @*/
    4356: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
    4357: {
    4358:   PetscMPIInt result;

    4363:   if (section) {
    4365:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
    4366:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
    4367:   }
    4368:   if (mat) {
    4370:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
    4371:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
    4372:   }
    4373:   PetscObjectReference((PetscObject)section);
    4374:   PetscSectionDestroy(&dm->defaultConstraintSection);
    4375:   dm->defaultConstraintSection = section;
    4376:   PetscObjectReference((PetscObject)mat);
    4377:   MatDestroy(&dm->defaultConstraintMat);
    4378:   dm->defaultConstraintMat = mat;
    4379:   return(0);
    4380: }

    4382: #if defined(PETSC_USE_DEBUG)
    4383: /*
    4384:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

    4386:   Input Parameters:
    4387: + dm - The DM
    4388: . localSection - PetscSection describing the local data layout
    4389: - globalSection - PetscSection describing the global data layout

    4391:   Level: intermediate

    4393: .seealso: DMGetSectionSF(), DMSetSectionSF()
    4394: */
    4395: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
    4396: {
    4397:   MPI_Comm        comm;
    4398:   PetscLayout     layout;
    4399:   const PetscInt *ranges;
    4400:   PetscInt        pStart, pEnd, p, nroots;
    4401:   PetscMPIInt     size, rank;
    4402:   PetscBool       valid = PETSC_TRUE, gvalid;
    4403:   PetscErrorCode  ierr;

    4406:   PetscObjectGetComm((PetscObject)dm,&comm);
    4408:   MPI_Comm_size(comm, &size);
    4409:   MPI_Comm_rank(comm, &rank);
    4410:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
    4411:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
    4412:   PetscLayoutCreate(comm, &layout);
    4413:   PetscLayoutSetBlockSize(layout, 1);
    4414:   PetscLayoutSetLocalSize(layout, nroots);
    4415:   PetscLayoutSetUp(layout);
    4416:   PetscLayoutGetRanges(layout, &ranges);
    4417:   for (p = pStart; p < pEnd; ++p) {
    4418:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

    4420:     PetscSectionGetDof(localSection, p, &dof);
    4421:     PetscSectionGetOffset(localSection, p, &off);
    4422:     PetscSectionGetConstraintDof(localSection, p, &cdof);
    4423:     PetscSectionGetDof(globalSection, p, &gdof);
    4424:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
    4425:     PetscSectionGetOffset(globalSection, p, &goff);
    4426:     if (!gdof) continue; /* Censored point */
    4427:     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;}
    4428:     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;}
    4429:     if (gdof < 0) {
    4430:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
    4431:       for (d = 0; d < gsize; ++d) {
    4432:         PetscInt offset = -(goff+1) + d, r;

    4434:         PetscFindInt(offset,size+1,ranges,&r);
    4435:         if (r < 0) r = -(r+2);
    4436:         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;}
    4437:       }
    4438:     }
    4439:   }
    4440:   PetscLayoutDestroy(&layout);
    4441:   PetscSynchronizedFlush(comm, NULL);
    4442:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
    4443:   if (!gvalid) {
    4444:     DMView(dm, NULL);
    4445:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
    4446:   }
    4447:   return(0);
    4448: }
    4449: #endif

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

    4454:   Collective on dm

    4456:   Input Parameter:
    4457: . dm - The DM

    4459:   Output Parameter:
    4460: . section - The PetscSection

    4462:   Level: intermediate

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

    4466: .seealso: DMSetLocalSection(), DMGetLocalSection()
    4467: @*/
    4468: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
    4469: {

    4475:   if (!dm->globalSection) {
    4476:     PetscSection s;

    4478:     DMGetLocalSection(dm, &s);
    4479:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
    4480:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
    4481:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
    4482:     PetscLayoutDestroy(&dm->map);
    4483:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
    4484:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
    4485:   }
    4486:   *section = dm->globalSection;
    4487:   return(0);
    4488: }

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

    4493:   Input Parameters:
    4494: + dm - The DM
    4495: - section - The PetscSection, or NULL

    4497:   Level: intermediate

    4499:   Note: Any existing Section will be destroyed

    4501: .seealso: DMGetGlobalSection(), DMSetLocalSection()
    4502: @*/
    4503: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
    4504: {

    4510:   PetscObjectReference((PetscObject)section);
    4511:   PetscSectionDestroy(&dm->globalSection);
    4512:   dm->globalSection = section;
    4513: #if defined(PETSC_USE_DEBUG)
    4514:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
    4515: #endif
    4516:   return(0);
    4517: }

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

    4523:   Input Parameter:
    4524: . dm - The DM

    4526:   Output Parameter:
    4527: . sf - The PetscSF

    4529:   Level: intermediate

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

    4533: .seealso: DMSetSectionSF(), DMCreateSectionSF()
    4534: @*/
    4535: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
    4536: {
    4537:   PetscInt       nroots;

    4543:   if (!dm->sectionSF) {
    4544:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
    4545:   }
    4546:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
    4547:   if (nroots < 0) {
    4548:     PetscSection section, gSection;

    4550:     DMGetLocalSection(dm, &section);
    4551:     if (section) {
    4552:       DMGetGlobalSection(dm, &gSection);
    4553:       DMCreateSectionSF(dm, section, gSection);
    4554:     } else {
    4555:       *sf = NULL;
    4556:       return(0);
    4557:     }
    4558:   }
    4559:   *sf = dm->sectionSF;
    4560:   return(0);
    4561: }

    4563: /*@
    4564:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

    4566:   Input Parameters:
    4567: + dm - The DM
    4568: - sf - The PetscSF

    4570:   Level: intermediate

    4572:   Note: Any previous SF is destroyed

    4574: .seealso: DMGetSectionSF(), DMCreateSectionSF()
    4575: @*/
    4576: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
    4577: {

    4583:   PetscObjectReference((PetscObject) sf);
    4584:   PetscSFDestroy(&dm->sectionSF);
    4585:   dm->sectionSF = sf;
    4586:   return(0);
    4587: }

    4589: /*@C
    4590:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
    4591:   describing the data layout.

    4593:   Input Parameters:
    4594: + dm - The DM
    4595: . localSection - PetscSection describing the local data layout
    4596: - globalSection - PetscSection describing the global data layout

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

    4600:   Level: developer

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

    4606: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
    4607: @*/
    4608: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
    4609: {

    4614:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
    4615:   return(0);
    4616: }

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

    4621:   Input Parameter:
    4622: . dm - The DM

    4624:   Output Parameter:
    4625: . sf - The PetscSF

    4627:   Level: intermediate

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

    4631: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4632: @*/
    4633: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
    4634: {
    4638:   *sf = dm->sf;
    4639:   return(0);
    4640: }

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

    4645:   Input Parameters:
    4646: + dm - The DM
    4647: - sf - The PetscSF

    4649:   Level: intermediate

    4651: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4652: @*/
    4653: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
    4654: {

    4660:   PetscObjectReference((PetscObject) sf);
    4661:   PetscSFDestroy(&dm->sf);
    4662:   dm->sf = sf;
    4663:   return(0);
    4664: }

    4666: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
    4667: {
    4668:   PetscClassId   id;

    4672:   PetscObjectGetClassId(disc, &id);
    4673:   if (id == PETSCFE_CLASSID) {
    4674:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
    4675:   } else if (id == PETSCFV_CLASSID) {
    4676:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
    4677:   } else {
    4678:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
    4679:   }
    4680:   return(0);
    4681: }

    4683: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
    4684: {
    4685:   RegionField   *tmpr;
    4686:   PetscInt       Nf = dm->Nf, f;

    4690:   if (Nf >= NfNew) return(0);
    4691:   PetscMalloc1(NfNew, &tmpr);
    4692:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
    4693:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
    4694:   PetscFree(dm->fields);
    4695:   dm->Nf     = NfNew;
    4696:   dm->fields = tmpr;
    4697:   return(0);
    4698: }

    4700: /*@
    4701:   DMClearFields - Remove all fields from the DM

    4703:   Logically collective on dm

    4705:   Input Parameter:
    4706: . dm - The DM

    4708:   Level: intermediate

    4710: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
    4711: @*/
    4712: PetscErrorCode DMClearFields(DM dm)
    4713: {
    4714:   PetscInt       f;

    4719:   for (f = 0; f < dm->Nf; ++f) {
    4720:     PetscObjectDestroy(&dm->fields[f].disc);
    4721:     DMLabelDestroy(&dm->fields[f].label);
    4722:   }
    4723:   PetscFree(dm->fields);
    4724:   dm->fields = NULL;
    4725:   dm->Nf     = 0;
    4726:   return(0);
    4727: }

    4729: /*@
    4730:   DMGetNumFields - Get the number of fields in the DM

    4732:   Not collective

    4734:   Input Parameter:
    4735: . dm - The DM

    4737:   Output Parameter:
    4738: . Nf - The number of fields

    4740:   Level: intermediate

    4742: .seealso: DMSetNumFields(), DMSetField()
    4743: @*/
    4744: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
    4745: {
    4749:   *numFields = dm->Nf;
    4750:   return(0);
    4751: }

    4753: /*@
    4754:   DMSetNumFields - Set the number of fields in the DM

    4756:   Logically collective on dm

    4758:   Input Parameters:
    4759: + dm - The DM
    4760: - Nf - The number of fields

    4762:   Level: intermediate

    4764: .seealso: DMGetNumFields(), DMSetField()
    4765: @*/
    4766: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
    4767: {
    4768:   PetscInt       Nf, f;

    4773:   DMGetNumFields(dm, &Nf);
    4774:   for (f = Nf; f < numFields; ++f) {
    4775:     PetscContainer obj;

    4777:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
    4778:     DMAddField(dm, NULL, (PetscObject) obj);
    4779:     PetscContainerDestroy(&obj);
    4780:   }
    4781:   return(0);
    4782: }

    4784: /*@
    4785:   DMGetField - Return the discretization object for a given DM field

    4787:   Not collective

    4789:   Input Parameters:
    4790: + dm - The DM
    4791: - f  - The field number

    4793:   Output Parameters:
    4794: + label - The label indicating the support of the field, or NULL for the entire mesh
    4795: - field - The discretization object

    4797:   Level: intermediate

    4799: .seealso: DMAddField(), DMSetField()
    4800: @*/
    4801: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
    4802: {
    4806:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, dm->Nf);
    4807:   if (label) *label = dm->fields[f].label;
    4808:   if (field) *field = dm->fields[f].disc;
    4809:   return(0);
    4810: }

    4812: /* Does not clear the DS */
    4813: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4814: {

    4818:   DMFieldEnlarge_Static(dm, f+1);
    4819:   DMLabelDestroy(&dm->fields[f].label);
    4820:   PetscObjectDestroy(&dm->fields[f].disc);
    4821:   dm->fields[f].label = label;
    4822:   dm->fields[f].disc  = field;
    4823:   PetscObjectReference((PetscObject) label);
    4824:   PetscObjectReference((PetscObject) field);
    4825:   return(0);
    4826: }

    4828: /*@
    4829:   DMSetField - Set the discretization object for a given DM field

    4831:   Logically collective on dm

    4833:   Input Parameters:
    4834: + dm    - The DM
    4835: . f     - The field number
    4836: . label - The label indicating the support of the field, or NULL for the entire mesh
    4837: - field - The discretization object

    4839:   Level: intermediate

    4841: .seealso: DMAddField(), DMGetField()
    4842: @*/
    4843: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4844: {

    4851:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    4852:   DMSetField_Internal(dm, f, label, field);
    4853:   DMSetDefaultAdjacency_Private(dm, f, field);
    4854:   DMClearDS(dm);
    4855:   return(0);
    4856: }

    4858: /*@
    4859:   DMAddField - Add the discretization object for the given DM field

    4861:   Logically collective on dm

    4863:   Input Parameters:
    4864: + dm    - The DM
    4865: . label - The label indicating the support of the field, or NULL for the entire mesh
    4866: - field - The discretization object

    4868:   Level: intermediate

    4870: .seealso: DMSetField(), DMGetField()
    4871: @*/
    4872: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
    4873: {
    4874:   PetscInt       Nf = dm->Nf;

    4881:   DMFieldEnlarge_Static(dm, Nf+1);
    4882:   dm->fields[Nf].label = label;
    4883:   dm->fields[Nf].disc  = field;
    4884:   PetscObjectReference((PetscObject) label);
    4885:   PetscObjectReference((PetscObject) field);
    4886:   DMSetDefaultAdjacency_Private(dm, Nf, field);
    4887:   DMClearDS(dm);
    4888:   return(0);
    4889: }

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

    4894:   Logically collective on dm

    4896:   Input Parameters:
    4897: + dm          - The DM
    4898: . f           - The field index
    4899: - avoidTensor - The flag to avoid defining the field on tensor cells

    4901:   Level: intermediate

    4903: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
    4904: @*/
    4905: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
    4906: {
    4908:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
    4909:   dm->fields[f].avoidTensor = avoidTensor;
    4910:   return(0);
    4911: }

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

    4916:   Logically collective on dm

    4918:   Input Parameters:
    4919: + dm          - The DM
    4920: - f           - The field index

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

    4925:   Level: intermediate

    4927: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
    4928: @*/
    4929: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
    4930: {
    4932:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
    4933:   *avoidTensor = dm->fields[f].avoidTensor;
    4934:   return(0);
    4935: }

    4937: /*@
    4938:   DMCopyFields - Copy the discretizations for the DM into another DM

    4940:   Collective on dm

    4942:   Input Parameter:
    4943: . dm - The DM

    4945:   Output Parameter:
    4946: . newdm - The DM

    4948:   Level: advanced

    4950: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
    4951: @*/
    4952: PetscErrorCode DMCopyFields(DM dm, DM newdm)
    4953: {
    4954:   PetscInt       Nf, f;

    4958:   if (dm == newdm) return(0);
    4959:   DMGetNumFields(dm, &Nf);
    4960:   DMClearFields(newdm);
    4961:   for (f = 0; f < Nf; ++f) {
    4962:     DMLabel     label;
    4963:     PetscObject field;
    4964:     PetscBool   useCone, useClosure;

    4966:     DMGetField(dm, f, &label, &field);
    4967:     DMSetField(newdm, f, label, field);
    4968:     DMGetAdjacency(dm, f, &useCone, &useClosure);
    4969:     DMSetAdjacency(newdm, f, useCone, useClosure);
    4970:   }
    4971:   return(0);
    4972: }

    4974: /*@
    4975:   DMGetAdjacency - Returns the flags for determining variable influence

    4977:   Not collective

    4979:   Input Parameters:
    4980: + dm - The DM object
    4981: - f  - The field number, or PETSC_DEFAULT for the default adjacency

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

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

    4993:   Level: developer

    4995: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
    4996: @*/
    4997: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
    4998: {
    5003:   if (f < 0) {
    5004:     if (useCone)    *useCone    = dm->adjacency[0];
    5005:     if (useClosure) *useClosure = dm->adjacency[1];
    5006:   } else {
    5007:     PetscInt       Nf;

    5010:     DMGetNumFields(dm, &Nf);
    5011:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
    5012:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
    5013:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
    5014:   }
    5015:   return(0);
    5016: }

    5018: /*@
    5019:   DMSetAdjacency - Set the flags for determining variable influence

    5021:   Not collective

    5023:   Input Parameters:
    5024: + dm         - The DM object
    5025: . f          - The field number
    5026: . useCone    - Flag for variable influence starting with the cone operation
    5027: - useClosure - Flag for variable influence using transitive closure

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

    5035:   Level: developer

    5037: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
    5038: @*/
    5039: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
    5040: {
    5043:   if (f < 0) {
    5044:     dm->adjacency[0] = useCone;
    5045:     dm->adjacency[1] = useClosure;
    5046:   } else {
    5047:     PetscInt       Nf;

    5050:     DMGetNumFields(dm, &Nf);
    5051:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
    5052:     dm->fields[f].adjacency[0] = useCone;
    5053:     dm->fields[f].adjacency[1] = useClosure;
    5054:   }
    5055:   return(0);
    5056: }

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

    5061:   Not collective

    5063:   Input Parameter:
    5064: . dm - The DM object

    5066:   Output Parameters:
    5067: + useCone    - Flag for variable influence starting with the cone operation
    5068: - useClosure - Flag for variable influence using transitive closure

    5070:   Notes:
    5071: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
    5072: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
    5073: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

    5075:   Level: developer

    5077: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
    5078: @*/
    5079: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
    5080: {
    5081:   PetscInt       Nf;

    5088:   DMGetNumFields(dm, &Nf);
    5089:   if (!Nf) {
    5090:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    5091:   } else {
    5092:     DMGetAdjacency(dm, 0, useCone, useClosure);
    5093:   }
    5094:   return(0);
    5095: }

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

    5100:   Not collective

    5102:   Input Parameters:
    5103: + dm         - The DM object
    5104: . useCone    - Flag for variable influence starting with the cone operation
    5105: - useClosure - Flag for variable influence using transitive closure

    5107:   Notes:
    5108: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
    5109: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
    5110: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

    5112:   Level: developer

    5114: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
    5115: @*/
    5116: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
    5117: {
    5118:   PetscInt       Nf;

    5123:   DMGetNumFields(dm, &Nf);
    5124:   if (!Nf) {
    5125:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    5126:   } else {
    5127:     DMSetAdjacency(dm, 0, useCone, useClosure);
    5128:   }
    5129:   return(0);
    5130: }

    5132: /* Complete labels that are being used for FEM BC */
    5133: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label)
    5134: {
    5135:   PetscObject    obj;
    5136:   PetscClassId   id;
    5137:   PetscInt       Nbd, bd;
    5138:   PetscBool      isFE      = PETSC_FALSE;
    5139:   PetscBool      duplicate = PETSC_FALSE;

    5143:   DMGetField(dm, field, NULL, &obj);
    5144:   PetscObjectGetClassId(obj, &id);
    5145:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
    5146:   if (isFE && label) {
    5147:     /* Only want to modify label once */
    5148:     PetscDSGetNumBoundary(ds, &Nbd);
    5149:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
    5150:       DMLabel l;

    5152:       PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5153:       duplicate = l == label ? PETSC_TRUE : PETSC_FALSE;
    5154:       if (duplicate) break;
    5155:     }
    5156:     if (!duplicate) {
    5157:       DM plex;

    5159:       DMConvert(dm, DMPLEX, &plex);
    5160:       if (plex) {DMPlexLabelComplete(plex, label);}
    5161:       DMDestroy(&plex);
    5162:     }
    5163:   }
    5164:   return(0);
    5165: }

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

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

    5184: /*@
    5185:   DMGetNumDS - Get the number of discrete systems in the DM

    5187:   Not collective

    5189:   Input Parameter:
    5190: . dm - The DM

    5192:   Output Parameter:
    5193: . Nds - The number of PetscDS objects

    5195:   Level: intermediate

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

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

    5211:   Logically collective on dm

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

    5216:   Level: intermediate

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

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

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

    5241:   Not collective

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

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

    5249:   Level: intermediate

    5251: .seealso: DMGetCellDS(), DMGetRegionDS()
    5252: @*/
    5253: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
    5254: {

    5260:   if (dm->Nds <= 0) {
    5261:     PetscDS ds;

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

    5271: /*@
    5272:   DMGetCellDS - Get the PetscDS defined on a given cell

    5274:   Not collective

    5276:   Input Parameters:
    5277: + dm    - The DM
    5278: - point - Cell for the DS

    5280:   Output Parameter:
    5281: . prob - The PetscDS defined on the given cell

    5283:   Level: developer

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

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

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

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

    5314:   Not collective

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

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

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

    5326:   Level: advanced

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

    5339:   for (s = 0; s < Nds; ++s) {
    5340:     if (dm->probs[s].label == label) {
    5341:       if (fields) *fields = dm->probs[s].fields;
    5342:       if (ds)     *ds     = dm->probs[s].ds;
    5343:       return(0);
    5344:     }
    5345:   }
    5346:   return(0);
    5347: }

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

    5352:   Collective on dm

    5354:   Input Parameters:
    5355: + dm     - The DM
    5356: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
    5357: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
    5358: - prob   - The PetscDS defined on the given cell

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

    5363:   Level: advanced

    5365: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
    5366: @*/
    5367: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
    5368: {
    5369:   PetscInt       Nds = dm->Nds, s;

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

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

    5401:   Not collective

    5403:   Input Parameters:
    5404: + dm  - The DM
    5405: - num - The region number, in [0, Nds)

    5407:   Output Parameters:
    5408: + label  - The region label, or NULL
    5409: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
    5410: - ds     - The PetscDS defined on the given region, or NULL

    5412:   Level: advanced

    5414: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
    5415: @*/
    5416: PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
    5417: {
    5418:   PetscInt       Nds;

    5423:   DMGetNumDS(dm, &Nds);
    5424:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5425:   if (label) {
    5427:     *label = dm->probs[num].label;
    5428:   }
    5429:   if (fields) {
    5431:     *fields = dm->probs[num].fields;
    5432:   }
    5433:   if (ds) {
    5435:     *ds = dm->probs[num].ds;
    5436:   }
    5437:   return(0);
    5438: }

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

    5443:   Not collective

    5445:   Input Parameters:
    5446: + dm     - The DM
    5447: . num    - The region number, in [0, Nds)
    5448: . label  - The region label, or NULL
    5449: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
    5450: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

    5452:   Level: advanced

    5454: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
    5455: @*/
    5456: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
    5457: {
    5458:   PetscInt       Nds;

    5464:   DMGetNumDS(dm, &Nds);
    5465:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5466:   PetscObjectReference((PetscObject) label);
    5467:   DMLabelDestroy(&dm->probs[num].label);
    5468:   dm->probs[num].label = label;
    5469:   if (fields) {
    5471:     PetscObjectReference((PetscObject) fields);
    5472:     ISDestroy(&dm->probs[num].fields);
    5473:     dm->probs[num].fields = fields;
    5474:   }
    5475:   if (ds) {
    5477:     PetscObjectReference((PetscObject) ds);
    5478:     PetscDSDestroy(&dm->probs[num].ds);
    5479:     dm->probs[num].ds = ds;
    5480:   }
    5481:   return(0);
    5482: }

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

    5487:   Not collective

    5489:   Input Parameters:
    5490: + dm  - The DM
    5491: - ds  - The PetscDS defined on the given region

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

    5496:   Level: advanced

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

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

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

    5519:   Collective on dm

    5521:   Input Parameter:
    5522: . dm - The DM

    5524:   Options Database Keys:
    5525: . -dm_petscds_view - View all the PetscDS objects in this DM

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

    5529:   Level: intermediate

    5531: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5532: @*/
    5533: PetscErrorCode DMCreateDS(DM dm)
    5534: {
    5535:   MPI_Comm       comm;
    5536:   PetscDS        dsDef;
    5537:   DMLabel       *labelSet;
    5538:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
    5539:   PetscBool      doSetup = PETSC_TRUE, flg;

    5544:   if (!dm->fields) return(0);
    5545:   PetscObjectGetComm((PetscObject) dm, &comm);
    5546:   DMGetCoordinateDim(dm, &dE);
    5547:   /* Determine how many regions we have */
    5548:   PetscMalloc1(Nf, &labelSet);
    5549:   Nl   = 0;
    5550:   Ndef = 0;
    5551:   for (f = 0; f < Nf; ++f) {
    5552:     DMLabel  label = dm->fields[f].label;
    5553:     PetscInt l;

    5555: #ifdef PETSC_HAVE_LIBCEED
    5556:     /* Move CEED context to discretizations */
    5557:     {
    5558:       PetscClassId id;

    5560:       PetscObjectGetClassId(dm->fields[f].disc, &id);
    5561:       if (id == PETSCFE_CLASSID) {
    5562:         Ceed ceed;

    5564:         DMGetCeed(dm, &ceed);
    5565:         PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed);
    5566:       }
    5567:     }
    5568: #endif
    5569:     if (!label) {++Ndef; continue;}
    5570:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
    5571:     if (l < Nl) continue;
    5572:     labelSet[Nl++] = label;
    5573:   }
    5574:   /* Create default DS if there are no labels to intersect with */
    5575:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5576:   if (!dsDef && Ndef && !Nl) {
    5577:     IS        fields;
    5578:     PetscInt *fld, nf;

    5580:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
    5581:     if (nf) {
    5582:       PetscMalloc1(nf, &fld);
    5583:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
    5584:       ISCreate(PETSC_COMM_SELF, &fields);
    5585:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
    5586:       ISSetType(fields, ISGENERAL);
    5587:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

    5589:       PetscDSCreate(PETSC_COMM_SELF, &dsDef);
    5590:       DMSetRegionDS(dm, NULL, fields, dsDef);
    5591:       PetscDSDestroy(&dsDef);
    5592:       ISDestroy(&fields);
    5593:     }
    5594:   }
    5595:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5596:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
    5597:   /* Intersect labels with default fields */
    5598:   if (Ndef && Nl) {
    5599:     DM              plex;
    5600:     DMLabel         cellLabel;
    5601:     IS              fieldIS, allcellIS, defcellIS = NULL;
    5602:     PetscInt       *fields;
    5603:     const PetscInt *cells;
    5604:     PetscInt        depth, nf = 0, n, c;

    5606:     DMConvert(dm, DMPLEX, &plex);
    5607:     DMPlexGetDepth(plex, &depth);
    5608:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
    5609:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
    5610:     for (l = 0; l < Nl; ++l) {
    5611:       DMLabel label = labelSet[l];
    5612:       IS      pointIS;

    5614:       ISDestroy(&defcellIS);
    5615:       DMLabelGetStratumIS(label, 1, &pointIS);
    5616:       ISDifference(allcellIS, pointIS, &defcellIS);
    5617:       ISDestroy(&pointIS);
    5618:     }
    5619:     ISDestroy(&allcellIS);

    5621:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
    5622:     ISGetLocalSize(defcellIS, &n);
    5623:     ISGetIndices(defcellIS, &cells);
    5624:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
    5625:     ISRestoreIndices(defcellIS, &cells);
    5626:     ISDestroy(&defcellIS);
    5627:     DMPlexLabelComplete(plex, cellLabel);

    5629:     PetscMalloc1(Ndef, &fields);
    5630:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
    5631:     ISCreate(PETSC_COMM_SELF, &fieldIS);
    5632:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
    5633:     ISSetType(fieldIS, ISGENERAL);
    5634:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

    5636:     PetscDSCreate(PETSC_COMM_SELF, &dsDef);
    5637:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
    5638:     DMLabelDestroy(&cellLabel);
    5639:     PetscDSSetCoordinateDimension(dsDef, dE);
    5640:     PetscDSDestroy(&dsDef);
    5641:     ISDestroy(&fieldIS);
    5642:     DMDestroy(&plex);
    5643:   }
    5644:   /* Create label DSes
    5645:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
    5646:   */
    5647:   /* TODO Should check that labels are disjoint */
    5648:   for (l = 0; l < Nl; ++l) {
    5649:     DMLabel   label = labelSet[l];
    5650:     PetscDS   ds;
    5651:     IS        fields;
    5652:     PetscInt *fld, nf;

    5654:     PetscDSCreate(PETSC_COMM_SELF, &ds);
    5655:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
    5656:     PetscMalloc1(nf, &fld);
    5657:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
    5658:     ISCreate(PETSC_COMM_SELF, &fields);
    5659:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
    5660:     ISSetType(fields, ISGENERAL);
    5661:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
    5662:     DMSetRegionDS(dm, label, fields, ds);
    5663:     ISDestroy(&fields);
    5664:     PetscDSSetCoordinateDimension(ds, dE);
    5665:     {
    5666:       DMPolytopeType ct;
    5667:       PetscInt       lStart, lEnd;
    5668:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

    5670:       DMLabelGetBounds(label, &lStart, &lEnd);
    5671:       if (lStart >= 0) {
    5672:         DMPlexGetCellType(dm, lStart, &ct);
    5673:         switch (ct) {
    5674:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
    5675:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
    5676:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
    5677:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
    5678:             isHybridLocal = PETSC_TRUE;break;
    5679:           default: break;
    5680:         }
    5681:       }
    5682:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
    5683:       PetscDSSetHybrid(ds, isHybrid);
    5684:     }
    5685:     PetscDSDestroy(&ds);
    5686:   }
    5687:   PetscFree(labelSet);
    5688:   /* Set fields in DSes */
    5689:   for (s = 0; s < dm->Nds; ++s) {
    5690:     PetscDS         ds     = dm->probs[s].ds;
    5691:     IS              fields = dm->probs[s].fields;
    5692:     const PetscInt *fld;
    5693:     PetscInt        nf;

    5695:     ISGetLocalSize(fields, &nf);
    5696:     ISGetIndices(fields, &fld);
    5697:     for (f = 0; f < nf; ++f) {
    5698:       PetscObject  disc  = dm->fields[fld[f]].disc;
    5699:       PetscBool    isHybrid;
    5700:       PetscClassId id;

    5702:       PetscDSGetHybrid(ds, &isHybrid);
    5703:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
    5704:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
    5705:       PetscDSSetDiscretization(ds, f, disc);
    5706:       /* We allow people to have placeholder fields and construct the Section by hand */
    5707:       PetscObjectGetClassId(disc, &id);
    5708:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
    5709:     }
    5710:     ISRestoreIndices(fields, &fld);
    5711:   }
    5712:   /* Allow k-jet tabulation */
    5713:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
    5714:   if (flg) {
    5715:     for (s = 0; s < dm->Nds; ++s) {
    5716:       PetscDS  ds = dm->probs[s].ds;
    5717:       PetscInt Nf, f;

    5719:       PetscDSGetNumFields(ds, &Nf);
    5720:       for (f = 0; f < Nf; ++f) {PetscDSSetJetDegree(ds, f, k);}
    5721:     }
    5722:   }
    5723:   /* Setup DSes */
    5724:   if (doSetup) {
    5725:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
    5726:   }
    5727:   return(0);
    5728: }

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

    5733:   Collective on DM

    5735:   Input Parameters:
    5736: + dm   - The DM
    5737: - time - The time

    5739:   Output Parameters:
    5740: + u    - The vector will be filled with exact solution values, or NULL
    5741: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

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

    5745:   Level: developer

    5747: .seealso: PetscDSSetExactSolution()
    5748: @*/
    5749: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
    5750: {
    5751:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
    5752:   void            **ectxs;
    5753:   PetscInt          Nf, Nds, s;
    5754:   PetscErrorCode    ierr;

    5760:   DMGetNumFields(dm, &Nf);
    5761:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
    5762:   DMGetNumDS(dm, &Nds);
    5763:   for (s = 0; s < Nds; ++s) {
    5764:     PetscDS         ds;
    5765:     DMLabel         label;
    5766:     IS              fieldIS;
    5767:     const PetscInt *fields, id = 1;
    5768:     PetscInt        dsNf, f;

    5770:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    5771:     PetscDSGetNumFields(ds, &dsNf);
    5772:     ISGetIndices(fieldIS, &fields);
    5773:     PetscArrayzero(exacts, Nf);
    5774:     PetscArrayzero(ectxs, Nf);
    5775:     if (u) {
    5776:       for (f = 0; f < dsNf; ++f) {
    5777:         const PetscInt field = fields[f];
    5778:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
    5779:       }
    5780:       ISRestoreIndices(fieldIS, &fields);
    5781:       if (label) {
    5782:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
    5783:       } else {
    5784:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
    5785:       }
    5786:     }
    5787:     if (u_t) {
    5788:       PetscArrayzero(exacts, Nf);
    5789:       PetscArrayzero(ectxs, Nf);
    5790:       for (f = 0; f < dsNf; ++f) {
    5791:         const PetscInt field = fields[f];
    5792:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
    5793:       }
    5794:       ISRestoreIndices(fieldIS, &fields);
    5795:       if (label) {
    5796:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5797:       } else {
    5798:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5799:       }
    5800:     }
    5801:   }
    5802:   if (u) {
    5803:     PetscObjectSetName((PetscObject) u, "Exact Solution");
    5804:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
    5805:   }
    5806:   if (u_t) {
    5807:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
    5808:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
    5809:   }
    5810:   PetscFree2(exacts, ectxs);
    5811:   return(0);
    5812: }

    5814: PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
    5815: {
    5816:   PetscDS        dsNew;
    5817:   DSBoundary     b;
    5818:   PetscInt       cdim, Nf, f;
    5819:   PetscBool      isHybrid;
    5820:   void          *ctx;

    5824:   PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew);
    5825:   PetscDSCopyConstants(ds, dsNew);
    5826:   PetscDSCopyExactSolutions(ds, dsNew);
    5827:   PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew);
    5828:   PetscDSCopyEquations(ds, dsNew);
    5829:   PetscDSGetNumFields(ds, &Nf);
    5830:   for (f = 0; f < Nf; ++f) {
    5831:     PetscDSGetContext(ds, f, &ctx);
    5832:     PetscDSSetContext(dsNew, f, ctx);
    5833:   }
    5834:   if (Nf) {
    5835:     PetscDSGetCoordinateDimension(ds, &cdim);
    5836:     PetscDSSetCoordinateDimension(dsNew, cdim);
    5837:   }
    5838:   PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew);
    5839:   for (b = dsNew->boundary; b; b = b->next) {
    5840:     DMGetLabel(dm, b->lname, &b->label);
    5841:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    5842:     //if (!b->label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
    5843:   }
    5844:   PetscDSGetHybrid(ds, &isHybrid);
    5845:   PetscDSSetHybrid(dsNew, isHybrid);

    5847:   DMSetRegionDS(dm, label, fields, dsNew);
    5848:   PetscDSDestroy(&dsNew);
    5849:   return(0);
    5850: }

    5852: /*@
    5853:   DMCopyDS - Copy the discrete systems for the DM into another DM

    5855:   Collective on dm

    5857:   Input Parameter:
    5858: . dm - The DM

    5860:   Output Parameter:
    5861: . newdm - The DM

    5863:   Level: advanced

    5865: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5866: @*/
    5867: PetscErrorCode DMCopyDS(DM dm, DM newdm)
    5868: {
    5869:   PetscInt       Nds, s;

    5873:   if (dm == newdm) return(0);
    5874:   DMGetNumDS(dm, &Nds);
    5875:   DMClearDS(newdm);
    5876:   for (s = 0; s < Nds; ++s) {
    5877:     DMLabel  label;
    5878:     IS       fields;
    5879:     PetscDS  ds, newds;
    5880:     PetscInt Nbd, bd;

    5882:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
    5883:     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
    5884:     DMTransferDS_Internal(newdm, label, fields, ds);
    5885:     /* Commplete new labels in the new DS */
    5886:     DMGetRegionDS(newdm, label, NULL, &newds);
    5887:     PetscDSGetNumBoundary(newds, &Nbd);
    5888:     for (bd = 0; bd < Nbd; ++bd) {
    5889:       PetscWeakForm wf;
    5890:       DMLabel       label;
    5891:       PetscInt      field;

    5893:       PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL);
    5894:       DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label);
    5895:       PetscWeakFormReplaceLabel(wf, label);
    5896:     }
    5897:   }
    5898:   return(0);
    5899: }

    5901: /*@
    5902:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

    5904:   Collective on dm

    5906:   Input Parameter:
    5907: . dm - The DM

    5909:   Output Parameter:
    5910: . newdm - The DM

    5912:   Level: advanced

    5914: .seealso: DMCopyFields(), DMCopyDS()
    5915: @*/
    5916: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
    5917: {

    5921:   DMCopyFields(dm, newdm);
    5922:   DMCopyDS(dm, newdm);
    5923:   return(0);
    5924: }

    5926: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
    5927: {
    5928:   DM dm_coord,dmc_coord;
    5930:   Vec coords,ccoords;
    5931:   Mat inject;
    5933:   DMGetCoordinateDM(dm,&dm_coord);
    5934:   DMGetCoordinateDM(dmc,&dmc_coord);
    5935:   DMGetCoordinates(dm,&coords);
    5936:   DMGetCoordinates(dmc,&ccoords);
    5937:   if (coords && !ccoords) {
    5938:     DMCreateGlobalVector(dmc_coord,&ccoords);
    5939:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5940:     DMCreateInjection(dmc_coord,dm_coord,&inject);
    5941:     MatRestrict(inject,coords,ccoords);
    5942:     MatDestroy(&inject);
    5943:     DMSetCoordinates(dmc,ccoords);
    5944:     VecDestroy(&ccoords);
    5945:   }
    5946:   return(0);
    5947: }

    5949: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
    5950: {
    5951:   DM dm_coord,subdm_coord;
    5953:   Vec coords,ccoords,clcoords;
    5954:   VecScatter *scat_i,*scat_g;
    5956:   DMGetCoordinateDM(dm,&dm_coord);
    5957:   DMGetCoordinateDM(subdm,&subdm_coord);
    5958:   DMGetCoordinates(dm,&coords);
    5959:   DMGetCoordinates(subdm,&ccoords);
    5960:   if (coords && !ccoords) {
    5961:     DMCreateGlobalVector(subdm_coord,&ccoords);
    5962:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5963:     DMCreateLocalVector(subdm_coord,&clcoords);
    5964:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
    5965:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
    5966:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5967:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5968:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5969:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5970:     DMSetCoordinates(subdm,ccoords);
    5971:     DMSetCoordinatesLocal(subdm,clcoords);
    5972:     VecScatterDestroy(&scat_i[0]);
    5973:     VecScatterDestroy(&scat_g[0]);
    5974:     VecDestroy(&ccoords);
    5975:     VecDestroy(&clcoords);
    5976:     PetscFree(scat_i);
    5977:     PetscFree(scat_g);
    5978:   }
    5979:   return(0);
    5980: }

    5982: /*@
    5983:   DMGetDimension - Return the topological dimension of the DM

    5985:   Not collective

    5987:   Input Parameter:
    5988: . dm - The DM

    5990:   Output Parameter:
    5991: . dim - The topological dimension

    5993:   Level: beginner

    5995: .seealso: DMSetDimension(), DMCreate()
    5996: @*/
    5997: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
    5998: {
    6002:   *dim = dm->dim;
    6003:   return(0);
    6004: }

    6006: /*@
    6007:   DMSetDimension - Set the topological dimension of the DM

    6009:   Collective on dm

    6011:   Input Parameters:
    6012: + dm - The DM
    6013: - dim - The topological dimension

    6015:   Level: beginner

    6017: .seealso: DMGetDimension(), DMCreate()
    6018: @*/
    6019: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
    6020: {
    6021:   PetscDS        ds;
    6022:   PetscInt       Nds, n;

    6028:   dm->dim = dim;
    6029:   if (dm->dim >= 0) {
    6030:     DMGetNumDS(dm, &Nds);
    6031:     for (n = 0; n < Nds; ++n) {
    6032:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
    6033:       if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dim);}
    6034:     }
    6035:   }
    6036:   return(0);
    6037: }

    6039: /*@
    6040:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

    6042:   Collective on dm

    6044:   Input Parameters:
    6045: + dm - the DM
    6046: - dim - the dimension

    6048:   Output Parameters:
    6049: + pStart - The first point of the given dimension
    6050: - pEnd - The first point following points of the given dimension

    6052:   Note:
    6053:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
    6054:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
    6055:   then the interval is empty.

    6057:   Level: intermediate

    6059: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
    6060: @*/
    6061: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
    6062: {
    6063:   PetscInt       d;

    6068:   DMGetDimension(dm, &d);
    6069:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
    6070:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
    6071:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
    6072:   return(0);
    6073: }

    6075: /*@
    6076:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

    6078:   Collective on dm

    6080:   Input Parameters:
    6081: + dm - the DM
    6082: - c - coordinate vector

    6084:   Notes:
    6085:   The coordinates do include those for ghost points, which are in the local vector.

    6087:   The vector c should be destroyed by the caller.

    6089:   Level: intermediate

    6091: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    6092: @*/
    6093: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
    6094: {

    6100:   PetscObjectReference((PetscObject) c);
    6101:   VecDestroy(&dm->coordinates);
    6102:   dm->coordinates = c;
    6103:   VecDestroy(&dm->coordinatesLocal);
    6104:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
    6105:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
    6106:   return(0);
    6107: }

    6109: /*@
    6110:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

    6112:   Not collective

    6114:    Input Parameters:
    6115: +  dm - the DM
    6116: -  c - coordinate vector

    6118:   Notes:
    6119:   The coordinates of ghost points can be set using DMSetCoordinates()
    6120:   followed by DMGetCoordinatesLocal(). This is intended to enable the
    6121:   setting of ghost coordinates outside of the domain.

    6123:   The vector c should be destroyed by the caller.

    6125:   Level: intermediate

    6127: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
    6128: @*/
    6129: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
    6130: {

    6136:   PetscObjectReference((PetscObject) c);
    6137:   VecDestroy(&dm->coordinatesLocal);

    6139:   dm->coordinatesLocal = c;

    6141:   VecDestroy(&dm->coordinates);
    6142:   return(0);
    6143: }

    6145: /*@
    6146:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

    6148:   Collective on dm

    6150:   Input Parameter:
    6151: . dm - the DM

    6153:   Output Parameter:
    6154: . c - global coordinate vector

    6156:   Note:
    6157:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
    6158:   destroyed the array will no longer be valid.

    6160:   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).

    6162:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6163:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6165:   Level: intermediate

    6167: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    6168: @*/
    6169: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
    6170: {

    6176:   if (!dm->coordinates && dm->coordinatesLocal) {
    6177:     DM        cdm = NULL;
    6178:     PetscBool localized;

    6180:     DMGetCoordinateDM(dm, &cdm);
    6181:     DMCreateGlobalVector(cdm, &dm->coordinates);
    6182:     DMGetCoordinatesLocalized(dm, &localized);
    6183:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
    6184:     if (localized) {
    6185:       PetscInt cdim;

    6187:       DMGetCoordinateDim(dm, &cdim);
    6188:       VecSetBlockSize(dm->coordinates, cdim);
    6189:     }
    6190:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
    6191:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6192:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6193:   }
    6194:   *c = dm->coordinates;
    6195:   return(0);
    6196: }

    6198: /*@
    6199:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

    6201:   Collective on dm

    6203:   Input Parameter:
    6204: . dm - the DM

    6206:   Level: advanced

    6208: .seealso: DMGetCoordinatesLocalNoncollective()
    6209: @*/
    6210: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
    6211: {

    6216:   if (!dm->coordinatesLocal && dm->coordinates) {
    6217:     DM        cdm = NULL;
    6218:     PetscBool localized;

    6220:     DMGetCoordinateDM(dm, &cdm);
    6221:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
    6222:     DMGetCoordinatesLocalized(dm, &localized);
    6223:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
    6224:     if (localized) {
    6225:       PetscInt cdim;

    6227:       DMGetCoordinateDim(dm, &cdim);
    6228:       VecSetBlockSize(dm->coordinates, cdim);
    6229:     }
    6230:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
    6231:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6232:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6233:   }
    6234:   return(0);
    6235: }

    6237: /*@
    6238:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

    6240:   Collective on dm

    6242:   Input Parameter:
    6243: . dm - the DM

    6245:   Output Parameter:
    6246: . c - coordinate vector

    6248:   Note:
    6249:   This is a borrowed reference, so the user should NOT destroy this vector

    6251:   Each process has the local and ghost coordinates

    6253:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6254:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6256:   Level: intermediate

    6258: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
    6259: @*/
    6260: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
    6261: {

    6267:   DMGetCoordinatesLocalSetUp(dm);
    6268:   *c = dm->coordinatesLocal;
    6269:   return(0);
    6270: }

    6272: /*@
    6273:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

    6275:   Not collective

    6277:   Input Parameter:
    6278: . dm - the DM

    6280:   Output Parameter:
    6281: . c - coordinate vector

    6283:   Level: advanced

    6285: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6286: @*/
    6287: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
    6288: {
    6292:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
    6293:   *c = dm->coordinatesLocal;
    6294:   return(0);
    6295: }

    6297: /*@
    6298:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

    6300:   Not collective

    6302:   Input Parameters:
    6303: + dm - the DM
    6304: - p - the IS of points whose coordinates will be returned

    6306:   Output Parameters:
    6307: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
    6308: - pCoord - the Vec with coordinates of points in p

    6310:   Note:
    6311:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

    6313:   This creates a new vector, so the user SHOULD destroy this vector

    6315:   Each process has the local and ghost coordinates

    6317:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6318:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6320:   Level: advanced

    6322: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6323: @*/
    6324: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
    6325: {
    6326:   PetscSection        cs, newcs;
    6327:   Vec                 coords;
    6328:   const PetscScalar   *arr;
    6329:   PetscScalar         *newarr=NULL;
    6330:   PetscInt            n;
    6331:   PetscErrorCode      ierr;

    6338:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
    6339:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
    6340:   cs = dm->coordinateDM->localSection;
    6341:   coords = dm->coordinatesLocal;
    6342:   VecGetArrayRead(coords, &arr);
    6343:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
    6344:   VecRestoreArrayRead(coords, &arr);
    6345:   if (pCoord) {
    6346:     PetscSectionGetStorageSize(newcs, &n);
    6347:     /* set array in two steps to mimic PETSC_OWN_POINTER */
    6348:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
    6349:     VecReplaceArray(*pCoord, newarr);
    6350:   } else {
    6351:     PetscFree(newarr);
    6352:   }
    6353:   if (pCoordSection) {*pCoordSection = newcs;}
    6354:   else               {PetscSectionDestroy(&newcs);}
    6355:   return(0);
    6356: }

    6358: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
    6359: {

    6365:   if (!dm->coordinateField) {
    6366:     if (dm->ops->createcoordinatefield) {
    6367:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
    6368:     }
    6369:   }
    6370:   *field = dm->coordinateField;
    6371:   return(0);
    6372: }

    6374: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
    6375: {

    6381:   PetscObjectReference((PetscObject)field);
    6382:   DMFieldDestroy(&dm->coordinateField);
    6383:   dm->coordinateField = field;
    6384:   return(0);
    6385: }

    6387: /*@
    6388:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6390:   Collective on dm

    6392:   Input Parameter:
    6393: . dm - the DM

    6395:   Output Parameter:
    6396: . cdm - coordinate DM

    6398:   Level: intermediate

    6400: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6401: @*/
    6402: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
    6403: {

    6409:   if (!dm->coordinateDM) {
    6410:     DM cdm;

    6412:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
    6413:     (*dm->ops->createcoordinatedm)(dm, &cdm);
    6414:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
    6415:      * until the call to CreateCoordinateDM) */
    6416:     DMDestroy(&dm->coordinateDM);
    6417:     dm->coordinateDM = cdm;
    6418:   }
    6419:   *cdm = dm->coordinateDM;
    6420:   return(0);
    6421: }

    6423: /*@
    6424:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6426:   Logically Collective on dm

    6428:   Input Parameters:
    6429: + dm - the DM
    6430: - cdm - coordinate DM

    6432:   Level: intermediate

    6434: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6435: @*/
    6436: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
    6437: {

    6443:   PetscObjectReference((PetscObject)cdm);
    6444:   DMDestroy(&dm->coordinateDM);
    6445:   dm->coordinateDM = cdm;
    6446:   return(0);
    6447: }

    6449: /*@
    6450:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

    6452:   Not Collective

    6454:   Input Parameter:
    6455: . dm - The DM object

    6457:   Output Parameter:
    6458: . dim - The embedding dimension

    6460:   Level: intermediate

    6462: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6463: @*/
    6464: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
    6465: {
    6469:   if (dm->dimEmbed == PETSC_DEFAULT) {
    6470:     dm->dimEmbed = dm->dim;
    6471:   }
    6472:   *dim = dm->dimEmbed;
    6473:   return(0);
    6474: }

    6476: /*@
    6477:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

    6479:   Not Collective

    6481:   Input Parameters:
    6482: + dm  - The DM object
    6483: - dim - The embedding dimension

    6485:   Level: intermediate

    6487: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6488: @*/
    6489: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
    6490: {
    6491:   PetscDS        ds;
    6492:   PetscInt       Nds, n;

    6497:   dm->dimEmbed = dim;
    6498:   if (dm->dim >= 0) {
    6499:     DMGetNumDS(dm, &Nds);
    6500:     for (n = 0; n < Nds; ++n) {
    6501:       DMGetRegionNumDS(dm, n, NULL, NULL, &ds);
    6502:       PetscDSSetCoordinateDimension(ds, dim);
    6503:     }
    6504:   }
    6505:   return(0);
    6506: }

    6508: /*@
    6509:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

    6511:   Collective on dm

    6513:   Input Parameter:
    6514: . dm - The DM object

    6516:   Output Parameter:
    6517: . section - The PetscSection object

    6519:   Level: intermediate

    6521: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6522: @*/
    6523: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
    6524: {
    6525:   DM             cdm;

    6531:   DMGetCoordinateDM(dm, &cdm);
    6532:   DMGetLocalSection(cdm, section);
    6533:   return(0);
    6534: }

    6536: /*@
    6537:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

    6539:   Not Collective

    6541:   Input Parameters:
    6542: + dm      - The DM object
    6543: . dim     - The embedding dimension, or PETSC_DETERMINE
    6544: - section - The PetscSection object

    6546:   Level: intermediate

    6548: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6549: @*/
    6550: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
    6551: {
    6552:   DM             cdm;

    6558:   DMGetCoordinateDM(dm, &cdm);
    6559:   DMSetLocalSection(cdm, section);
    6560:   if (dim == PETSC_DETERMINE) {
    6561:     PetscInt d = PETSC_DEFAULT;
    6562:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

    6564:     PetscSectionGetChart(section, &pStart, &pEnd);
    6565:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
    6566:     pStart = PetscMax(vStart, pStart);
    6567:     pEnd   = PetscMin(vEnd, pEnd);
    6568:     for (v = pStart; v < pEnd; ++v) {
    6569:       PetscSectionGetDof(section, v, &dd);
    6570:       if (dd) {d = dd; break;}
    6571:     }
    6572:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
    6573:   }
    6574:   return(0);
    6575: }

    6577: /*@
    6578:   DMProjectCoordinates - Project coordinates to a different space

    6580:   Input Parameters:
    6581: + dm      - The DM object
    6582: - disc    - The new coordinate discretization

    6584:   Level: intermediate

    6586: .seealso: DMGetCoordinateField()
    6587: @*/
    6588: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
    6589: {
    6590:   PetscObject    discOld;
    6591:   PetscClassId   classid;
    6592:   DM             cdmOld,cdmNew;
    6593:   Vec            coordsOld,coordsNew;
    6594:   Mat            matInterp;

    6601:   DMGetCoordinateDM(dm, &cdmOld);
    6602:   /* Check current discretization is compatible */
    6603:   DMGetField(cdmOld, 0, NULL, &discOld);
    6604:   PetscObjectGetClassId(discOld, &classid);
    6605:   if (classid != PETSCFE_CLASSID) {
    6606:     if (classid == PETSC_CONTAINER_CLASSID) {
    6607:       PetscFE        feLinear;
    6608:       DMPolytopeType ct;
    6609:       PetscInt       dim, dE, cStart;
    6610:       PetscBool      simplex;

    6612:       /* Assume linear vertex coordinates */
    6613:       DMGetDimension(dm, &dim);
    6614:       DMGetCoordinateDim(dm, &dE);
    6615:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
    6616:       DMPlexGetCellType(dm, cStart, &ct);
    6617:       switch (ct) {
    6618:         case DM_POLYTOPE_TRI_PRISM:
    6619:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
    6620:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
    6621:         default: break;
    6622:       }
    6623:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
    6624:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
    6625:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
    6626:       PetscFEDestroy(&feLinear);
    6627:       DMCreateDS(cdmOld);
    6628:     } else {
    6629:       const char *discname;

    6631:       PetscObjectGetType(discOld, &discname);
    6632:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
    6633:     }
    6634:   }
    6635:   /* Make a fresh clone of the coordinate DM */
    6636:   DMClone(cdmOld, &cdmNew);
    6637:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
    6638:   DMCreateDS(cdmNew);
    6639:   /* Project the coordinate vector from old to new space  */
    6640:   DMGetCoordinates(dm, &coordsOld);
    6641:   DMCreateGlobalVector(cdmNew, &coordsNew);
    6642:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
    6643:   MatInterpolate(matInterp, coordsOld, coordsNew);
    6644:   MatDestroy(&matInterp);
    6645:   /* Set new coordinate structures */
    6646:   DMSetCoordinateField(dm, NULL);
    6647:   DMSetCoordinateDM(dm, cdmNew);
    6648:   DMSetCoordinates(dm, coordsNew);
    6649:   VecDestroy(&coordsNew);
    6650:   DMDestroy(&cdmNew);
    6651:   return(0);
    6652: }

    6654: /*@C
    6655:   DMGetPeriodicity - Get the description of mesh periodicity

    6657:   Input Parameter:
    6658: . dm      - The DM object

    6660:   Output Parameters:
    6661: + per     - Whether the DM is periodic or not
    6662: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
    6663: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6664: - bd      - This describes the type of periodicity in each topological dimension

    6666:   Level: developer

    6668: .seealso: DMGetPeriodicity()
    6669: @*/
    6670: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
    6671: {
    6674:   if (per)     *per     = dm->periodic;
    6675:   if (L)       *L       = dm->L;
    6676:   if (maxCell) *maxCell = dm->maxCell;
    6677:   if (bd)      *bd      = dm->bdtype;
    6678:   return(0);
    6679: }

    6681: /*@C
    6682:   DMSetPeriodicity - Set the description of mesh periodicity

    6684:   Input Parameters:
    6685: + dm      - The DM object
    6686: . per     - Whether the DM is periodic or not.
    6687: . 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.
    6688: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6689: - bd      - This describes the type of periodicity in each topological dimension

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

    6693:   Level: developer

    6695: .seealso: DMGetPeriodicity()
    6696: @*/
    6697: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
    6698: {
    6699:   PetscInt       dim, d;

    6708:   DMGetDimension(dm, &dim);
    6709:   if (maxCell) {
    6710:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
    6711:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
    6712:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
    6713:     PetscFree(dm->maxCell);
    6714:   }

    6716:   if (L) {
    6717:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
    6718:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
    6719:   }
    6720:   if (bd) {
    6721:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
    6722:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
    6723:   }
    6724:   dm->periodic = per;
    6725:   return(0);
    6726: }

    6728: /*@
    6729:   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.

    6731:   Input Parameters:
    6732: + dm     - The DM
    6733: . in     - The input coordinate point (dim numbers)
    6734: - endpoint - Include the endpoint L_i

    6736:   Output Parameter:
    6737: . out - The localized coordinate point

    6739:   Level: developer

    6741: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6742: @*/
    6743: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
    6744: {
    6745:   PetscInt       dim, d;

    6749:   DMGetCoordinateDim(dm, &dim);
    6750:   if (!dm->maxCell) {
    6751:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6752:   } else {
    6753:     if (endpoint) {
    6754:       for (d = 0; d < dim; ++d) {
    6755:         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)) {
    6756:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
    6757:         } else {
    6758:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6759:         }
    6760:       }
    6761:     } else {
    6762:       for (d = 0; d < dim; ++d) {
    6763:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6764:       }
    6765:     }
    6766:   }
    6767:   return(0);
    6768: }

    6770: /*
    6771:   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.

    6773:   Input Parameters:
    6774: + dm     - The DM
    6775: . dim    - The spatial dimension
    6776: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6777: - in     - The input coordinate point (dim numbers)

    6779:   Output Parameter:
    6780: . out - The localized coordinate point

    6782:   Level: developer

    6784:   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

    6786: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6787: */
    6788: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6789: {
    6790:   PetscInt d;

    6793:   if (!dm->maxCell) {
    6794:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6795:   } else {
    6796:     for (d = 0; d < dim; ++d) {
    6797:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
    6798:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6799:       } else {
    6800:         out[d] = in[d];
    6801:       }
    6802:     }
    6803:   }
    6804:   return(0);
    6805: }

    6807: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
    6808: {
    6809:   PetscInt d;

    6812:   if (!dm->maxCell) {
    6813:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6814:   } else {
    6815:     for (d = 0; d < dim; ++d) {
    6816:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
    6817:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6818:       } else {
    6819:         out[d] = in[d];
    6820:       }
    6821:     }
    6822:   }
    6823:   return(0);
    6824: }

    6826: /*
    6827:   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.

    6829:   Input Parameters:
    6830: + dm     - The DM
    6831: . dim    - The spatial dimension
    6832: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6833: . in     - The input coordinate delta (dim numbers)
    6834: - out    - The input coordinate point (dim numbers)

    6836:   Output Parameter:
    6837: . out    - The localized coordinate in + out

    6839:   Level: developer

    6841:   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

    6843: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
    6844: */
    6845: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6846: {
    6847:   PetscInt d;

    6850:   if (!dm->maxCell) {
    6851:     for (d = 0; d < dim; ++d) out[d] += in[d];
    6852:   } else {
    6853:     for (d = 0; d < dim; ++d) {
    6854:       const PetscReal maxC = dm->maxCell[d];

    6856:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
    6857:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

    6859:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
    6860:           SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "%D-Coordinate %g more than %g away from anchor %g", d, (double) PetscRealPart(in[d]), (double) maxC, (double) PetscRealPart(anchor[d]));
    6861:         out[d] += newCoord;
    6862:       } else {
    6863:         out[d] += in[d];
    6864:       }
    6865:     }
    6866:   }
    6867:   return(0);
    6868: }

    6870: /*@
    6871:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

    6873:   Not collective

    6875:   Input Parameter:
    6876: . dm - The DM

    6878:   Output Parameter:
    6879:   areLocalized - True if localized

    6881:   Level: developer

    6883: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
    6884: @*/
    6885: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
    6886: {
    6887:   DM             cdm;
    6888:   PetscSection   coordSection;
    6889:   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
    6890:   PetscBool      isPlex, alreadyLocalized;

    6896:   *areLocalized = PETSC_FALSE;

    6898:   /* We need some generic way of refering to cells/vertices */
    6899:   DMGetCoordinateDM(dm, &cdm);
    6900:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
    6901:   if (!isPlex) return(0);
    6902:   DMPlexGetDepth(cdm, &depth);
    6903:   if (!depth) return(0);

    6905:   DMGetCoordinateSection(dm, &coordSection);
    6906:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
    6907:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
    6908:   alreadyLocalized = PETSC_FALSE;
    6909:   for (c = cStart; c < cEnd; ++c) {
    6910:     if (c < sStart || c >= sEnd) continue;
    6911:     PetscSectionGetDof(coordSection, c, &dof);
    6912:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
    6913:   }
    6914:   *areLocalized = alreadyLocalized;
    6915:   return(0);
    6916: }

    6918: /*@
    6919:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

    6921:   Collective on dm

    6923:   Input Parameter:
    6924: . dm - The DM

    6926:   Output Parameter:
    6927:   areLocalized - True if localized

    6929:   Level: developer

    6931: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
    6932: @*/
    6933: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
    6934: {
    6935:   PetscBool      localized;

    6941:   DMGetCoordinatesLocalizedLocal(dm,&localized);
    6942:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
    6943:   return(0);
    6944: }

    6946: /*@
    6947:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

    6949:   Collective on dm

    6951:   Input Parameter:
    6952: . dm - The DM

    6954:   Level: developer

    6956: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
    6957: @*/
    6958: PetscErrorCode DMLocalizeCoordinates(DM dm)
    6959: {
    6960:   DM             cdm;
    6961:   PetscSection   coordSection, cSection;
    6962:   Vec            coordinates,  cVec;
    6963:   PetscScalar   *coords, *coords2, *anchor, *localized;
    6964:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
    6965:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
    6966:   PetscInt       maxHeight = 0, h;
    6967:   PetscInt       *pStart = NULL, *pEnd = NULL;

    6972:   if (!dm->periodic) return(0);
    6973:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
    6974:   if (alreadyLocalized) return(0);

    6976:   /* We need some generic way of refering to cells/vertices */
    6977:   DMGetCoordinateDM(dm, &cdm);
    6978:   {
    6979:     PetscBool isplex;

    6981:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
    6982:     if (isplex) {
    6983:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
    6984:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
    6985:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6986:       pEnd = &pStart[maxHeight + 1];
    6987:       newStart = vStart;
    6988:       newEnd   = vEnd;
    6989:       for (h = 0; h <= maxHeight; h++) {
    6990:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
    6991:         newStart = PetscMin(newStart,pStart[h]);
    6992:         newEnd   = PetscMax(newEnd,pEnd[h]);
    6993:       }
    6994:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
    6995:   }
    6996:   DMGetCoordinatesLocal(dm, &coordinates);
    6997:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
    6998:   DMGetCoordinateSection(dm, &coordSection);
    6999:   VecGetBlockSize(coordinates, &bs);
    7000:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

    7002:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
    7003:   PetscSectionSetNumFields(cSection, 1);
    7004:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
    7005:   PetscSectionSetFieldComponents(cSection, 0, Nc);
    7006:   PetscSectionSetChart(cSection, newStart, newEnd);

    7008:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    7009:   localized = &anchor[bs];
    7010:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
    7011:   for (h = 0; h <= maxHeight; h++) {
    7012:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    7014:     for (c = cStart; c < cEnd; ++c) {
    7015:       PetscScalar *cellCoords = NULL;
    7016:       PetscInt     b;

    7018:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
    7019:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    7020:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    7021:       for (d = 0; d < dof/bs; ++d) {
    7022:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
    7023:         for (b = 0; b < bs; b++) {
    7024:           if (cellCoords[d*bs + b] != localized[b]) break;
    7025:         }
    7026:         if (b < bs) break;
    7027:       }
    7028:       if (d < dof/bs) {
    7029:         if (c >= sStart && c < sEnd) {
    7030:           PetscInt cdof;

    7032:           PetscSectionGetDof(coordSection, c, &cdof);
    7033:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
    7034:         }
    7035:         PetscSectionSetDof(cSection, c, dof);
    7036:         PetscSectionSetFieldDof(cSection, c, 0, dof);
    7037:       }
    7038:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    7039:     }
    7040:   }
    7041:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
    7042:   if (alreadyLocalizedGlobal) {
    7043:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    7044:     PetscSectionDestroy(&cSection);
    7045:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    7046:     return(0);
    7047:   }
    7048:   for (v = vStart; v < vEnd; ++v) {
    7049:     PetscSectionGetDof(coordSection, v, &dof);
    7050:     PetscSectionSetDof(cSection, v, dof);
    7051:     PetscSectionSetFieldDof(cSection, v, 0, dof);
    7052:   }
    7053:   PetscSectionSetUp(cSection);
    7054:   PetscSectionGetStorageSize(cSection, &coordSize);
    7055:   VecCreate(PETSC_COMM_SELF, &cVec);
    7056:   PetscObjectSetName((PetscObject)cVec,"coordinates");
    7057:   VecSetBlockSize(cVec, bs);
    7058:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
    7059:   VecSetType(cVec, VECSTANDARD);
    7060:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
    7061:   VecGetArray(cVec, &coords2);
    7062:   for (v = vStart; v < vEnd; ++v) {
    7063:     PetscSectionGetDof(coordSection, v, &dof);
    7064:     PetscSectionGetOffset(coordSection, v, &off);
    7065:     PetscSectionGetOffset(cSection,     v, &off2);
    7066:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
    7067:   }
    7068:   for (h = 0; h <= maxHeight; h++) {
    7069:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    7071:     for (c = cStart; c < cEnd; ++c) {
    7072:       PetscScalar *cellCoords = NULL;
    7073:       PetscInt     b, cdof;

    7075:       PetscSectionGetDof(cSection,c,&cdof);
    7076:       if (!cdof) continue;
    7077:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    7078:       PetscSectionGetOffset(cSection, c, &off2);
    7079:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    7080:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
    7081:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    7082:     }
    7083:   }
    7084:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    7085:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    7086:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
    7087:   VecRestoreArray(cVec, &coords2);
    7088:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
    7089:   DMSetCoordinatesLocal(dm, cVec);
    7090:   VecDestroy(&cVec);
    7091:   PetscSectionDestroy(&cSection);
    7092:   return(0);
    7093: }

    7095: /*@
    7096:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

    7098:   Collective on v (see explanation below)

    7100:   Input Parameters:
    7101: + dm - The DM
    7102: - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST

    7104:   Input/Output Parameters:
    7105: + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
    7106: - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
    7107:            on output, the PetscSF containing the ranks and local indices of the containing points

    7109:   Level: developer

    7111:   Notes:
    7112:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
    7113:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

    7115:   If *cellSF is NULL on input, a PetscSF will be created.
    7116:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

    7118:   An array that maps each point to its containing cell can be obtained with

    7120: $    const PetscSFNode *cells;
    7121: $    PetscInt           nFound;
    7122: $    const PetscInt    *found;
    7123: $
    7124: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

    7126:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
    7127:   the index of the cell in its rank's local numbering.

    7129: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
    7130: @*/
    7131: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
    7132: {

    7139:   if (*cellSF) {
    7140:     PetscMPIInt result;

    7143:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
    7144:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
    7145:   } else {
    7146:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
    7147:   }
    7148:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
    7149:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
    7150:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
    7151:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
    7152:   return(0);
    7153: }

    7155: /*@
    7156:   DMGetOutputDM - Retrieve the DM associated with the layout for output

    7158:   Collective on dm

    7160:   Input Parameter:
    7161: . dm - The original DM

    7163:   Output Parameter:
    7164: . odm - The DM which provides the layout for output

    7166:   Level: intermediate

    7168: .seealso: VecView(), DMGetGlobalSection()
    7169: @*/
    7170: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
    7171: {
    7172:   PetscSection   section;
    7173:   PetscBool      hasConstraints, ghasConstraints;

    7179:   DMGetLocalSection(dm, &section);
    7180:   PetscSectionHasConstraints(section, &hasConstraints);
    7181:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
    7182:   if (!ghasConstraints) {
    7183:     *odm = dm;
    7184:     return(0);
    7185:   }
    7186:   if (!dm->dmBC) {
    7187:     PetscSection newSection, gsection;
    7188:     PetscSF      sf;

    7190:     DMClone(dm, &dm->dmBC);
    7191:     DMCopyDisc(dm, dm->dmBC);
    7192:     PetscSectionClone(section, &newSection);
    7193:     DMSetLocalSection(dm->dmBC, newSection);
    7194:     PetscSectionDestroy(&newSection);
    7195:     DMGetPointSF(dm->dmBC, &sf);
    7196:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
    7197:     DMSetGlobalSection(dm->dmBC, gsection);
    7198:     PetscSectionDestroy(&gsection);
    7199:   }
    7200:   *odm = dm->dmBC;
    7201:   return(0);
    7202: }

    7204: /*@
    7205:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

    7207:   Input Parameter:
    7208: . dm - The original DM

    7210:   Output Parameters:
    7211: + num - The output sequence number
    7212: - val - The output sequence value

    7214:   Level: intermediate

    7216:   Note: This is intended for output that should appear in sequence, for instance
    7217:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7219: .seealso: VecView()
    7220: @*/
    7221: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
    7222: {
    7227:   return(0);
    7228: }

    7230: /*@
    7231:   DMSetOutputSequenceNumber - Set the sequence number/value for output

    7233:   Input Parameters:
    7234: + dm - The original DM
    7235: . num - The output sequence number
    7236: - val - The output sequence value

    7238:   Level: intermediate

    7240:   Note: This is intended for output that should appear in sequence, for instance
    7241:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7243: .seealso: VecView()
    7244: @*/
    7245: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
    7246: {
    7249:   dm->outputSequenceNum = num;
    7250:   dm->outputSequenceVal = val;
    7251:   return(0);
    7252: }

    7254: /*@C
    7255:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

    7257:   Input Parameters:
    7258: + dm   - The original DM
    7259: . name - The sequence name
    7260: - num  - The output sequence number

    7262:   Output Parameter:
    7263: . val  - The output sequence value

    7265:   Level: intermediate

    7267:   Note: This is intended for output that should appear in sequence, for instance
    7268:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7270: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
    7271: @*/
    7272: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
    7273: {
    7274:   PetscBool      ishdf5;

    7281:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    7282:   if (ishdf5) {
    7283: #if defined(PETSC_HAVE_HDF5)
    7284:     PetscScalar value;

    7286:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
    7287:     *val = PetscRealPart(value);
    7288: #endif
    7289:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
    7290:   return(0);
    7291: }

    7293: /*@
    7294:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

    7296:   Not collective

    7298:   Input Parameter:
    7299: . dm - The DM

    7301:   Output Parameter:
    7302: . useNatural - The flag to build the mapping to a natural order during distribution

    7304:   Level: beginner

    7306: .seealso: DMSetUseNatural(), DMCreate()
    7307: @*/
    7308: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
    7309: {
    7313:   *useNatural = dm->useNatural;
    7314:   return(0);
    7315: }

    7317: /*@
    7318:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

    7320:   Collective on dm

    7322:   Input Parameters:
    7323: + dm - The DM
    7324: - useNatural - The flag to build the mapping to a natural order during distribution

    7326:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

    7328:   Level: beginner

    7330: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
    7331: @*/
    7332: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
    7333: {
    7337:   dm->useNatural = useNatural;
    7338:   return(0);
    7339: }

    7341: /*@C
    7342:   DMCreateLabel - Create a label of the given name if it does not already exist

    7344:   Not Collective

    7346:   Input Parameters:
    7347: + dm   - The DM object
    7348: - name - The label name

    7350:   Level: intermediate

    7352: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7353: @*/
    7354: PetscErrorCode DMCreateLabel(DM dm, const char name[])
    7355: {
    7356:   PetscBool      flg;
    7357:   DMLabel        label;

    7363:   DMHasLabel(dm, name, &flg);
    7364:   if (!flg) {
    7365:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7366:     DMAddLabel(dm, label);
    7367:     DMLabelDestroy(&label);
    7368:   }
    7369:   return(0);
    7370: }

    7372: /*@C
    7373:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

    7375:   Not Collective

    7377:   Input Parameters:
    7378: + dm   - The DM object
    7379: . l    - The index for the label
    7380: - name - The label name

    7382:   Level: intermediate

    7384: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7385: @*/
    7386: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
    7387: {
    7388:   DMLabelLink    orig, prev = NULL;
    7389:   DMLabel        label;
    7390:   PetscInt       Nl, m;
    7391:   PetscBool      flg, match;
    7392:   const char    *lname;

    7398:   DMHasLabel(dm, name, &flg);
    7399:   if (!flg) {
    7400:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7401:     DMAddLabel(dm, label);
    7402:     DMLabelDestroy(&label);
    7403:   }
    7404:   DMGetNumLabels(dm, &Nl);
    7405:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
    7406:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
    7407:     PetscObjectGetName((PetscObject) orig->label, &lname);
    7408:     PetscStrcmp(name, lname, &match);
    7409:     if (match) break;
    7410:   }
    7411:   if (m == l) return(0);
    7412:   if (!m) dm->labels = orig->next;
    7413:   else    prev->next = orig->next;
    7414:   if (!l) {
    7415:     orig->next = dm->labels;
    7416:     dm->labels = orig;
    7417:   } else {
    7418:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
    7419:     orig->next = prev->next;
    7420:     prev->next = orig;
    7421:   }
    7422:   return(0);
    7423: }

    7425: /*@C
    7426:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

    7428:   Not Collective

    7430:   Input Parameters:
    7431: + dm   - The DM object
    7432: . name - The label name
    7433: - point - The mesh point

    7435:   Output Parameter:
    7436: . value - The label value for this point, or -1 if the point is not in the label

    7438:   Level: beginner

    7440: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
    7441: @*/
    7442: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
    7443: {
    7444:   DMLabel        label;

    7450:   DMGetLabel(dm, name, &label);
    7451:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
    7452:   DMLabelGetValue(label, point, value);
    7453:   return(0);
    7454: }

    7456: /*@C
    7457:   DMSetLabelValue - Add a point to a Sieve Label with given value

    7459:   Not Collective

    7461:   Input Parameters:
    7462: + dm   - The DM object
    7463: . name - The label name
    7464: . point - The mesh point
    7465: - value - The label value for this point

    7467:   Output Parameter:

    7469:   Level: beginner

    7471: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
    7472: @*/
    7473: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7474: {
    7475:   DMLabel        label;

    7481:   DMGetLabel(dm, name, &label);
    7482:   if (!label) {
    7483:     DMCreateLabel(dm, name);
    7484:     DMGetLabel(dm, name, &label);
    7485:   }
    7486:   DMLabelSetValue(label, point, value);
    7487:   return(0);
    7488: }

    7490: /*@C
    7491:   DMClearLabelValue - Remove a point from a Sieve Label with given value

    7493:   Not Collective

    7495:   Input Parameters:
    7496: + dm   - The DM object
    7497: . name - The label name
    7498: . point - The mesh point
    7499: - value - The label value for this point

    7501:   Output Parameter:

    7503:   Level: beginner

    7505: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
    7506: @*/
    7507: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7508: {
    7509:   DMLabel        label;

    7515:   DMGetLabel(dm, name, &label);
    7516:   if (!label) return(0);
    7517:   DMLabelClearValue(label, point, value);
    7518:   return(0);
    7519: }

    7521: /*@C
    7522:   DMGetLabelSize - Get the number of different integer ids in a Label

    7524:   Not Collective

    7526:   Input Parameters:
    7527: + dm   - The DM object
    7528: - name - The label name

    7530:   Output Parameter:
    7531: . size - The number of different integer ids, or 0 if the label does not exist

    7533:   Level: beginner

    7535: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
    7536: @*/
    7537: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
    7538: {
    7539:   DMLabel        label;

    7546:   DMGetLabel(dm, name, &label);
    7547:   *size = 0;
    7548:   if (!label) return(0);
    7549:   DMLabelGetNumValues(label, size);
    7550:   return(0);
    7551: }

    7553: /*@C
    7554:   DMGetLabelIdIS - Get the integer ids in a label

    7556:   Not Collective

    7558:   Input Parameters:
    7559: + mesh - The DM object
    7560: - name - The label name

    7562:   Output Parameter:
    7563: . ids - The integer ids, or NULL if the label does not exist

    7565:   Level: beginner

    7567: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
    7568: @*/
    7569: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
    7570: {
    7571:   DMLabel        label;

    7578:   DMGetLabel(dm, name, &label);
    7579:   *ids = NULL;
    7580:  if (label) {
    7581:     DMLabelGetValueIS(label, ids);
    7582:   } else {
    7583:     /* returning an empty IS */
    7584:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
    7585:   }
    7586:   return(0);
    7587: }

    7589: /*@C
    7590:   DMGetStratumSize - Get the number of points in a label stratum

    7592:   Not Collective

    7594:   Input Parameters:
    7595: + dm - The DM object
    7596: . name - The label name
    7597: - value - The stratum value

    7599:   Output Parameter:
    7600: . size - The stratum size

    7602:   Level: beginner

    7604: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
    7605: @*/
    7606: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
    7607: {
    7608:   DMLabel        label;

    7615:   DMGetLabel(dm, name, &label);
    7616:   *size = 0;
    7617:   if (!label) return(0);
    7618:   DMLabelGetStratumSize(label, value, size);
    7619:   return(0);
    7620: }

    7622: /*@C
    7623:   DMGetStratumIS - Get the points in a label stratum

    7625:   Not Collective

    7627:   Input Parameters:
    7628: + dm - The DM object
    7629: . name - The label name
    7630: - value - The stratum value

    7632:   Output Parameter:
    7633: . points - The stratum points, or NULL if the label does not exist or does not have that value

    7635:   Level: beginner

    7637: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
    7638: @*/
    7639: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
    7640: {
    7641:   DMLabel        label;

    7648:   DMGetLabel(dm, name, &label);
    7649:   *points = NULL;
    7650:   if (!label) return(0);
    7651:   DMLabelGetStratumIS(label, value, points);
    7652:   return(0);
    7653: }

    7655: /*@C
    7656:   DMSetStratumIS - Set the points in a label stratum

    7658:   Not Collective

    7660:   Input Parameters:
    7661: + dm - The DM object
    7662: . name - The label name
    7663: . value - The stratum value
    7664: - points - The stratum points

    7666:   Level: beginner

    7668: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
    7669: @*/
    7670: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
    7671: {
    7672:   DMLabel        label;

    7679:   DMGetLabel(dm, name, &label);
    7680:   if (!label) return(0);
    7681:   DMLabelSetStratumIS(label, value, points);
    7682:   return(0);
    7683: }

    7685: /*@C
    7686:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

    7688:   Not Collective

    7690:   Input Parameters:
    7691: + dm   - The DM object
    7692: . name - The label name
    7693: - value - The label value for this point

    7695:   Output Parameter:

    7697:   Level: beginner

    7699: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
    7700: @*/
    7701: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
    7702: {
    7703:   DMLabel        label;

    7709:   DMGetLabel(dm, name, &label);
    7710:   if (!label) return(0);
    7711:   DMLabelClearStratum(label, value);
    7712:   return(0);
    7713: }

    7715: /*@
    7716:   DMGetNumLabels - Return the number of labels defined by the mesh

    7718:   Not Collective

    7720:   Input Parameter:
    7721: . dm   - The DM object

    7723:   Output Parameter:
    7724: . numLabels - the number of Labels

    7726:   Level: intermediate

    7728: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7729: @*/
    7730: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
    7731: {
    7732:   DMLabelLink next = dm->labels;
    7733:   PetscInt  n    = 0;

    7738:   while (next) {++n; next = next->next;}
    7739:   *numLabels = n;
    7740:   return(0);
    7741: }

    7743: /*@C
    7744:   DMGetLabelName - Return the name of nth label

    7746:   Not Collective

    7748:   Input Parameters:
    7749: + dm - The DM object
    7750: - n  - the label number

    7752:   Output Parameter:
    7753: . name - the label name

    7755:   Level: intermediate

    7757: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7758: @*/
    7759: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
    7760: {
    7761:   DMLabelLink    next = dm->labels;
    7762:   PetscInt       l    = 0;

    7768:   while (next) {
    7769:     if (l == n) {
    7770:       PetscObjectGetName((PetscObject) next->label, name);
    7771:       return(0);
    7772:     }
    7773:     ++l;
    7774:     next = next->next;
    7775:   }
    7776:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7777: }

    7779: /*@C
    7780:   DMHasLabel - Determine whether the mesh has a label of a given name

    7782:   Not Collective

    7784:   Input Parameters:
    7785: + dm   - The DM object
    7786: - name - The label name

    7788:   Output Parameter:
    7789: . hasLabel - PETSC_TRUE if the label is present

    7791:   Level: intermediate

    7793: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7794: @*/
    7795: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
    7796: {
    7797:   DMLabelLink    next = dm->labels;
    7798:   const char    *lname;

    7805:   *hasLabel = PETSC_FALSE;
    7806:   while (next) {
    7807:     PetscObjectGetName((PetscObject) next->label, &lname);
    7808:     PetscStrcmp(name, lname, hasLabel);
    7809:     if (*hasLabel) break;
    7810:     next = next->next;
    7811:   }
    7812:   return(0);
    7813: }

    7815: /*@C
    7816:   DMGetLabel - Return the label of a given name, or NULL

    7818:   Not Collective

    7820:   Input Parameters:
    7821: + dm   - The DM object
    7822: - name - The label name

    7824:   Output Parameter:
    7825: . label - The DMLabel, or NULL if the label is absent

    7827:   Note: Some of the default labels in a DMPlex will be
    7828: $ "depth"       - Holds the depth (co-dimension) of each mesh point
    7829: $ "celltype"    - Holds the topological type of each cell
    7830: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
    7831: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
    7832: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
    7833: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

    7835:   Level: intermediate

    7837: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
    7838: @*/
    7839: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
    7840: {
    7841:   DMLabelLink    next = dm->labels;
    7842:   PetscBool      hasLabel;
    7843:   const char    *lname;

    7850:   *label = NULL;
    7851:   while (next) {
    7852:     PetscObjectGetName((PetscObject) next->label, &lname);
    7853:     PetscStrcmp(name, lname, &hasLabel);
    7854:     if (hasLabel) {
    7855:       *label = next->label;
    7856:       break;
    7857:     }
    7858:     next = next->next;
    7859:   }
    7860:   return(0);
    7861: }

    7863: /*@C
    7864:   DMGetLabelByNum - Return the nth label

    7866:   Not Collective

    7868:   Input Parameters:
    7869: + dm - The DM object
    7870: - n  - the label number

    7872:   Output Parameter:
    7873: . label - the label

    7875:   Level: intermediate

    7877: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7878: @*/
    7879: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
    7880: {
    7881:   DMLabelLink next = dm->labels;
    7882:   PetscInt    l    = 0;

    7887:   while (next) {
    7888:     if (l == n) {
    7889:       *label = next->label;
    7890:       return(0);
    7891:     }
    7892:     ++l;
    7893:     next = next->next;
    7894:   }
    7895:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7896: }

    7898: /*@C
    7899:   DMAddLabel - Add the label to this mesh

    7901:   Not Collective

    7903:   Input Parameters:
    7904: + dm   - The DM object
    7905: - label - The DMLabel

    7907:   Level: developer

    7909: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7910: @*/
    7911: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
    7912: {
    7913:   DMLabelLink    l, *p, tmpLabel;
    7914:   PetscBool      hasLabel;
    7915:   const char    *lname;
    7916:   PetscBool      flg;

    7921:   PetscObjectGetName((PetscObject) label, &lname);
    7922:   DMHasLabel(dm, lname, &hasLabel);
    7923:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
    7924:   PetscCalloc1(1, &tmpLabel);
    7925:   tmpLabel->label  = label;
    7926:   tmpLabel->output = PETSC_TRUE;
    7927:   for (p=&dm->labels; (l=*p); p=&l->next) {}
    7928:   *p = tmpLabel;
    7929:   PetscObjectReference((PetscObject)label);
    7930:   PetscStrcmp(lname, "depth", &flg);
    7931:   if (flg) dm->depthLabel = label;
    7932:   PetscStrcmp(lname, "celltype", &flg);
    7933:   if (flg) dm->celltypeLabel = label;
    7934:   return(0);
    7935: }

    7937: /*@C
    7938:   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present

    7940:   Not Collective

    7942:   Input Parameters:
    7943: + dm    - The DM object
    7944: - label - The DMLabel, having the same name, to substitute

    7946:   Note: Some of the default labels in a DMPlex will be
    7947: $ "depth"       - Holds the depth (co-dimension) of each mesh point
    7948: $ "celltype"    - Holds the topological type of each cell
    7949: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
    7950: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
    7951: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
    7952: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

    7954:   Level: intermediate

    7956: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
    7957: @*/
    7958: PetscErrorCode DMSetLabel(DM dm, DMLabel label)
    7959: {
    7960:   DMLabelLink    next = dm->labels;
    7961:   PetscBool      hasLabel, flg;
    7962:   const char    *name, *lname;

    7968:   PetscObjectGetName((PetscObject) label, &name);
    7969:   while (next) {
    7970:     PetscObjectGetName((PetscObject) next->label, &lname);
    7971:     PetscStrcmp(name, lname, &hasLabel);
    7972:     if (hasLabel) {
    7973:       PetscObjectReference((PetscObject) label);
    7974:       PetscStrcmp(lname, "depth", &flg);
    7975:       if (flg) dm->depthLabel = label;
    7976:       PetscStrcmp(lname, "celltype", &flg);
    7977:       if (flg) dm->celltypeLabel = label;
    7978:       DMLabelDestroy(&next->label);
    7979:       next->label = label;
    7980:       break;
    7981:     }
    7982:     next = next->next;
    7983:   }
    7984:   return(0);
    7985: }

    7987: /*@C
    7988:   DMRemoveLabel - Remove the label given by name from this mesh

    7990:   Not Collective

    7992:   Input Parameters:
    7993: + dm   - The DM object
    7994: - name - The label name

    7996:   Output Parameter:
    7997: . label - The DMLabel, or NULL if the label is absent

    7999:   Level: developer

    8001:   Notes:
    8002:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
    8003:   DMLabelDestroy() on the label.

    8005:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
    8006:   call DMLabelDestroy(). Instead, the label is returned and the user is
    8007:   responsible of calling DMLabelDestroy() at some point.

    8009: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
    8010: @*/
    8011: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
    8012: {
    8013:   DMLabelLink    link, *pnext;
    8014:   PetscBool      hasLabel;
    8015:   const char    *lname;

    8021:   if (label) {
    8023:     *label = NULL;
    8024:   }
    8025:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    8026:     PetscObjectGetName((PetscObject) link->label, &lname);
    8027:     PetscStrcmp(name, lname, &hasLabel);
    8028:     if (hasLabel) {
    8029:       *pnext = link->next; /* Remove from list */
    8030:       PetscStrcmp(name, "depth", &hasLabel);
    8031:       if (hasLabel) dm->depthLabel = NULL;
    8032:       PetscStrcmp(name, "celltype", &hasLabel);
    8033:       if (hasLabel) dm->celltypeLabel = NULL;
    8034:       if (label) *label = link->label;
    8035:       else       {DMLabelDestroy(&link->label);}
    8036:       PetscFree(link);
    8037:       break;
    8038:     }
    8039:   }
    8040:   return(0);
    8041: }

    8043: /*@
    8044:   DMRemoveLabelBySelf - Remove the label from this mesh

    8046:   Not Collective

    8048:   Input Parameters:
    8049: + dm   - The DM object
    8050: . label - The DMLabel to be removed from the DM
    8051: - failNotFound - Should it fail if the label is not found in the DM?

    8053:   Level: developer

    8055:   Notes:
    8056:   Only exactly the same instance is removed if found, name match is ignored.
    8057:   If the DM has an exclusive reference to the label, it gets destroyed and
    8058:   *label nullified.

    8060: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
    8061: @*/
    8062: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
    8063: {
    8064:   DMLabelLink    link, *pnext;
    8065:   PetscBool      hasLabel = PETSC_FALSE;

    8071:   if (!*label && !failNotFound) return(0);
    8074:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    8075:     if (*label == link->label) {
    8076:       hasLabel = PETSC_TRUE;
    8077:       *pnext = link->next; /* Remove from list */
    8078:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
    8079:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    8080:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
    8081:       DMLabelDestroy(&link->label);
    8082:       PetscFree(link);
    8083:       break;
    8084:     }
    8085:   }
    8086:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
    8087:   return(0);
    8088: }

    8090: /*@C
    8091:   DMGetLabelOutput - Get the output flag for a given label

    8093:   Not Collective

    8095:   Input Parameters:
    8096: + dm   - The DM object
    8097: - name - The label name

    8099:   Output Parameter:
    8100: . output - The flag for output

    8102:   Level: developer

    8104: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    8105: @*/
    8106: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
    8107: {
    8108:   DMLabelLink    next = dm->labels;
    8109:   const char    *lname;

    8116:   while (next) {
    8117:     PetscBool flg;

    8119:     PetscObjectGetName((PetscObject) next->label, &lname);
    8120:     PetscStrcmp(name, lname, &flg);
    8121:     if (flg) {*output = next->output; return(0);}
    8122:     next = next->next;
    8123:   }
    8124:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    8125: }

    8127: /*@C
    8128:   DMSetLabelOutput - Set the output flag for a given label

    8130:   Not Collective

    8132:   Input Parameters:
    8133: + dm     - The DM object
    8134: . name   - The label name
    8135: - output - The flag for output

    8137:   Level: developer

    8139: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    8140: @*/
    8141: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
    8142: {
    8143:   DMLabelLink    next = dm->labels;
    8144:   const char    *lname;

    8150:   while (next) {
    8151:     PetscBool flg;

    8153:     PetscObjectGetName((PetscObject) next->label, &lname);
    8154:     PetscStrcmp(name, lname, &flg);
    8155:     if (flg) {next->output = output; return(0);}
    8156:     next = next->next;
    8157:   }
    8158:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    8159: }

    8161: /*@
    8162:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

    8164:   Collective on dmA

    8166:   Input Parameters:
    8167: + dmA - The DM object with initial labels
    8168: . dmB - The DM object with copied labels
    8169: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
    8170: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

    8172:   Level: intermediate

    8174:   Note: This is typically used when interpolating or otherwise adding to a mesh

    8176: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
    8177: @*/
    8178: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
    8179: {
    8180:   DMLabel        label, labelNew;
    8181:   const char    *name;
    8182:   PetscBool      flg;
    8183:   DMLabelLink    link;

    8191:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
    8192:   if (dmA == dmB) return(0);
    8193:   for (link=dmA->labels; link; link=link->next) {
    8194:     label=link->label;
    8195:     PetscObjectGetName((PetscObject)label, &name);
    8196:     if (!all) {
    8197:       PetscStrcmp(name, "depth", &flg);
    8198:       if (flg) continue;
    8199:       PetscStrcmp(name, "dim", &flg);
    8200:       if (flg) continue;
    8201:       PetscStrcmp(name, "celltype", &flg);
    8202:       if (flg) continue;
    8203:     }
    8204:     if (mode==PETSC_COPY_VALUES) {
    8205:       DMLabelDuplicate(label, &labelNew);
    8206:     } else {
    8207:       labelNew = label;
    8208:     }
    8209:     DMAddLabel(dmB, labelNew);
    8210:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
    8211:   }
    8212:   return(0);
    8213: }

    8215: PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
    8216: {
    8220:   if (!*label) {
    8221:     DMCreateLabel(dm, name);
    8222:     DMGetLabel(dm, name, label);
    8223:   }
    8224:   DMLabelSetValue(*label, point, value);
    8225:   return(0);
    8226: }

    8228: /*
    8229:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
    8230:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
    8231:   (label, id) pair in the DM.

    8233:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
    8234:   each label.
    8235: */
    8236: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
    8237: {
    8238:   DMUniversalLabel ul;
    8239:   PetscBool       *active;
    8240:   PetscInt         pStart, pEnd, p, Nl, l, m;
    8241:   PetscErrorCode   ierr;

    8244:   PetscMalloc1(1, &ul);
    8245:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
    8246:   DMGetNumLabels(dm, &Nl);
    8247:   PetscCalloc1(Nl, &active);
    8248:   ul->Nl = 0;
    8249:   for (l = 0; l < Nl; ++l) {
    8250:     PetscBool   isdepth, iscelltype;
    8251:     const char *name;

    8253:     DMGetLabelName(dm, l, &name);
    8254:     PetscStrncmp(name, "depth", 6, &isdepth);
    8255:     PetscStrncmp(name, "celltype", 9, &iscelltype);
    8256:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
    8257:     if (active[l]) ++ul->Nl;
    8258:   }
    8259:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
    8260:   ul->Nv = 0;
    8261:   for (l = 0, m = 0; l < Nl; ++l) {
    8262:     DMLabel     label;
    8263:     PetscInt    nv;
    8264:     const char *name;

    8266:     if (!active[l]) continue;
    8267:     DMGetLabelName(dm, l, &name);
    8268:     DMGetLabelByNum(dm, l, &label);
    8269:     DMLabelGetNumValues(label, &nv);
    8270:     PetscStrallocpy(name, &ul->names[m]);
    8271:     ul->indices[m]   = l;
    8272:     ul->Nv          += nv;
    8273:     ul->offsets[m+1] = nv;
    8274:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
    8275:     ++m;
    8276:   }
    8277:   for (l = 1; l <= ul->Nl; ++l) {
    8278:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
    8279:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
    8280:   }
    8281:   for (l = 0; l < ul->Nl; ++l) {
    8282:     PetscInt b;

    8284:     ul->masks[l] = 0;
    8285:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
    8286:   }
    8287:   PetscMalloc1(ul->Nv, &ul->values);
    8288:   for (l = 0, m = 0; l < Nl; ++l) {
    8289:     DMLabel         label;
    8290:     IS              valueIS;
    8291:     const PetscInt *varr;
    8292:     PetscInt        nv, v;

    8294:     if (!active[l]) continue;
    8295:     DMGetLabelByNum(dm, l, &label);
    8296:     DMLabelGetNumValues(label, &nv);
    8297:     DMLabelGetValueIS(label, &valueIS);
    8298:     ISGetIndices(valueIS, &varr);
    8299:     for (v = 0; v < nv; ++v) {
    8300:       ul->values[ul->offsets[m]+v] = varr[v];
    8301:     }
    8302:     ISRestoreIndices(valueIS, &varr);
    8303:     ISDestroy(&valueIS);
    8304:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
    8305:     ++m;
    8306:   }
    8307:   DMPlexGetChart(dm, &pStart, &pEnd);
    8308:   for (p = pStart; p < pEnd; ++p) {
    8309:     PetscInt  uval = 0;
    8310:     PetscBool marked = PETSC_FALSE;

    8312:     for (l = 0, m = 0; l < Nl; ++l) {
    8313:       DMLabel  label;
    8314:       PetscInt val, defval, loc, nv;

    8316:       if (!active[l]) continue;
    8317:       DMGetLabelByNum(dm, l, &label);
    8318:       DMLabelGetValue(label, p, &val);
    8319:       DMLabelGetDefaultValue(label, &defval);
    8320:       if (val == defval) {++m; continue;}
    8321:       nv = ul->offsets[m+1]-ul->offsets[m];
    8322:       marked = PETSC_TRUE;
    8323:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
    8324:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
    8325:       uval += (loc+1) << ul->bits[m];
    8326:       ++m;
    8327:     }
    8328:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
    8329:   }
    8330:   PetscFree(active);
    8331:   *universal = ul;
    8332:   return(0);
    8333: }

    8335: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
    8336: {
    8337:   PetscInt       l;

    8341:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
    8342:   DMLabelDestroy(&(*universal)->label);
    8343:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
    8344:   PetscFree((*universal)->values);
    8345:   PetscFree(*universal);
    8346:   *universal = NULL;
    8347:   return(0);
    8348: }

    8350: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
    8351: {
    8354:   *ulabel = ul->label;
    8355:   return(0);
    8356: }

    8358: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
    8359: {
    8360:   PetscInt       Nl = ul->Nl, l;

    8365:   for (l = 0; l < Nl; ++l) {
    8366:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
    8367:     else               {DMCreateLabel(dm, ul->names[l]);}
    8368:   }
    8369:   if (preserveOrder) {
    8370:     for (l = 0; l < ul->Nl; ++l) {
    8371:       const char *name;
    8372:       PetscBool   match;

    8374:       DMGetLabelName(dm, ul->indices[l], &name);
    8375:       PetscStrcmp(name, ul->names[l], &match);
    8376:       if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
    8377:     }
    8378:   }
    8379:   return(0);
    8380: }

    8382: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
    8383: {
    8384:   PetscInt       l;

    8388:   for (l = 0; l < ul->Nl; ++l) {
    8389:     DMLabel  label;
    8390:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

    8392:     if (lval) {
    8393:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
    8394:       else          {DMGetLabel(dm, ul->names[l], &label);}
    8395:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
    8396:     }
    8397:   }
    8398:   return(0);
    8399: }

    8401: /*@
    8402:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

    8404:   Input Parameter:
    8405: . dm - The DM object

    8407:   Output Parameter:
    8408: . cdm - The coarse DM

    8410:   Level: intermediate

    8412: .seealso: DMSetCoarseDM()
    8413: @*/
    8414: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
    8415: {
    8419:   *cdm = dm->coarseMesh;
    8420:   return(0);
    8421: }

    8423: /*@
    8424:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

    8426:   Input Parameters:
    8427: + dm - The DM object
    8428: - cdm - The coarse DM

    8430:   Level: intermediate

    8432: .seealso: DMGetCoarseDM()
    8433: @*/
    8434: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
    8435: {

    8441:   PetscObjectReference((PetscObject)cdm);
    8442:   DMDestroy(&dm->coarseMesh);
    8443:   dm->coarseMesh = cdm;
    8444:   return(0);
    8445: }

    8447: /*@
    8448:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

    8450:   Input Parameter:
    8451: . dm - The DM object

    8453:   Output Parameter:
    8454: . fdm - The fine DM

    8456:   Level: intermediate

    8458: .seealso: DMSetFineDM()
    8459: @*/
    8460: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
    8461: {
    8465:   *fdm = dm->fineMesh;
    8466:   return(0);
    8467: }

    8469: /*@
    8470:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

    8472:   Input Parameters:
    8473: + dm - The DM object
    8474: - fdm - The fine DM

    8476:   Level: intermediate

    8478: .seealso: DMGetFineDM()
    8479: @*/
    8480: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
    8481: {

    8487:   PetscObjectReference((PetscObject)fdm);
    8488:   DMDestroy(&dm->fineMesh);
    8489:   dm->fineMesh = fdm;
    8490:   return(0);
    8491: }

    8493: /*=== DMBoundary code ===*/

    8495: /*@C
    8496:   DMAddBoundary - Add a boundary condition to the model

    8498:   Collective on dm

    8500:   Input Parameters:
    8501: + dm       - The DM, with a PetscDS that matches the problem being constrained
    8502: . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8503: . name     - The BC name
    8504: . label    - The label defining constrained points
    8505: . Nv       - The number of DMLabel values for constrained points
    8506: . values   - An array of values for constrained points
    8507: . field    - The field to constrain
    8508: . Nc       - The number of constrained field components (0 will constrain all fields)
    8509: . comps    - An array of constrained component numbers
    8510: . bcFunc   - A pointwise function giving boundary values
    8511: . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
    8512: - ctx      - An optional user context for bcFunc

    8514:   Output Parameter:
    8515: . bd          - (Optional) Boundary number

    8517:   Options Database Keys:
    8518: + -bc_<boundary name> <num> - Overrides the boundary ids
    8519: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8521:   Note:
    8522:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

    8524: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

    8526:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    8528: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8529: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8530: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8531: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    8533: + dim - the spatial dimension
    8534: . Nf - the number of fields
    8535: . uOff - the offset into u[] and u_t[] for each field
    8536: . uOff_x - the offset into u_x[] for each field
    8537: . u - each field evaluated at the current point
    8538: . u_t - the time derivative of each field evaluated at the current point
    8539: . u_x - the gradient of each field evaluated at the current point
    8540: . aOff - the offset into a[] and a_t[] for each auxiliary field
    8541: . aOff_x - the offset into a_x[] for each auxiliary field
    8542: . a - each auxiliary field evaluated at the current point
    8543: . a_t - the time derivative of each auxiliary field evaluated at the current point
    8544: . a_x - the gradient of auxiliary each field evaluated at the current point
    8545: . t - current time
    8546: . x - coordinates of the current point
    8547: . numConstants - number of constant parameters
    8548: . constants - constant parameters
    8549: - bcval - output values at the current point

    8551:   Level: developer

    8553: .seealso: DSGetBoundary(), PetscDSAddBoundary()
    8554: @*/
    8555: 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)
    8556: {
    8557:   PetscDS        ds;

    8567:   DMGetDS(dm, &ds);
    8568:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label);
    8569:   PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd);
    8570:   return(0);
    8571: }

    8573: /* TODO Remove this since now the structures are the same */
    8574: static PetscErrorCode DMPopulateBoundary(DM dm)
    8575: {
    8576:   PetscDS        ds;
    8577:   DMBoundary    *lastnext;
    8578:   DSBoundary     dsbound;

    8582:   DMGetDS(dm, &ds);
    8583:   dsbound = ds->boundary;
    8584:   if (dm->boundary) {
    8585:     DMBoundary next = dm->boundary;

    8587:     /* quick check to see if the PetscDS has changed */
    8588:     if (next->dsboundary == dsbound) return(0);
    8589:     /* the PetscDS has changed: tear down and rebuild */
    8590:     while (next) {
    8591:       DMBoundary b = next;

    8593:       next = b->next;
    8594:       PetscFree(b);
    8595:     }
    8596:     dm->boundary = NULL;
    8597:   }

    8599:   lastnext = &(dm->boundary);
    8600:   while (dsbound) {
    8601:     DMBoundary dmbound;

    8603:     PetscNew(&dmbound);
    8604:     dmbound->dsboundary = dsbound;
    8605:     dmbound->label      = dsbound->label;
    8606:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
    8607:     *lastnext = dmbound;
    8608:     lastnext = &(dmbound->next);
    8609:     dsbound = dsbound->next;
    8610:   }
    8611:   return(0);
    8612: }

    8614: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
    8615: {
    8616:   DMBoundary     b;

    8622:   *isBd = PETSC_FALSE;
    8623:   DMPopulateBoundary(dm);
    8624:   b = dm->boundary;
    8625:   while (b && !(*isBd)) {
    8626:     DMLabel    label = b->label;
    8627:     DSBoundary dsb   = b->dsboundary;
    8628:     PetscInt   i;

    8630:     if (label) {
    8631:       for (i = 0; i < dsb->Nv && !(*isBd); ++i) {DMLabelStratumHasPoint(label, dsb->values[i], point, isBd);}
    8632:     }
    8633:     b = b->next;
    8634:   }
    8635:   return(0);
    8636: }

    8638: /*@C
    8639:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

    8641:   Collective on DM

    8643:   Input Parameters:
    8644: + dm      - The DM
    8645: . time    - The time
    8646: . funcs   - The coordinate functions to evaluate, one per field
    8647: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8648: - mode    - The insertion mode for values

    8650:   Output Parameter:
    8651: . X - vector

    8653:    Calling sequence of func:
    8654: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8656: +  dim - The spatial dimension
    8657: .  time - The time at which to sample
    8658: .  x   - The coordinates
    8659: .  Nc  - The number of components
    8660: .  u   - The output field values
    8661: -  ctx - optional user-defined function context

    8663:   Level: developer

    8665: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8666: @*/
    8667: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
    8668: {
    8669:   Vec            localX;

    8674:   DMGetLocalVector(dm, &localX);
    8675:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
    8676:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8677:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8678:   DMRestoreLocalVector(dm, &localX);
    8679:   return(0);
    8680: }

    8682: /*@C
    8683:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

    8685:   Not collective

    8687:   Input Parameters:
    8688: + dm      - The DM
    8689: . time    - The time
    8690: . funcs   - The coordinate functions to evaluate, one per field
    8691: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8692: - mode    - The insertion mode for values

    8694:   Output Parameter:
    8695: . localX - vector

    8697:    Calling sequence of func:
    8698: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8700: +  dim - The spatial dimension
    8701: .  x   - The coordinates
    8702: .  Nc  - The number of components
    8703: .  u   - The output field values
    8704: -  ctx - optional user-defined function context

    8706:   Level: developer

    8708: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8709: @*/
    8710: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
    8711: {

    8717:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
    8718:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
    8719:   return(0);
    8720: }

    8722: /*@C
    8723:   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.

    8725:   Collective on DM

    8727:   Input Parameters:
    8728: + dm      - The DM
    8729: . time    - The time
    8730: . label   - The DMLabel selecting the portion of the mesh for projection
    8731: . funcs   - The coordinate functions to evaluate, one per field
    8732: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8733: - mode    - The insertion mode for values

    8735:   Output Parameter:
    8736: . X - vector

    8738:    Calling sequence of func:
    8739: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8741: +  dim - The spatial dimension
    8742: .  x   - The coordinates
    8743: .  Nc  - The number of components
    8744: .  u   - The output field values
    8745: -  ctx - optional user-defined function context

    8747:   Level: developer

    8749: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
    8750: @*/
    8751: 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)
    8752: {
    8753:   Vec            localX;

    8758:   DMGetLocalVector(dm, &localX);
    8759:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8760:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8761:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8762:   DMRestoreLocalVector(dm, &localX);
    8763:   return(0);
    8764: }

    8766: /*@C
    8767:   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.

    8769:   Not collective

    8771:   Input Parameters:
    8772: + dm      - The DM
    8773: . time    - The time
    8774: . label   - The DMLabel selecting the portion of the mesh for projection
    8775: . funcs   - The coordinate functions to evaluate, one per field
    8776: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8777: - mode    - The insertion mode for values

    8779:   Output Parameter:
    8780: . localX - vector

    8782:    Calling sequence of func:
    8783: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);

    8785: +  dim - The spatial dimension
    8786: .  x   - The coordinates
    8787: .  Nc  - The number of components
    8788: .  u   - The output field values
    8789: -  ctx - optional user-defined function context

    8791:   Level: developer

    8793: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8794: @*/
    8795: 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)
    8796: {

    8802:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
    8803:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8804:   return(0);
    8805: }

    8807: /*@C
    8808:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

    8810:   Not collective

    8812:   Input Parameters:
    8813: + dm      - The DM
    8814: . time    - The time
    8815: . localU  - The input field vector
    8816: . funcs   - The functions to evaluate, one per field
    8817: - mode    - The insertion mode for values

    8819:   Output Parameter:
    8820: . localX  - The output vector

    8822:    Calling sequence of func:
    8823: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8824: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8825: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8826: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8828: +  dim          - The spatial dimension
    8829: .  Nf           - The number of input fields
    8830: .  NfAux        - The number of input auxiliary fields
    8831: .  uOff         - The offset of each field in u[]
    8832: .  uOff_x       - The offset of each field in u_x[]
    8833: .  u            - The field values at this point in space
    8834: .  u_t          - The field time derivative at this point in space (or NULL)
    8835: .  u_x          - The field derivatives at this point in space
    8836: .  aOff         - The offset of each auxiliary field in u[]
    8837: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8838: .  a            - The auxiliary field values at this point in space
    8839: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8840: .  a_x          - The auxiliary field derivatives at this point in space
    8841: .  t            - The current time
    8842: .  x            - The coordinates of this point
    8843: .  numConstants - The number of constants
    8844: .  constants    - The value of each constant
    8845: -  f            - The value of the function at this point in space

    8847:   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.
    8848:   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
    8849:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8850:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8852:   Level: intermediate

    8854: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8855: @*/
    8856: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
    8857:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
    8858:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8859:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8860:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8861:                                    InsertMode mode, Vec localX)
    8862: {

    8869:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
    8870:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
    8871:   return(0);
    8872: }

    8874: /*@C
    8875:   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.

    8877:   Not collective

    8879:   Input Parameters:
    8880: + dm      - The DM
    8881: . time    - The time
    8882: . label   - The DMLabel marking the portion of the domain to output
    8883: . numIds  - The number of label ids to use
    8884: . ids     - The label ids to use for marking
    8885: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8886: . comps   - The components to set in the output, or NULL for all components
    8887: . localU  - The input field vector
    8888: . funcs   - The functions to evaluate, one per field
    8889: - mode    - The insertion mode for values

    8891:   Output Parameter:
    8892: . localX  - The output vector

    8894:    Calling sequence of func:
    8895: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8896: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8897: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8898: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8900: +  dim          - The spatial dimension
    8901: .  Nf           - The number of input fields
    8902: .  NfAux        - The number of input auxiliary fields
    8903: .  uOff         - The offset of each field in u[]
    8904: .  uOff_x       - The offset of each field in u_x[]
    8905: .  u            - The field values at this point in space
    8906: .  u_t          - The field time derivative at this point in space (or NULL)
    8907: .  u_x          - The field derivatives at this point in space
    8908: .  aOff         - The offset of each auxiliary field in u[]
    8909: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8910: .  a            - The auxiliary field values at this point in space
    8911: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8912: .  a_x          - The auxiliary field derivatives at this point in space
    8913: .  t            - The current time
    8914: .  x            - The coordinates of this point
    8915: .  numConstants - The number of constants
    8916: .  constants    - The value of each constant
    8917: -  f            - The value of the function at this point in space

    8919:   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.
    8920:   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
    8921:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8922:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8924:   Level: intermediate

    8926: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8927: @*/
    8928: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8929:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
    8930:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8931:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8932:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8933:                                         InsertMode mode, Vec localX)
    8934: {

    8941:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
    8942:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8943:   return(0);
    8944: }

    8946: /*@C
    8947:   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.

    8949:   Not collective

    8951:   Input Parameters:
    8952: + dm      - The DM
    8953: . time    - The time
    8954: . label   - The DMLabel marking the portion of the domain boundary to output
    8955: . numIds  - The number of label ids to use
    8956: . ids     - The label ids to use for marking
    8957: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8958: . comps   - The components to set in the output, or NULL for all components
    8959: . localU  - The input field vector
    8960: . funcs   - The functions to evaluate, one per field
    8961: - mode    - The insertion mode for values

    8963:   Output Parameter:
    8964: . localX  - The output vector

    8966:    Calling sequence of func:
    8967: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8968: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8969: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8970: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8972: +  dim          - The spatial dimension
    8973: .  Nf           - The number of input fields
    8974: .  NfAux        - The number of input auxiliary fields
    8975: .  uOff         - The offset of each field in u[]
    8976: .  uOff_x       - The offset of each field in u_x[]
    8977: .  u            - The field values at this point in space
    8978: .  u_t          - The field time derivative at this point in space (or NULL)
    8979: .  u_x          - The field derivatives at this point in space
    8980: .  aOff         - The offset of each auxiliary field in u[]
    8981: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8982: .  a            - The auxiliary field values at this point in space
    8983: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8984: .  a_x          - The auxiliary field derivatives at this point in space
    8985: .  t            - The current time
    8986: .  x            - The coordinates of this point
    8987: .  n            - The face normal
    8988: .  numConstants - The number of constants
    8989: .  constants    - The value of each constant
    8990: -  f            - The value of the function at this point in space

    8992:   Note:
    8993:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8994:   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
    8995:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8996:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8998:   Level: intermediate

    9000: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    9001: @*/
    9002: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    9003:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
    9004:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    9005:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    9006:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    9007:                                           InsertMode mode, Vec localX)
    9008: {

    9015:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
    9016:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    9017:   return(0);
    9018: }

    9020: /*@C
    9021:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

    9023:   Input Parameters:
    9024: + dm    - The DM
    9025: . time  - The time
    9026: . funcs - The functions to evaluate for each field component
    9027: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    9028: - X     - The coefficient vector u_h, a global vector

    9030:   Output Parameter:
    9031: . diff - The diff ||u - u_h||_2

    9033:   Level: developer

    9035: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    9036: @*/
    9037: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
    9038: {

    9044:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
    9045:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
    9046:   return(0);
    9047: }

    9049: /*@C
    9050:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

    9052:   Collective on dm

    9054:   Input Parameters:
    9055: + dm    - The DM
    9056: , time  - The time
    9057: . funcs - The gradient functions to evaluate for each field component
    9058: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    9059: . X     - The coefficient vector u_h, a global vector
    9060: - n     - The vector to project along

    9062:   Output Parameter:
    9063: . diff - The diff ||(grad u - grad u_h) . n||_2

    9065:   Level: developer

    9067: .seealso: DMProjectFunction(), DMComputeL2Diff()
    9068: @*/
    9069: 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)
    9070: {

    9076:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
    9077:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
    9078:   return(0);
    9079: }

    9081: /*@C
    9082:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

    9084:   Collective on dm

    9086:   Input Parameters:
    9087: + dm    - The DM
    9088: . time  - The time
    9089: . funcs - The functions to evaluate for each field component
    9090: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    9091: - X     - The coefficient vector u_h, a global vector

    9093:   Output Parameter:
    9094: . diff - The array of differences, ||u^f - u^f_h||_2

    9096:   Level: developer

    9098: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    9099: @*/
    9100: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
    9101: {

    9107:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
    9108:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
    9109:   return(0);
    9110: }

    9112: /*@C
    9113:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
    9114:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

    9116:   Collective on dm

    9118:   Input parameters:
    9119: + dm - the pre-adaptation DM object
    9120: - label - label with the flags

    9122:   Output parameters:
    9123: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

    9125:   Level: intermediate

    9127: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
    9128: @*/
    9129: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
    9130: {

    9137:   *dmAdapt = NULL;
    9138:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
    9139:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
    9140:   if (*dmAdapt) {
    9141:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
    9142:     PetscFree((*dmAdapt)->vectype);
    9143:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
    9144:     PetscFree((*dmAdapt)->mattype);
    9145:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
    9146:   }
    9147:   return(0);
    9148: }

    9150: /*@C
    9151:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

    9153:   Input Parameters:
    9154: + dm - The DM object
    9155: . metric - The metric to which the mesh is adapted, defined vertex-wise.
    9156: - bdLabel - Label for boundary tags, which will be preserved in the output mesh. bdLabel should be NULL if there is no such label, and should be different from "_boundary_".

    9158:   Output Parameter:
    9159: . dmAdapt  - Pointer to the DM object containing the adapted mesh

    9161:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

    9163:   Level: advanced

    9165: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
    9166: @*/
    9167: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
    9168: {

    9176:   *dmAdapt = NULL;
    9177:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
    9178:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
    9179:   return(0);
    9180: }

    9182: /*@C
    9183:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

    9185:  Not Collective

    9187:  Input Parameter:
    9188: .  dm    - The DM

    9190:  Output Parameters:
    9191: +  nranks - the number of neighbours
    9192: -  ranks - the neighbors ranks

    9194:  Notes:
    9195:  Do not free the array, it is freed when the DM is destroyed.

    9197:  Level: beginner

    9199:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
    9200: @*/
    9201: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
    9202: {

    9207:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
    9208:   (dm->ops->getneighbors)(dm,nranks,ranks);
    9209:   return(0);
    9210: }

    9212: #include <petsc/private/matimpl.h>

    9214: /*
    9215:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
    9216:     This has be a different function because it requires DM which is not defined in the Mat library
    9217: */
    9218: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
    9219: {

    9223:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9224:     Vec x1local;
    9225:     DM  dm;
    9226:     MatGetDM(J,&dm);
    9227:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
    9228:     DMGetLocalVector(dm,&x1local);
    9229:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
    9230:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
    9231:     x1   = x1local;
    9232:   }
    9233:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
    9234:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9235:     DM  dm;
    9236:     MatGetDM(J,&dm);
    9237:     DMRestoreLocalVector(dm,&x1);
    9238:   }
    9239:   return(0);
    9240: }

    9242: /*@
    9243:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

    9245:     Input Parameter:
    9246: .    coloring - the MatFDColoring object

    9248:     Developer Notes:
    9249:     this routine exists because the PETSc Mat library does not know about the DM objects

    9251:     Level: advanced

    9253: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
    9254: @*/
    9255: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
    9256: {
    9258:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
    9259:   return(0);
    9260: }

    9262: /*@
    9263:     DMGetCompatibility - determine if two DMs are compatible

    9265:     Collective

    9267:     Input Parameters:
    9268: +    dm1 - the first DM
    9269: -    dm2 - the second DM

    9271:     Output Parameters:
    9272: +    compatible - whether or not the two DMs are compatible
    9273: -    set - whether or not the compatible value was set

    9275:     Notes:
    9276:     Two DMs are deemed compatible if they represent the same parallel decomposition
    9277:     of the same topology. This implies that the section (field data) on one
    9278:     "makes sense" with respect to the topology and parallel decomposition of the other.
    9279:     Loosely speaking, compatible DMs represent the same domain and parallel
    9280:     decomposition, but hold different data.

    9282:     Typically, one would confirm compatibility if intending to simultaneously iterate
    9283:     over a pair of vectors obtained from different DMs.

    9285:     For example, two DMDA objects are compatible if they have the same local
    9286:     and global sizes and the same stencil width. They can have different numbers
    9287:     of degrees of freedom per node. Thus, one could use the node numbering from
    9288:     either DM in bounds for a loop over vectors derived from either DM.

    9290:     Consider the operation of summing data living on a 2-dof DMDA to data living
    9291:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
    9292: .vb
    9293:   ...
    9294:   DMGetCompatibility(da1,da2,&compatible,&set);
    9295:   if (set && compatible)  {
    9296:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
    9297:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
    9298:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
    9299:     for (j=y; j<y+n; ++j) {
    9300:       for (i=x; i<x+m, ++i) {
    9301:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
    9302:       }
    9303:     }
    9304:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
    9305:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
    9306:   } else {
    9307:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
    9308:   }
    9309:   ...
    9310: .ve

    9312:     Checking compatibility might be expensive for a given implementation of DM,
    9313:     or might be impossible to unambiguously confirm or deny. For this reason,
    9314:     this function may decline to determine compatibility, and hence users should
    9315:     always check the "set" output parameter.

    9317:     A DM is always compatible with itself.

    9319:     In the current implementation, DMs which live on "unequal" communicators
    9320:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
    9321:     incompatible.

    9323:     This function is labeled "Collective," as information about all subdomains
    9324:     is required on each rank. However, in DM implementations which store all this
    9325:     information locally, this function may be merely "Logically Collective".

    9327:     Developer Notes:
    9328:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
    9329:     iff B is compatible with A. Thus, this function checks the implementations
    9330:     of both dm and dmc (if they are of different types), attempting to determine
    9331:     compatibility. It is left to DM implementers to ensure that symmetry is
    9332:     preserved. The simplest way to do this is, when implementing type-specific
    9333:     logic for this function, is to check for existing logic in the implementation
    9334:     of other DM types and let *set = PETSC_FALSE if found.

    9336:     Level: advanced

    9338: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
    9339: @*/

    9341: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
    9342: {
    9344:   PetscMPIInt    compareResult;
    9345:   DMType         type,type2;
    9346:   PetscBool      sameType;

    9352:   /* Declare a DM compatible with itself */
    9353:   if (dm1 == dm2) {
    9354:     *set = PETSC_TRUE;
    9355:     *compatible = PETSC_TRUE;
    9356:     return(0);
    9357:   }

    9359:   /* Declare a DM incompatible with a DM that lives on an "unequal"
    9360:      communicator. Note that this does not preclude compatibility with
    9361:      DMs living on "congruent" or "similar" communicators, but this must be
    9362:      determined by the implementation-specific logic */
    9363:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
    9364:   if (compareResult == MPI_UNEQUAL) {
    9365:     *set = PETSC_TRUE;
    9366:     *compatible = PETSC_FALSE;
    9367:     return(0);
    9368:   }

    9370:   /* Pass to the implementation-specific routine, if one exists. */
    9371:   if (dm1->ops->getcompatibility) {
    9372:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
    9373:     if (*set) return(0);
    9374:   }

    9376:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
    9377:      with an implementation of this function from dm2 */
    9378:   DMGetType(dm1,&type);
    9379:   DMGetType(dm2,&type2);
    9380:   PetscStrcmp(type,type2,&sameType);
    9381:   if (!sameType && dm2->ops->getcompatibility) {
    9382:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
    9383:   } else {
    9384:     *set = PETSC_FALSE;
    9385:   }
    9386:   return(0);
    9387: }

    9389: /*@C
    9390:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

    9392:   Logically Collective on DM

    9394:   Input Parameters:
    9395: + DM - the DM
    9396: . f - the monitor function
    9397: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
    9398: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

    9400:   Options Database Keys:
    9401: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
    9402:                             does not cancel those set via the options database.

    9404:   Notes:
    9405:   Several different monitoring routines may be set by calling
    9406:   DMMonitorSet() multiple times; all will be called in the
    9407:   order in which they were set.

    9409:   Fortran Notes:
    9410:   Only a single monitor function can be set for each DM object

    9412:   Level: intermediate

    9414: .seealso: DMMonitorCancel()
    9415: @*/
    9416: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
    9417: {
    9418:   PetscInt       m;

    9423:   for (m = 0; m < dm->numbermonitors; ++m) {
    9424:     PetscBool identical;

    9426:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
    9427:     if (identical) return(0);
    9428:   }
    9429:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
    9430:   dm->monitor[dm->numbermonitors]          = f;
    9431:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
    9432:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
    9433:   return(0);
    9434: }

    9436: /*@
    9437:   DMMonitorCancel - Clears all the monitor functions for a DM object.

    9439:   Logically Collective on DM

    9441:   Input Parameter:
    9442: . dm - the DM

    9444:   Options Database Key:
    9445: . -dm_monitor_cancel - cancels all monitors that have been hardwired
    9446:   into a code by calls to DMonitorSet(), but does not cancel those
    9447:   set via the options database

    9449:   Notes:
    9450:   There is no way to clear one specific monitor from a DM object.

    9452:   Level: intermediate

    9454: .seealso: DMMonitorSet()
    9455: @*/
    9456: PetscErrorCode DMMonitorCancel(DM dm)
    9457: {
    9459:   PetscInt       m;

    9463:   for (m = 0; m < dm->numbermonitors; ++m) {
    9464:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
    9465:   }
    9466:   dm->numbermonitors = 0;
    9467:   return(0);
    9468: }

    9470: /*@C
    9471:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

    9473:   Collective on DM

    9475:   Input Parameters:
    9476: + dm   - DM object you wish to monitor
    9477: . name - the monitor type one is seeking
    9478: . help - message indicating what monitoring is done
    9479: . manual - manual page for the monitor
    9480: . monitor - the monitor function
    9481: - 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

    9483:   Output Parameter:
    9484: . flg - Flag set if the monitor was created

    9486:   Level: developer

    9488: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
    9489:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
    9490:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
    9491:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
    9492:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
    9493:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
    9494:           PetscOptionsFList(), PetscOptionsEList()
    9495: @*/
    9496: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
    9497: {
    9498:   PetscViewer       viewer;
    9499:   PetscViewerFormat format;
    9500:   PetscErrorCode    ierr;

    9504:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
    9505:   if (*flg) {
    9506:     PetscViewerAndFormat *vf;

    9508:     PetscViewerAndFormatCreate(viewer, format, &vf);
    9509:     PetscObjectDereference((PetscObject) viewer);
    9510:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
    9511:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
    9512:   }
    9513:   return(0);
    9514: }

    9516: /*@
    9517:    DMMonitor - runs the user provided monitor routines, if they exist

    9519:    Collective on DM

    9521:    Input Parameters:
    9522: .  dm - The DM

    9524:    Level: developer

    9526: .seealso: DMMonitorSet()
    9527: @*/
    9528: PetscErrorCode DMMonitor(DM dm)
    9529: {
    9530:   PetscInt       m;

    9534:   if (!dm) return(0);
    9536:   for (m = 0; m < dm->numbermonitors; ++m) {
    9537:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
    9538:   }
    9539:   return(0);
    9540: }

    9542: /*@
    9543:   DMComputeError - Computes the error assuming the user has given exact solution functions

    9545:   Collective on DM

    9547:   Input Parameters:
    9548: + dm     - The DM
    9549: - sol    - The solution vector

    9551:   Input/Output Parameter:
    9552: . errors - An array of length Nf, the number of fields, or NULL for no output; on output
    9553:            contains the error in each field

    9555:   Output Parameter:
    9556: . errorVec - A vector to hold the cellwise error (may be NULL)

    9558:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

    9560:   Level: developer

    9562: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
    9563: @*/
    9564: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
    9565: {
    9566:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
    9567:   void            **ctxs;
    9568:   PetscReal         time;
    9569:   PetscInt          Nf, f, Nds, s;
    9570:   PetscErrorCode    ierr;

    9573:   DMGetNumFields(dm, &Nf);
    9574:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
    9575:   DMGetNumDS(dm, &Nds);
    9576:   for (s = 0; s < Nds; ++s) {
    9577:     PetscDS         ds;
    9578:     DMLabel         label;
    9579:     IS              fieldIS;
    9580:     const PetscInt *fields;
    9581:     PetscInt        dsNf;

    9583:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    9584:     PetscDSGetNumFields(ds, &dsNf);
    9585:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
    9586:     for (f = 0; f < dsNf; ++f) {
    9587:       const PetscInt field = fields[f];
    9588:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
    9589:     }
    9590:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
    9591:   }
    9592:   for (f = 0; f < Nf; ++f) {
    9593:     if (!exactSol[f]) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %D", f);
    9594:   }
    9595:   DMGetOutputSequenceNumber(dm, NULL, &time);
    9596:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
    9597:   if (errorVec) {
    9598:     DM             edm;
    9599:     DMPolytopeType ct;
    9600:     PetscBool      simplex;
    9601:     PetscInt       dim, cStart, Nf;

    9603:     DMClone(dm, &edm);
    9604:     DMGetDimension(edm, &dim);
    9605:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
    9606:     DMPlexGetCellType(dm, cStart, &ct);
    9607:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
    9608:     DMGetNumFields(dm, &Nf);
    9609:     for (f = 0; f < Nf; ++f) {
    9610:       PetscFE         fe, efe;
    9611:       PetscQuadrature q;
    9612:       const char     *name;

    9614:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
    9615:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
    9616:       PetscObjectGetName((PetscObject) fe, &name);
    9617:       PetscObjectSetName((PetscObject) efe, name);
    9618:       PetscFEGetQuadrature(fe, &q);
    9619:       PetscFESetQuadrature(efe, q);
    9620:       DMSetField(edm, f, NULL, (PetscObject) efe);
    9621:       PetscFEDestroy(&efe);
    9622:     }
    9623:     DMCreateDS(edm);

    9625:     DMCreateGlobalVector(edm, errorVec);
    9626:     PetscObjectSetName((PetscObject) *errorVec, "Error");
    9627:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
    9628:     DMDestroy(&edm);
    9629:   }
    9630:   PetscFree2(exactSol, ctxs);
    9631:   return(0);
    9632: }

    9634: /*@
    9635:   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM

    9637:   Not collective

    9639:   Input Parameter:
    9640: . dm     - The DM

    9642:   Output Parameter:
    9643: . numAux - The number of auxiliary data vectors

    9645:   Level: advanced

    9647: .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9648: @*/
    9649: PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
    9650: {

    9655:   PetscHMapAuxGetSize(dm->auxData, numAux);
    9656:   return(0);
    9657: }

    9659: /*@
    9660:   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value

    9662:   Not collective

    9664:   Input Parameters:
    9665: + dm     - The DM
    9666: . label  - The DMLabel
    9667: - value  - The label value indicating the region

    9669:   Output Parameter:
    9670: . aux    - The Vec holding auxiliary field data

    9672:   Note: If no auxiliary vector is found for this (label, value), (NULL, 0) is checked as well.

    9674:   Level: advanced

    9676: .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec()
    9677: @*/
    9678: PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec *aux)
    9679: {
    9680:   PetscHashAuxKey key, wild = {NULL, 0};
    9681:   PetscBool       has;
    9682:   PetscErrorCode  ierr;

    9687:   key.label = label;
    9688:   key.value = value;
    9689:   PetscHMapAuxHas(dm->auxData, key, &has);
    9690:   if (has) {PetscHMapAuxGet(dm->auxData, key,  aux);}
    9691:   else     {PetscHMapAuxGet(dm->auxData, wild, aux);}
    9692:   return(0);
    9693: }

    9695: /*@
    9696:   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value

    9698:   Not collective

    9700:   Input Parameters:
    9701: + dm     - The DM
    9702: . label  - The DMLabel
    9703: . value  - The label value indicating the region
    9704: - aux    - The Vec holding auxiliary field data

    9706:   Level: advanced

    9708: .seealso: DMGetAuxiliaryVec()
    9709: @*/
    9710: PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, Vec aux)
    9711: {
    9712:   Vec             old;
    9713:   PetscHashAuxKey key;
    9714:   PetscErrorCode  ierr;

    9719:   key.label = label;
    9720:   key.value = value;
    9721:   PetscHMapAuxGet(dm->auxData, key, &old);
    9722:   PetscObjectReference((PetscObject) aux);
    9723:   PetscObjectDereference((PetscObject) old);
    9724:   if (!aux) {PetscHMapAuxDel(dm->auxData, key);}
    9725:   else      {PetscHMapAuxSet(dm->auxData, key, aux);}
    9726:   return(0);
    9727: }

    9729: /*@C
    9730:   DMGetAuxiliaryLabels - Get the labels and values for all auxiliary vectors in this DM

    9732:   Not collective

    9734:   Input Parameter:
    9735: . dm      - The DM

    9737:   Output Parameters:
    9738: + labels  - The DMLabels for each Vec
    9739: - values  - The label values for each Vec

    9741:   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().

    9743:   Level: advanced

    9745: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9746: @*/
    9747: PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[])
    9748: {
    9749:   PetscHashAuxKey *keys;
    9750:   PetscInt         n, i, off = 0;
    9751:   PetscErrorCode   ierr;

    9757:   DMGetNumAuxiliaryVec(dm, &n);
    9758:   PetscMalloc1(n, &keys);
    9759:   PetscHMapAuxGetKeys(dm->auxData, &off, keys);
    9760:   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value;}
    9761:   PetscFree(keys);
    9762:   return(0);
    9763: }

    9765: /*@
    9766:   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM

    9768:   Not collective

    9770:   Input Parameter:
    9771: . dm    - The DM

    9773:   Output Parameter:
    9774: . dmNew - The new DM, now with the same auxiliary data

    9776:   Level: advanced

    9778: .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec()
    9779: @*/
    9780: PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
    9781: {

    9786:   PetscHMapAuxDestroy(&dmNew->auxData);
    9787:   PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData);
    9788:   return(0);
    9789: }

    9791: /*@C
    9792:   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

    9794:   Not collective

    9796:   Input Parameters:
    9797: + ct         - The DMPolytopeType
    9798: . sourceCone - The source arrangement of faces
    9799: - targetCone - The target arrangement of faces

    9801:   Output Parameters:
    9802: + ornt  - The orientation which will take the source arrangement to the target arrangement
    9803: - found - Flag indicating that a suitable orientation was found

    9805:   Level: advanced

    9807: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation()
    9808: @*/
    9809: PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
    9810: {
    9811:   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
    9812:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
    9813:   PetscInt       o, c;

    9816:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
    9817:   for (o = -nO; o < nO; ++o) {
    9818:     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);

    9820:     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
    9821:     if (c == cS) {*ornt = o; break;}
    9822:   }
    9823:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
    9824:   return(0);
    9825: }

    9827: /*@C
    9828:   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement

    9830:   Not collective

    9832:   Input Parameters:
    9833: + ct         - The DMPolytopeType
    9834: . sourceCone - The source arrangement of faces
    9835: - targetCone - The target arrangement of faces

    9837:   Output Parameters:
    9838: . ornt  - The orientation which will take the source arrangement to the target arrangement

    9840:   Note: This function will fail if no suitable orientation can be found.

    9842:   Level: advanced

    9844: .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation()
    9845: @*/
    9846: PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
    9847: {
    9848:   PetscBool      found;

    9852:   DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found);
    9853:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
    9854:   return(0);
    9855: }

    9857: /*@C
    9858:   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

    9860:   Not collective

    9862:   Input Parameters:
    9863: + ct         - The DMPolytopeType
    9864: . sourceVert - The source arrangement of vertices
    9865: - targetVert - The target arrangement of vertices

    9867:   Output Parameters:
    9868: + ornt  - The orientation which will take the source arrangement to the target arrangement
    9869: - found - Flag indicating that a suitable orientation was found

    9871:   Level: advanced

    9873: .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation()
    9874: @*/
    9875: PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
    9876: {
    9877:   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
    9878:   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
    9879:   PetscInt       o, c;

    9882:   if (!nO) {*ornt = 0; *found = PETSC_TRUE; return(0);}
    9883:   for (o = -nO; o < nO; ++o) {
    9884:     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);

    9886:     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
    9887:     if (c == cS) {*ornt = o; break;}
    9888:   }
    9889:   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
    9890:   return(0);
    9891: }

    9893: /*@C
    9894:   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement

    9896:   Not collective

    9898:   Input Parameters:
    9899: + ct         - The DMPolytopeType
    9900: . sourceCone - The source arrangement of vertices
    9901: - targetCone - The target arrangement of vertices

    9903:   Output Parameters:
    9904: . ornt  - The orientation which will take the source arrangement to the target arrangement

    9906:   Note: This function will fail if no suitable orientation can be found.

    9908:   Level: advanced

    9910: .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation()
    9911: @*/
    9912: PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
    9913: {
    9914:   PetscBool      found;

    9918:   DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found);
    9919:   if (!found) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
    9920:   return(0);
    9921: }

    9923: /*@C
    9924:   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type

    9926:   Not collective

    9928:   Input Parameters:
    9929: + ct    - The DMPolytopeType
    9930: - point - Coordinates of the point

    9932:   Output Parameters:
    9933: . inside  - Flag indicating whether the point is inside the reference cell of given type

    9935:   Level: advanced

    9937: .seealso: DMLocatePoints()
    9938: @*/
    9939: PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
    9940: {
    9941:   PetscReal sum = 0.0;
    9942:   PetscInt  d;

    9945:   *inside = PETSC_TRUE;
    9946:   switch (ct) {
    9947:   case DM_POLYTOPE_TRIANGLE:
    9948:   case DM_POLYTOPE_TETRAHEDRON:
    9949:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
    9950:       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
    9951:       sum += point[d];
    9952:     }
    9953:     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
    9954:     break;
    9955:   case DM_POLYTOPE_QUADRILATERAL:
    9956:   case DM_POLYTOPE_HEXAHEDRON:
    9957:     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
    9958:       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
    9959:     break;
    9960:   default:
    9961:     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
    9962:   }
    9963:   return(0);
    9964: }