Actual source code: dm.c
petsc-3.15.0 2021-03-30
Report Typos and Errors

      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: #if defined(PETSC_HAVE_VALGRIND)
     11: #  include <valgrind/memcheck.h>
     12: #endif

     14: PetscClassId  DM_CLASSID;
     15: PetscClassId  DMLABEL_CLASSID;
     16: 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;

     18: const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DMBoundaryType","DM_BOUNDARY_", NULL};
     19: const char *const DMBoundaryConditionTypes[] = {"INVALID","ESSENTIAL","NATURAL","INVALID","INVALID","ESSENTIAL_FIELD","NATURAL_FIELD","INVALID","INVALID","INVALID","NATURAL_RIEMANN","DMBoundaryConditionType","DM_BC_", NULL};
     20: 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};

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

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

     28:   Collective

     30:   Input Parameter:
     31: . comm - The communicator for the DM object

     33:   Output Parameter:
     34: . dm - The DM object

     36:   Level: beginner

     38: .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE, DMPLEX, DMMOAB, DMNETWORK
     39: @*/
     40: PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
     41: {
     42:   DM             v;
     43:   PetscDS        ds;

     48:   *dm = NULL;
     49:   DMInitializePackage();

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

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

     91:   *dm = v;
     92:   return(0);
     93: }

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

     98:   Collective

    100:   Input Parameter:
    101: . dm - The original DM object

    103:   Output Parameter:
    104: . newdm  - The new DM object

    106:   Level: beginner

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

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

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

    117: @*/
    118: PetscErrorCode DMClone(DM dm, DM *newdm)
    119: {
    120:   PetscSF        sf;
    121:   Vec            coords;
    122:   void          *ctx;
    123:   PetscInt       dim, cdim;

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

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

    183:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
    184:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
    185:   }
    186:   return(0);
    187: }

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

    192:    Logically Collective on da

    194:    Input Parameter:
    195: +  da - initial distributed array
    196: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

    198:    Options Database:
    199: .   -dm_vec_type ctype

    201:    Level: intermediate

    203: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
    204: @*/
    205: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
    206: {

    211:   PetscFree(da->vectype);
    212:   PetscStrallocpy(ctype,(char**)&da->vectype);
    213:   return(0);
    214: }

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

    219:    Logically Collective on da

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

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

    227:    Level: intermediate

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

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

    242:   Not collective

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

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

    250:   Level: intermediate

    252: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    253: @*/
    254: PetscErrorCode VecGetDM(Vec v, DM *dm)
    255: {

    261:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
    262:   return(0);
    263: }

    265: /*@
    266:   VecSetDM - Sets the DM defining the data layout of the vector.

    268:   Not collective

    270:   Input Parameters:
    271: + v - The Vec
    272: - dm - The DM

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

    276:   Level: intermediate

    278: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    279: @*/
    280: PetscErrorCode VecSetDM(Vec v, DM dm)
    281: {

    287:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
    288:   return(0);
    289: }

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

    294:    Logically Collective on dm

    296:    Input Parameters:
    297: +  dm - the DM context
    298: -  ctype - the matrix type

    300:    Options Database:
    301: .   -dm_is_coloring_type - global or local

    303:    Level: intermediate

    305: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
    306:           DMGetISColoringType()
    307: @*/
    308: PetscErrorCode  DMSetISColoringType(DM dm,ISColoringType ctype)
    309: {
    312:   dm->coloringtype = ctype;
    313:   return(0);
    314: }

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

    319:    Logically Collective on dm

    321:    Input Parameter:
    322: .  dm - the DM context

    324:    Output Parameter:
    325: .  ctype - the matrix type

    327:    Options Database:
    328: .   -dm_is_coloring_type - global or local

    330:    Level: intermediate

    332: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(),
    333:           DMGetISColoringType()
    334: @*/
    335: PetscErrorCode  DMGetISColoringType(DM dm,ISColoringType *ctype)
    336: {
    339:   *ctype = dm->coloringtype;
    340:   return(0);
    341: }

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

    346:    Logically Collective on dm

    348:    Input Parameters:
    349: +  dm - the DM context
    350: -  ctype - the matrix type

    352:    Options Database:
    353: .   -dm_mat_type ctype

    355:    Level: intermediate

    357: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
    358: @*/
    359: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
    360: {

    365:   PetscFree(dm->mattype);
    366:   PetscStrallocpy(ctype,(char**)&dm->mattype);
    367:   return(0);
    368: }

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

    373:    Logically Collective on dm

    375:    Input Parameter:
    376: .  dm - the DM context

    378:    Output Parameter:
    379: .  ctype - the matrix type

    381:    Options Database:
    382: .   -dm_mat_type ctype

    384:    Level: intermediate

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

    396: /*@
    397:   MatGetDM - Gets the DM defining the data layout of the matrix

    399:   Not collective

    401:   Input Parameter:
    402: . A - The Mat

    404:   Output Parameter:
    405: . dm - The DM

    407:   Level: intermediate

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

    412: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
    413: @*/
    414: PetscErrorCode MatGetDM(Mat A, DM *dm)
    415: {

    421:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
    422:   return(0);
    423: }

    425: /*@
    426:   MatSetDM - Sets the DM defining the data layout of the matrix

    428:   Not collective

    430:   Input Parameters:
    431: + A - The Mat
    432: - dm - The DM

    434:   Level: intermediate

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

    440: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
    441: @*/
    442: PetscErrorCode MatSetDM(Mat A, DM dm)
    443: {

    449:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
    450:   return(0);
    451: }

    453: /*@C
    454:    DMSetOptionsPrefix - Sets the prefix used for searching for all
    455:    DM options in the database.

    457:    Logically Collective on dm

    459:    Input Parameter:
    460: +  da - the DM context
    461: -  prefix - the prefix to prepend to all option names

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

    467:    Level: advanced

    469: .seealso: DMSetFromOptions()
    470: @*/
    471: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
    472: {

    477:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
    478:   if (dm->sf) {
    479:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
    480:   }
    481:   if (dm->sectionSF) {
    482:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
    483:   }
    484:   return(0);
    485: }

    487: /*@C
    488:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
    489:    DM options in the database.

    491:    Logically Collective on dm

    493:    Input Parameters:
    494: +  dm - the DM context
    495: -  prefix - the prefix string to prepend to all DM option requests

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

    501:    Level: advanced

    503: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
    504: @*/
    505: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
    506: {

    511:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
    512:   return(0);
    513: }

    515: /*@C
    516:    DMGetOptionsPrefix - Gets the prefix used for searching for all
    517:    DM options in the database.

    519:    Not Collective

    521:    Input Parameters:
    522: .  dm - the DM context

    524:    Output Parameters:
    525: .  prefix - pointer to the prefix string used is returned

    527:    Notes:
    528:     On the fortran side, the user should pass in a string 'prefix' of
    529:    sufficient length to hold the prefix.

    531:    Level: advanced

    533: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
    534: @*/
    535: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
    536: {

    541:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
    542:   return(0);
    543: }

    545: static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
    546: {
    547:   PetscInt       refct = ((PetscObject) dm)->refct;

    551:   *ncrefct = 0;
    552:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
    553:     refct--;
    554:     if (recurseCoarse) {
    555:       PetscInt coarseCount;

    557:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
    558:       refct += coarseCount;
    559:     }
    560:   }
    561:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
    562:     refct--;
    563:     if (recurseFine) {
    564:       PetscInt fineCount;

    566:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
    567:       refct += fineCount;
    568:     }
    569:   }
    570:   *ncrefct = refct;
    571:   return(0);
    572: }

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

    580:   /* destroy the labels */
    581:   while (next) {
    582:     DMLabelLink tmp = next->next;

    584:     if (next->label == dm->depthLabel)    dm->depthLabel    = NULL;
    585:     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    586:     DMLabelDestroy(&next->label);
    587:     PetscFree(next);
    588:     next = tmp;
    589:   }
    590:   dm->labels = NULL;
    591:   return(0);
    592: }

    594: /*@C
    595:     DMDestroy - Destroys a vector packer or DM.

    597:     Collective on dm

    599:     Input Parameter:
    600: .   dm - the DM object to destroy

    602:     Level: developer

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

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

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

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

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

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

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

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

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

    717:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
    718:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
    719:   }
    720:   MatFDColoringDestroy(&(*dm)->fd);
    721:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
    722:   PetscFree((*dm)->vectype);
    723:   PetscFree((*dm)->mattype);

    725:   PetscSectionDestroy(&(*dm)->localSection);
    726:   PetscSectionDestroy(&(*dm)->globalSection);
    727:   PetscLayoutDestroy(&(*dm)->map);
    728:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
    729:   MatDestroy(&(*dm)->defaultConstraintMat);
    730:   PetscSFDestroy(&(*dm)->sf);
    731:   PetscSFDestroy(&(*dm)->sectionSF);
    732:   if ((*dm)->useNatural) {
    733:     if ((*dm)->sfNatural) {
    734:       PetscSFDestroy(&(*dm)->sfNatural);
    735:     }
    736:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
    737:   }
    738:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
    739:     DMSetFineDM((*dm)->coarseMesh,NULL);
    740:   }

    742:   DMDestroy(&(*dm)->coarseMesh);
    743:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
    744:     DMSetCoarseDM((*dm)->fineMesh,NULL);
    745:   }
    746:   DMDestroy(&(*dm)->fineMesh);
    747:   DMFieldDestroy(&(*dm)->coordinateField);
    748:   DMDestroy(&(*dm)->coordinateDM);
    749:   VecDestroy(&(*dm)->coordinates);
    750:   VecDestroy(&(*dm)->coordinatesLocal);
    751:   PetscFree((*dm)->L);
    752:   PetscFree((*dm)->maxCell);
    753:   PetscFree((*dm)->bdtype);
    754:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
    755:   DMDestroy(&(*dm)->transformDM);
    756:   VecDestroy(&(*dm)->transform);

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

    763:   if ((*dm)->ops->destroy) {
    764:     (*(*dm)->ops->destroy)(*dm);
    765:   }
    766:   DMMonitorCancel(*dm);
    767:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
    768:   PetscHeaderDestroy(dm);
    769:   return(0);
    770: }

    772: /*@
    773:     DMSetUp - sets up the data structures inside a DM object

    775:     Collective on dm

    777:     Input Parameter:
    778: .   dm - the DM object to setup

    780:     Level: developer

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

    784: @*/
    785: PetscErrorCode  DMSetUp(DM dm)
    786: {

    791:   if (dm->setupcalled) return(0);
    792:   if (dm->ops->setup) {
    793:     (*dm->ops->setup)(dm);
    794:   }
    795:   dm->setupcalled = PETSC_TRUE;
    796:   return(0);
    797: }

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

    802:     Collective on dm

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

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

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

    822:     Level: intermediate

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

    827: @*/
    828: PetscErrorCode DMSetFromOptions(DM dm)
    829: {
    830:   char           typeName[256];
    831:   PetscBool      flg;

    836:   dm->setfromoptionscalled = PETSC_TRUE;
    837:   if (dm->sf) {PetscSFSetFromOptions(dm->sf);}
    838:   if (dm->sectionSF) {PetscSFSetFromOptions(dm->sectionSF);}
    839:   PetscObjectOptionsBegin((PetscObject)dm);
    840:   PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);
    841:   PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);
    842:   if (flg) {
    843:     DMSetVecType(dm,typeName);
    844:   }
    845:   PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);
    846:   if (flg) {
    847:     DMSetMatType(dm,typeName);
    848:   }
    849:   PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","DMSetISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);
    850:   if (dm->ops->setfromoptions) {
    851:     (*dm->ops->setfromoptions)(PetscOptionsObject,dm);
    852:   }
    853:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    854:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) dm);
    855:   PetscOptionsEnd();
    856:   return(0);
    857: }

    859: /*@C
    860:    DMViewFromOptions - View from Options

    862:    Collective on DM

    864:    Input Parameters:
    865: +  dm - the DM object
    866: .  obj - Optional object
    867: -  name - command line option

    869:    Level: intermediate
    870: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
    871: @*/
    872: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
    873: {

    878:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
    879:   return(0);
    880: }

    882: /*@C
    883:     DMView - Views a DM

    885:     Collective on dm

    887:     Input Parameter:
    888: +   dm - the DM object to view
    889: -   v - the viewer

    891:     Level: beginner

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

    895: @*/
    896: PetscErrorCode  DMView(DM dm,PetscViewer v)
    897: {
    898:   PetscErrorCode    ierr;
    899:   PetscBool         isbinary;
    900:   PetscMPIInt       size;
    901:   PetscViewerFormat format;

    905:   if (!v) {
    906:     PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);
    907:   }
    909:   /* Ideally, we would like to have this test on.
    910:      However, it currently breaks socket viz via GLVis.
    911:      During DMView(parallel_mesh,glvis_viewer), each
    912:      process opens a sequential ASCII socket to visualize
    913:      the local mesh, and PetscObjectView(dm,local_socket)
    914:      is internally called inside VecView_GLVis, incurring
    915:      in an error here */
    917:   PetscViewerCheckWritable(v);

    919:   PetscViewerGetFormat(v,&format);
    920:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
    921:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
    922:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
    923:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
    924:   if (isbinary) {
    925:     PetscInt classid = DM_FILE_CLASSID;
    926:     char     type[256];

    928:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
    929:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
    930:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
    931:   }
    932:   if (dm->ops->view) {
    933:     (*dm->ops->view)(dm,v);
    934:   }
    935:   return(0);
    936: }

    938: /*@
    939:     DMCreateGlobalVector - Creates a global vector from a DM object

    941:     Collective on dm

    943:     Input Parameter:
    944: .   dm - the DM object

    946:     Output Parameter:
    947: .   vec - the global vector

    949:     Level: beginner

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

    953: @*/
    954: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
    955: {

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

    966:     VecGetDM(*vec,&vdm);
    967:     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);
    968:   }
    969:   return(0);
    970: }

    972: /*@
    973:     DMCreateLocalVector - Creates a local vector from a DM object

    975:     Not Collective

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

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

    983:     Level: beginner

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

    987: @*/
    988: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
    989: {

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

    1000:     VecGetDM(*vec,&vdm);
    1001:     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);
    1002:   }
    1003:   return(0);
    1004: }

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

    1009:    Collective on dm

    1011:    Input Parameter:
    1012: .  dm - the DM that provides the mapping

    1014:    Output Parameter:
    1015: .  ltog - the mapping

    1017:    Level: intermediate

    1019:    Notes:
    1020:    This mapping can then be used by VecSetLocalToGlobalMapping() or
    1021:    MatSetLocalToGlobalMapping().

    1023: .seealso: DMCreateLocalVector()
    1024: @*/
    1025: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
    1026: {
    1027:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

    1033:   if (!dm->ltogmap) {
    1034:     PetscSection section, sectionGlobal;

    1036:     DMGetLocalSection(dm, &section);
    1037:     if (section) {
    1038:       const PetscInt *cdofs;
    1039:       PetscInt       *ltog;
    1040:       PetscInt        pStart, pEnd, n, p, k, l;

    1042:       DMGetGlobalSection(dm, &sectionGlobal);
    1043:       PetscSectionGetChart(section, &pStart, &pEnd);
    1044:       PetscSectionGetStorageSize(section, &n);
    1045:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
    1046:       for (p = pStart, l = 0; p < pEnd; ++p) {
    1047:         PetscInt bdof, cdof, dof, off, c, cind = 0;

    1049:         /* Should probably use constrained dofs */
    1050:         PetscSectionGetDof(section, p, &dof);
    1051:         PetscSectionGetConstraintDof(section, p, &cdof);
    1052:         PetscSectionGetConstraintIndices(section, p, &cdofs);
    1053:         PetscSectionGetOffset(sectionGlobal, p, &off);
    1054:         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
    1055:         bdof = cdof && (dof-cdof) ? 1 : dof;
    1056:         if (dof) {
    1057:           if (bs < 0)          {bs = bdof;}
    1058:           else if (bs != bdof) {bs = 1;}
    1059:         }
    1060:         for (c = 0; c < dof; ++c, ++l) {
    1061:           if ((cind < cdof) && (c == cdofs[cind])) ltog[l] = off < 0 ? off-c : off+c;
    1062:           else                                     ltog[l] = (off < 0 ? -(off+1) : off) + c;
    1063:         }
    1064:       }
    1065:       /* Must have same blocksize on all procs (some might have no points) */
    1066:       bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; bsLocal[1] = bs;
    1067:       PetscGlobalMinMaxInt(PetscObjectComm((PetscObject) dm), bsLocal, bsMinMax);
    1068:       if (bsMinMax[0] != bsMinMax[1]) {bs = 1;}
    1069:       else                            {bs = bsMinMax[0];}
    1070:       bs = bs < 0 ? 1 : bs;
    1071:       /* Must reduce indices by blocksize */
    1072:       if (bs > 1) {
    1073:         for (l = 0, k = 0; l < n; l += bs, ++k) ltog[k] = ltog[l]/bs;
    1074:         n /= bs;
    1075:       }
    1076:       ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap);
    1077:       PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);
    1078:     } else {
    1079:       if (!dm->ops->getlocaltoglobalmapping) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetLocalToGlobalMapping",((PetscObject)dm)->type_name);
    1080:       (*dm->ops->getlocaltoglobalmapping)(dm);
    1081:     }
    1082:   }
    1083:   *ltog = dm->ltogmap;
    1084:   return(0);
    1085: }

    1087: /*@
    1088:    DMGetBlockSize - Gets the inherent block size associated with a DM

    1090:    Not Collective

    1092:    Input Parameter:
    1093: .  dm - the DM with block structure

    1095:    Output Parameter:
    1096: .  bs - the block size, 1 implies no exploitable block structure

    1098:    Level: intermediate

    1100: .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
    1101: @*/
    1102: PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
    1103: {
    1107:   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
    1108:   *bs = dm->bs;
    1109:   return(0);
    1110: }

    1112: /*@C
    1113:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

    1115:     Collective on dmc

    1117:     Input Parameter:
    1118: +   dmc - the DM object
    1119: -   dmf - the second, finer DM object

    1121:     Output Parameter:
    1122: +  mat - the interpolation
    1123: -  vec - the scaling (optional)

    1125:     Level: developer

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

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

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

    1137: @*/
    1138: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
    1139: {

    1146:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
    1147:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
    1148:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
    1149:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
    1150:   return(0);
    1151: }

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

    1156:   Input Parameters:
    1157: +      dac - DM that defines a coarse mesh
    1158: .      daf - DM that defines a fine mesh
    1159: -      mat - the restriction (or interpolation operator) from fine to coarse

    1161:   Output Parameter:
    1162: .    scale - the scaled vector

    1164:   Level: developer

    1166: .seealso: DMCreateInterpolation()

    1168: @*/
    1169: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
    1170: {
    1172:   Vec            fine;
    1173:   PetscScalar    one = 1.0;

    1176:   DMCreateGlobalVector(daf,&fine);
    1177:   DMCreateGlobalVector(dac,scale);
    1178:   VecSet(fine,one);
    1179:   MatRestrict(mat,fine,*scale);
    1180:   VecDestroy(&fine);
    1181:   VecReciprocal(*scale);
    1182:   return(0);
    1183: }

    1185: /*@
    1186:     DMCreateRestriction - Gets restriction matrix between two DM objects

    1188:     Collective on dmc

    1190:     Input Parameter:
    1191: +   dmc - the DM object
    1192: -   dmf - the second, finer DM object

    1194:     Output Parameter:
    1195: .  mat - the restriction

    1198:     Level: developer

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

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

    1207: @*/
    1208: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
    1209: {

    1216:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
    1217:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
    1218:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
    1219:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
    1220:   return(0);
    1221: }

    1223: /*@
    1224:     DMCreateInjection - Gets injection matrix between two DM objects

    1226:     Collective on dac

    1228:     Input Parameter:
    1229: +   dac - the DM object
    1230: -   daf - the second, finer DM object

    1232:     Output Parameter:
    1233: .   mat - the injection

    1235:     Level: developer

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

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

    1243: @*/
    1244: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
    1245: {

    1252:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
    1253:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
    1254:   (*dac->ops->createinjection)(dac,daf,mat);
    1255:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
    1256:   return(0);
    1257: }

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

    1262:   Collective on dac

    1264:   Input Parameter:
    1265: + dac - the DM object
    1266: - daf - the second, finer DM object

    1268:   Output Parameter:
    1269: . mat - the interpolation

    1271:   Level: developer

    1273: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
    1274: @*/
    1275: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
    1276: {

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

    1288: /*@
    1289:     DMCreateColoring - Gets coloring for a DM

    1291:     Collective on dm

    1293:     Input Parameter:
    1294: +   dm - the DM object
    1295: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

    1297:     Output Parameter:
    1298: .   coloring - the coloring

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

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

    1306:     Level: developer

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

    1310: @*/
    1311: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
    1312: {

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

    1323: /*@
    1324:     DMCreateMatrix - Gets empty Jacobian for a DM

    1326:     Collective on dm

    1328:     Input Parameter:
    1329: .   dm - the DM object

    1331:     Output Parameter:
    1332: .   mat - the empty Jacobian

    1334:     Level: beginner

    1336:     Notes:
    1337:     This properly preallocates the number of nonzeros in the sparse matrix so you
    1338:        do not need to do it yourself.

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

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

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

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

    1351: @*/
    1352: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
    1353: {

    1359:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
    1360:   MatInitializePackage();
    1361:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
    1362:   (*dm->ops->creatematrix)(dm,mat);
    1363:   if (PetscDefined(USE_DEBUG)) {
    1364:     DM mdm;

    1366:     MatGetDM(*mat,&mdm);
    1367:     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);
    1368:   }
    1369:   /* Handle nullspace and near nullspace */
    1370:   if (dm->Nf) {
    1371:     MatNullSpace nullSpace;
    1372:     PetscInt     Nf, f;

    1374:     DMGetNumFields(dm, &Nf);
    1375:     for (f = 0; f < Nf; ++f) {
    1376:       if (dm->nullspaceConstructors[f]) {
    1377:         (*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace);
    1378:         MatSetNullSpace(*mat, nullSpace);
    1379:         MatNullSpaceDestroy(&nullSpace);
    1380:         break;
    1381:       }
    1382:     }
    1383:     for (f = 0; f < Nf; ++f) {
    1384:       if (dm->nearnullspaceConstructors[f]) {
    1385:         (*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace);
    1386:         MatSetNearNullSpace(*mat, nullSpace);
    1387:         MatNullSpaceDestroy(&nullSpace);
    1388:       }
    1389:     }
    1390:   }
    1391:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
    1392:   return(0);
    1393: }

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

    1399:   Logically Collective on dm

    1401:   Input Parameter:
    1402: + dm - the DM
    1403: - only - PETSC_TRUE if only want preallocation

    1405:   Level: developer
    1406: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
    1407: @*/
    1408: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
    1409: {
    1412:   dm->prealloc_only = only;
    1413:   return(0);
    1414: }

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

    1420:   Logically Collective on dm

    1422:   Input Parameter:
    1423: + dm - the DM
    1424: - only - PETSC_TRUE if only want matrix stucture

    1426:   Level: developer
    1427: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
    1428: @*/
    1429: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
    1430: {
    1433:   dm->structure_only = only;
    1434:   return(0);
    1435: }

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

    1440:   Not Collective

    1442:   Input Parameters:
    1443: + dm - the DM object
    1444: . count - The minium size
    1445: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

    1447:   Output Parameter:
    1448: . array - the work array

    1450:   Level: developer

    1452: .seealso DMDestroy(), DMCreate()
    1453: @*/
    1454: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1455: {
    1457:   DMWorkLink     link;
    1458:   PetscMPIInt    dsize;

    1463:   if (dm->workin) {
    1464:     link       = dm->workin;
    1465:     dm->workin = dm->workin->next;
    1466:   } else {
    1467:     PetscNewLog(dm,&link);
    1468:   }
    1469:   MPI_Type_size(dtype,&dsize);
    1470:   if (((size_t)dsize*count) > link->bytes) {
    1471:     PetscFree(link->mem);
    1472:     PetscMalloc(dsize*count,&link->mem);
    1473:     link->bytes = dsize*count;
    1474:   }
    1475:   link->next   = dm->workout;
    1476:   dm->workout  = link;
    1477: #if defined(PETSC_HAVE_VALGRIND)
    1478:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
    1479:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
    1480: #endif
    1481:   *(void**)mem = link->mem;
    1482:   return(0);
    1483: }

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

    1488:   Not Collective

    1490:   Input Parameters:
    1491: + dm - the DM object
    1492: . count - The minium size
    1493: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

    1495:   Output Parameter:
    1496: . array - the work array

    1498:   Level: developer

    1500:   Developer Notes:
    1501:     count and dtype are ignored, they are only needed for DMGetWorkArray()
    1502: .seealso DMDestroy(), DMCreate()
    1503: @*/
    1504: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1505: {
    1506:   DMWorkLink *p,link;

    1511:   for (p=&dm->workout; (link=*p); p=&link->next) {
    1512:     if (link->mem == *(void**)mem) {
    1513:       *p           = link->next;
    1514:       link->next   = dm->workin;
    1515:       dm->workin   = link;
    1516:       *(void**)mem = NULL;
    1517:       return(0);
    1518:     }
    1519:   }
    1520:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
    1521: }

    1523: /*@C
    1524:   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field

    1526:   Logically collective on DM

    1528:   Input Parameters:
    1529: + dm     - The DM
    1530: . field  - The field number for the nullspace
    1531: - nullsp - A callback to create the nullspace

    1533:   Notes:
    1534:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1535: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1536: $ dm        - The present DM
    1537: $ origField - The field number given above, in the original DM
    1538: $ field     - The field number in dm
    1539: $ nullSpace - The nullspace for the given field

    1541:   This function is currently not available from Fortran.

    1543: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
    1544: */
    1545: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
    1546: {
    1549:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
    1550:   dm->nullspaceConstructors[field] = nullsp;
    1551:   return(0);
    1552: }

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

    1557:   Not collective

    1559:   Input Parameters:
    1560: + dm     - The DM
    1561: - field  - The field number for the nullspace

    1563:   Output Parameter:
    1564: . nullsp - A callback to create the nullspace

    1566:   Notes:
    1567:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1568: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1569: $ dm        - The present DM
    1570: $ origField - The field number given above, in the original DM
    1571: $ field     - The field number in dm
    1572: $ nullSpace - The nullspace for the given field

    1574:   This function is currently not available from Fortran.

    1576: .seealso: DMSetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
    1577: */
    1578: PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
    1579: {
    1583:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
    1584:   *nullsp = dm->nullspaceConstructors[field];
    1585:   return(0);
    1586: }

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

    1591:   Logically collective on DM

    1593:   Input Parameters:
    1594: + dm     - The DM
    1595: . field  - The field number for the nullspace
    1596: - nullsp - A callback to create the near-nullspace

    1598:   Notes:
    1599:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1600: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1601: $ dm        - The present DM
    1602: $ origField - The field number given above, in the original DM
    1603: $ field     - The field number in dm
    1604: $ nullSpace - The nullspace for the given field

    1606:   This function is currently not available from Fortran.

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

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

    1622:   Not collective

    1624:   Input Parameters:
    1625: + dm     - The DM
    1626: - field  - The field number for the nullspace

    1628:   Output Parameter:
    1629: . nullsp - A callback to create the near-nullspace

    1631:   Notes:
    1632:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1633: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1634: $ dm        - The present DM
    1635: $ origField - The field number given above, in the original DM
    1636: $ field     - The field number in dm
    1637: $ nullSpace - The nullspace for the given field

    1639:   This function is currently not available from Fortran.

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

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

    1656:   Not collective

    1658:   Input Parameter:
    1659: . dm - the DM object

    1661:   Output Parameters:
    1662: + numFields  - The number of fields (or NULL if not requested)
    1663: . fieldNames - The name for each field (or NULL if not requested)
    1664: - fields     - The global indices for each field (or NULL if not requested)

    1666:   Level: intermediate

    1668:   Notes:
    1669:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
    1670:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
    1671:   PetscFree().

    1673: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
    1674: @*/
    1675: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
    1676: {
    1677:   PetscSection   section, sectionGlobal;

    1682:   if (numFields) {
    1684:     *numFields = 0;
    1685:   }
    1686:   if (fieldNames) {
    1688:     *fieldNames = NULL;
    1689:   }
    1690:   if (fields) {
    1692:     *fields = NULL;
    1693:   }
    1694:   DMGetLocalSection(dm, &section);
    1695:   if (section) {
    1696:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
    1697:     PetscInt nF, f, pStart, pEnd, p;

    1699:     DMGetGlobalSection(dm, &sectionGlobal);
    1700:     PetscSectionGetNumFields(section, &nF);
    1701:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
    1702:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
    1703:     for (f = 0; f < nF; ++f) {
    1704:       fieldSizes[f] = 0;
    1705:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
    1706:     }
    1707:     for (p = pStart; p < pEnd; ++p) {
    1708:       PetscInt gdof;

    1710:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1711:       if (gdof > 0) {
    1712:         for (f = 0; f < nF; ++f) {
    1713:           PetscInt fdof, fcdof, fpdof;

    1715:           PetscSectionGetFieldDof(section, p, f, &fdof);
    1716:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    1717:           fpdof = fdof-fcdof;
    1718:           if (fpdof && fpdof != fieldNc[f]) {
    1719:             /* Layout does not admit a pointwise block size */
    1720:             fieldNc[f] = 1;
    1721:           }
    1722:           fieldSizes[f] += fpdof;
    1723:         }
    1724:       }
    1725:     }
    1726:     for (f = 0; f < nF; ++f) {
    1727:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
    1728:       fieldSizes[f] = 0;
    1729:     }
    1730:     for (p = pStart; p < pEnd; ++p) {
    1731:       PetscInt gdof, goff;

    1733:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1734:       if (gdof > 0) {
    1735:         PetscSectionGetOffset(sectionGlobal, p, &goff);
    1736:         for (f = 0; f < nF; ++f) {
    1737:           PetscInt fdof, fcdof, fc;

    1739:           PetscSectionGetFieldDof(section, p, f, &fdof);
    1740:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    1741:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
    1742:             fieldIndices[f][fieldSizes[f]] = goff++;
    1743:           }
    1744:         }
    1745:       }
    1746:     }
    1747:     if (numFields) *numFields = nF;
    1748:     if (fieldNames) {
    1749:       PetscMalloc1(nF, fieldNames);
    1750:       for (f = 0; f < nF; ++f) {
    1751:         const char *fieldName;

    1753:         PetscSectionGetFieldName(section, f, &fieldName);
    1754:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
    1755:       }
    1756:     }
    1757:     if (fields) {
    1758:       PetscMalloc1(nF, fields);
    1759:       for (f = 0; f < nF; ++f) {
    1760:         PetscInt bs, in[2], out[2];

    1762:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
    1763:         in[0] = -fieldNc[f];
    1764:         in[1] = fieldNc[f];
    1765:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
    1766:         bs    = (-out[0] == out[1]) ? out[1] : 1;
    1767:         ISSetBlockSize((*fields)[f], bs);
    1768:       }
    1769:     }
    1770:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
    1771:   } else if (dm->ops->createfieldis) {
    1772:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
    1773:   }
    1774:   return(0);
    1775: }

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

    1784:   Not collective

    1786:   Input Parameter:
    1787: . dm - the DM object

    1789:   Output Parameters:
    1790: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
    1791: . namelist  - The name for each field (or NULL if not requested)
    1792: . islist    - The global indices for each field (or NULL if not requested)
    1793: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

    1795:   Level: intermediate

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

    1802: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1803: @*/
    1804: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
    1805: {

    1810:   if (len) {
    1812:     *len = 0;
    1813:   }
    1814:   if (namelist) {
    1816:     *namelist = NULL;
    1817:   }
    1818:   if (islist) {
    1820:     *islist = NULL;
    1821:   }
    1822:   if (dmlist) {
    1824:     *dmlist = NULL;
    1825:   }
    1826:   /*
    1827:    Is it a good idea to apply the following check across all impls?
    1828:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
    1829:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
    1830:    */
    1831:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
    1832:   if (!dm->ops->createfielddecomposition) {
    1833:     PetscSection section;
    1834:     PetscInt     numFields, f;

    1836:     DMGetLocalSection(dm, &section);
    1837:     if (section) {PetscSectionGetNumFields(section, &numFields);}
    1838:     if (section && numFields && dm->ops->createsubdm) {
    1839:       if (len) *len = numFields;
    1840:       if (namelist) {PetscMalloc1(numFields,namelist);}
    1841:       if (islist)   {PetscMalloc1(numFields,islist);}
    1842:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
    1843:       for (f = 0; f < numFields; ++f) {
    1844:         const char *fieldName;

    1846:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
    1847:         if (namelist) {
    1848:           PetscSectionGetFieldName(section, f, &fieldName);
    1849:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
    1850:         }
    1851:       }
    1852:     } else {
    1853:       DMCreateFieldIS(dm, len, namelist, islist);
    1854:       /* By default there are no DMs associated with subproblems. */
    1855:       if (dmlist) *dmlist = NULL;
    1856:     }
    1857:   } else {
    1858:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
    1859:   }
    1860:   return(0);
    1861: }

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

    1867:   Not collective

    1869:   Input Parameters:
    1870: + dm        - The DM object
    1871: . numFields - The number of fields in this subproblem
    1872: - fields    - The field numbers of the selected fields

    1874:   Output Parameters:
    1875: + is - The global indices for the subproblem
    1876: - subdm - The DM for the subproblem

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

    1880:   Level: intermediate

    1882: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1883: @*/
    1884: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1885: {

    1893:   if (!dm->ops->createsubdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSubDM",((PetscObject)dm)->type_name);
    1894:   (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);
    1895:   return(0);
    1896: }

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

    1901:   Not collective

    1903:   Input Parameter:
    1904: + dms - The DM objects
    1905: - len - The number of DMs

    1907:   Output Parameters:
    1908: + is - The global indices for the subproblem, or NULL
    1909: - superdm - The DM for the superproblem

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

    1913:   Level: intermediate

    1915: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1916: @*/
    1917: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
    1918: {
    1919:   PetscInt       i;

    1927:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
    1928:   if (len) {
    1929:     DM dm = dms[0];
    1930:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
    1931:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
    1932:   }
    1933:   return(0);
    1934: }

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

    1944:   Not collective

    1946:   Input Parameter:
    1947: . dm - the DM object

    1949:   Output Parameters:
    1950: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
    1951: . namelist    - The name for each subdomain (or NULL if not requested)
    1952: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
    1953: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
    1954: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

    1956:   Level: intermediate

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

    1963: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
    1964: @*/
    1965: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
    1966: {
    1967:   PetscErrorCode      ierr;
    1968:   DMSubDomainHookLink link;
    1969:   PetscInt            i,l;

    1978:   /*
    1979:    Is it a good idea to apply the following check across all impls?
    1980:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
    1981:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
    1982:    */
    1983:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
    1984:   if (dm->ops->createdomaindecomposition) {
    1985:     (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);
    1986:     /* copy subdomain hooks and context over to the subdomain DMs */
    1987:     if (dmlist && *dmlist) {
    1988:       for (i = 0; i < l; i++) {
    1989:         for (link=dm->subdomainhook; link; link=link->next) {
    1990:           if (link->ddhook) {(*link->ddhook)(dm,(*dmlist)[i],link->ctx);}
    1991:         }
    1992:         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
    1993:       }
    1994:     }
    1995:     if (len) *len = l;
    1996:   }
    1997:   return(0);
    1998: }

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

    2004:   Not collective

    2006:   Input Parameters:
    2007: + dm - the DM object
    2008: . n  - the number of subdomain scatters
    2009: - subdms - the local subdomains

    2011:   Output Parameters:
    2012: + n     - the number of scatters returned
    2013: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
    2014: . oscat - scatter from global vector to overlapping global vector entries on subdomain
    2015: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

    2023:   Level: developer

    2025: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    2026: @*/
    2027: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
    2028: {

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

    2039: /*@
    2040:   DMRefine - Refines a DM object

    2042:   Collective on dm

    2044:   Input Parameter:
    2045: + dm   - the DM object
    2046: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    2048:   Output Parameter:
    2049: . dmf - the refined DM, or NULL

    2051:   Options Dtabase Keys:
    2052: . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex

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

    2056:   Level: developer

    2058: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    2059: @*/
    2060: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
    2061: {
    2062:   PetscErrorCode   ierr;
    2063:   DMRefineHookLink link;

    2067:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
    2068:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
    2069:   (*dm->ops->refine)(dm,comm,dmf);
    2070:   if (*dmf) {
    2071:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

    2075:     (*dmf)->ctx       = dm->ctx;
    2076:     (*dmf)->leveldown = dm->leveldown;
    2077:     (*dmf)->levelup   = dm->levelup + 1;

    2079:     DMSetMatType(*dmf,dm->mattype);
    2080:     for (link=dm->refinehook; link; link=link->next) {
    2081:       if (link->refinehook) {
    2082:         (*link->refinehook)(dm,*dmf,link->ctx);
    2083:       }
    2084:     }
    2085:   }
    2086:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
    2087:   return(0);
    2088: }

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

    2093:    Logically Collective

    2095:    Input Arguments:
    2096: +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
    2097: .  refinehook - function to run when setting up a coarser level
    2098: .  interphook - function to run to update data on finer levels (once per SNESSolve())
    2099: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    2104: +  coarse - coarse level DM
    2105: .  fine - fine level DM to interpolate problem to
    2106: -  ctx - optional user-defined function context

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

    2111: +  coarse - coarse level DM
    2112: .  interp - matrix interpolating a coarse-level solution to the finer grid
    2113: .  fine - fine level DM to update
    2114: -  ctx - optional user-defined function context

    2116:    Level: advanced

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

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

    2123:    This function is currently not available from Fortran.

    2125: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2126: @*/
    2127: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2128: {
    2129:   PetscErrorCode   ierr;
    2130:   DMRefineHookLink link,*p;

    2134:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    2135:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
    2136:   }
    2137:   PetscNew(&link);
    2138:   link->refinehook = refinehook;
    2139:   link->interphook = interphook;
    2140:   link->ctx        = ctx;
    2141:   link->next       = NULL;
    2142:   *p               = link;
    2143:   return(0);
    2144: }

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

    2149:    Logically Collective

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

    2157:    Level: advanced

    2159:    Notes:
    2160:    This function does nothing if the hook is not in the list.

    2162:    This function is currently not available from Fortran.

    2164: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2165: @*/
    2166: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2167: {
    2168:   PetscErrorCode   ierr;
    2169:   DMRefineHookLink link,*p;

    2173:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    2174:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
    2175:       link = *p;
    2176:       *p = link->next;
    2177:       PetscFree(link);
    2178:       break;
    2179:     }
    2180:   }
    2181:   return(0);
    2182: }

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

    2187:    Collective if any hooks are

    2189:    Input Arguments:
    2190: +  coarse - coarser DM to use as a base
    2191: .  interp - interpolation matrix, apply using MatInterpolate()
    2192: -  fine - finer DM to update

    2194:    Level: developer

    2196: .seealso: DMRefineHookAdd(), MatInterpolate()
    2197: @*/
    2198: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
    2199: {
    2200:   PetscErrorCode   ierr;
    2201:   DMRefineHookLink link;

    2204:   for (link=fine->refinehook; link; link=link->next) {
    2205:     if (link->interphook) {
    2206:       (*link->interphook)(coarse,interp,fine,link->ctx);
    2207:     }
    2208:   }
    2209:   return(0);
    2210: }

    2212: /*@
    2213:    DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.

    2215:    Collective on DM

    2217:    Input Arguments:
    2218: +  coarse - coarse DM
    2219: .  fine   - fine DM
    2220: .  interp - (optional) the matrix computed by DMCreateInterpolation().  Implementations may not need this, but if it
    2221:             is available it can avoid some recomputation.  If it is provided, MatInterpolate() will be used if
    2222:             the coarse DM does not have a specialized implementation.
    2223: -  coarseSol - solution on the coarse mesh

    2225:    Output Arguments:
    2226: .  fineSol - the interpolation of coarseSol to the fine mesh

    2228:    Level: developer

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

    2235: .seealso DMInterpolate(), DMCreateInterpolation()
    2236: @*/
    2237: PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
    2238: {
    2239:   PetscErrorCode (*interpsol)(DM,DM,Mat,Vec,Vec) = NULL;

    2249:   PetscObjectQueryFunction((PetscObject)coarse,"DMInterpolateSolution_C", &interpsol);
    2250:   if (interpsol) {
    2251:     (*interpsol)(coarse, fine, interp, coarseSol, fineSol);
    2252:   } else if (interp) {
    2253:     MatInterpolate(interp, coarseSol, fineSol);
    2254:   } else SETERRQ1(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
    2255:   return(0);
    2256: }

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

    2261:     Not Collective

    2263:     Input Parameter:
    2264: .   dm - the DM object

    2266:     Output Parameter:
    2267: .   level - number of refinements

    2269:     Level: developer

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

    2273: @*/
    2274: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
    2275: {
    2278:   *level = dm->levelup;
    2279:   return(0);
    2280: }

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

    2285:     Not Collective

    2287:     Input Parameter:
    2288: +   dm - the DM object
    2289: -   level - number of refinements

    2291:     Level: advanced

    2293:     Notes:
    2294:     This value is used by PCMG to determine how many multigrid levels to use

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

    2298: @*/
    2299: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
    2300: {
    2303:   dm->levelup = level;
    2304:   return(0);
    2305: }

    2307: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
    2308: {
    2312:   *tdm = dm->transformDM;
    2313:   return(0);
    2314: }

    2316: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
    2317: {
    2321:   *tv = dm->transform;
    2322:   return(0);
    2323: }

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

    2328:   Input Parameter:
    2329: . dm - The DM

    2331:   Output Parameter:
    2332: . flg - PETSC_TRUE if a basis transformation should be done

    2334:   Level: developer

    2336: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
    2337: @*/
    2338: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
    2339: {
    2340:   Vec            tv;

    2346:   DMGetBasisTransformVec_Internal(dm, &tv);
    2347:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
    2348:   return(0);
    2349: }

    2351: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
    2352: {
    2353:   PetscSection   s, ts;
    2354:   PetscScalar   *ta;
    2355:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

    2359:   DMGetCoordinateDim(dm, &cdim);
    2360:   DMGetLocalSection(dm, &s);
    2361:   PetscSectionGetChart(s, &pStart, &pEnd);
    2362:   PetscSectionGetNumFields(s, &Nf);
    2363:   DMClone(dm, &dm->transformDM);
    2364:   DMGetLocalSection(dm->transformDM, &ts);
    2365:   PetscSectionSetNumFields(ts, Nf);
    2366:   PetscSectionSetChart(ts, pStart, pEnd);
    2367:   for (f = 0; f < Nf; ++f) {
    2368:     PetscSectionGetFieldComponents(s, f, &Nc);
    2369:     /* We could start to label fields by their transformation properties */
    2370:     if (Nc != cdim) continue;
    2371:     for (p = pStart; p < pEnd; ++p) {
    2372:       PetscSectionGetFieldDof(s, p, f, &dof);
    2373:       if (!dof) continue;
    2374:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
    2375:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
    2376:     }
    2377:   }
    2378:   PetscSectionSetUp(ts);
    2379:   DMCreateLocalVector(dm->transformDM, &dm->transform);
    2380:   VecGetArray(dm->transform, &ta);
    2381:   for (p = pStart; p < pEnd; ++p) {
    2382:     for (f = 0; f < Nf; ++f) {
    2383:       PetscSectionGetFieldDof(ts, p, f, &dof);
    2384:       if (dof) {
    2385:         PetscReal          x[3] = {0.0, 0.0, 0.0};
    2386:         PetscScalar       *tva;
    2387:         const PetscScalar *A;

    2389:         /* TODO Get quadrature point for this dual basis vector for coordinate */
    2390:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
    2391:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
    2392:         PetscArraycpy(tva, A, PetscSqr(cdim));
    2393:       }
    2394:     }
    2395:   }
    2396:   VecRestoreArray(dm->transform, &ta);
    2397:   return(0);
    2398: }

    2400: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
    2401: {

    2407:   newdm->transformCtx       = dm->transformCtx;
    2408:   newdm->transformSetUp     = dm->transformSetUp;
    2409:   newdm->transformDestroy   = NULL;
    2410:   newdm->transformGetMatrix = dm->transformGetMatrix;
    2411:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
    2412:   return(0);
    2413: }

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

    2418:    Logically Collective

    2420:    Input Arguments:
    2421: +  dm - the DM
    2422: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
    2423: .  endhook - function to run after DMGlobalToLocalEnd() has completed
    2424: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    2429: +  dm - global DM
    2430: .  g - global vector
    2431: .  mode - mode
    2432: .  l - local vector
    2433: -  ctx - optional user-defined function context

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

    2439: +  global - global DM
    2440: -  ctx - optional user-defined function context

    2442:    Level: advanced

    2444: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2445: @*/
    2446: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
    2447: {
    2448:   PetscErrorCode          ierr;
    2449:   DMGlobalToLocalHookLink link,*p;

    2453:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
    2454:   PetscNew(&link);
    2455:   link->beginhook = beginhook;
    2456:   link->endhook   = endhook;
    2457:   link->ctx       = ctx;
    2458:   link->next      = NULL;
    2459:   *p              = link;
    2460:   return(0);
    2461: }

    2463: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
    2464: {
    2465:   Mat cMat;
    2466:   Vec cVec;
    2467:   PetscSection section, cSec;
    2468:   PetscInt pStart, pEnd, p, dof;

    2473:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    2474:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
    2475:     PetscInt nRows;

    2477:     MatGetSize(cMat,&nRows,NULL);
    2478:     if (nRows <= 0) return(0);
    2479:     DMGetLocalSection(dm,&section);
    2480:     MatCreateVecs(cMat,NULL,&cVec);
    2481:     MatMult(cMat,l,cVec);
    2482:     PetscSectionGetChart(cSec,&pStart,&pEnd);
    2483:     for (p = pStart; p < pEnd; p++) {
    2484:       PetscSectionGetDof(cSec,p,&dof);
    2485:       if (dof) {
    2486:         PetscScalar *vals;
    2487:         VecGetValuesSection(cVec,cSec,p,&vals);
    2488:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
    2489:       }
    2490:     }
    2491:     VecDestroy(&cVec);
    2492:   }
    2493:   return(0);
    2494: }

    2496: /*@
    2497:     DMGlobalToLocal - update local vectors from global vector

    2499:     Neighbor-wise Collective on dm

    2501:     Input Parameters:
    2502: +   dm - the DM object
    2503: .   g - the global vector
    2504: .   mode - INSERT_VALUES or ADD_VALUES
    2505: -   l - the local vector

    2507:     Notes:
    2508:     The communication involved in this update can be overlapped with computation by using
    2509:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

    2511:     Level: beginner

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

    2515: @*/
    2516: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
    2517: {

    2521:   DMGlobalToLocalBegin(dm,g,mode,l);
    2522:   DMGlobalToLocalEnd(dm,g,mode,l);
    2523:   return(0);
    2524: }

    2526: /*@
    2527:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

    2529:     Neighbor-wise Collective on dm

    2531:     Input Parameters:
    2532: +   dm - the DM object
    2533: .   g - the global vector
    2534: .   mode - INSERT_VALUES or ADD_VALUES
    2535: -   l - the local vector

    2537:     Level: intermediate

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

    2541: @*/
    2542: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
    2543: {
    2544:   PetscSF                 sf;
    2545:   PetscErrorCode          ierr;
    2546:   DMGlobalToLocalHookLink link;

    2551:   for (link=dm->gtolhook; link; link=link->next) {
    2552:     if (link->beginhook) {
    2553:       (*link->beginhook)(dm,g,mode,l,link->ctx);
    2554:     }
    2555:   }
    2556:   DMGetSectionSF(dm, &sf);
    2557:   if (sf) {
    2558:     const PetscScalar *gArray;
    2559:     PetscScalar       *lArray;
    2560:     PetscMemType      lmtype,gmtype;

    2562:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2563:     VecGetArrayAndMemType(l, &lArray, &lmtype);
    2564:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
    2565:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE);
    2566:     VecRestoreArrayAndMemType(l, &lArray);
    2567:     VecRestoreArrayReadAndMemType(g, &gArray);
    2568:   } else {
    2569:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
    2570:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2571:   }
    2572:   return(0);
    2573: }

    2575: /*@
    2576:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

    2578:     Neighbor-wise Collective on dm

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

    2586:     Level: intermediate

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

    2590: @*/
    2591: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    2592: {
    2593:   PetscSF                 sf;
    2594:   PetscErrorCode          ierr;
    2595:   const PetscScalar      *gArray;
    2596:   PetscScalar            *lArray;
    2597:   PetscBool               transform;
    2598:   DMGlobalToLocalHookLink link;
    2599:   PetscMemType            lmtype,gmtype;

    2603:   DMGetSectionSF(dm, &sf);
    2604:   DMHasBasisTransform(dm, &transform);
    2605:   if (sf) {
    2606:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

    2608:     VecGetArrayAndMemType(l, &lArray, &lmtype);
    2609:     VecGetArrayReadAndMemType(g, &gArray, &gmtype);
    2610:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray,MPI_REPLACE);
    2611:     VecRestoreArrayAndMemType(l, &lArray);
    2612:     VecRestoreArrayReadAndMemType(g, &gArray);
    2613:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
    2614:   } else {
    2615:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
    2616:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2617:   }
    2618:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
    2619:   for (link=dm->gtolhook; link; link=link->next) {
    2620:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2621:   }
    2622:   return(0);
    2623: }

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

    2628:    Logically Collective

    2630:    Input Arguments:
    2631: +  dm - the DM
    2632: .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
    2633: .  endhook - function to run after DMLocalToGlobalEnd() has completed
    2634: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    2639: +  dm - global DM
    2640: .  l - local vector
    2641: .  mode - mode
    2642: .  g - global vector
    2643: -  ctx - optional user-defined function context

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

    2649: +  global - global DM
    2650: .  l - local vector
    2651: .  mode - mode
    2652: .  g - global vector
    2653: -  ctx - optional user-defined function context

    2655:    Level: advanced

    2657: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2658: @*/
    2659: PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
    2660: {
    2661:   PetscErrorCode          ierr;
    2662:   DMLocalToGlobalHookLink link,*p;

    2666:   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
    2667:   PetscNew(&link);
    2668:   link->beginhook = beginhook;
    2669:   link->endhook   = endhook;
    2670:   link->ctx       = ctx;
    2671:   link->next      = NULL;
    2672:   *p              = link;
    2673:   return(0);
    2674: }

    2676: static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
    2677: {
    2678:   Mat cMat;
    2679:   Vec cVec;
    2680:   PetscSection section, cSec;
    2681:   PetscInt pStart, pEnd, p, dof;

    2686:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    2687:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
    2688:     PetscInt nRows;

    2690:     MatGetSize(cMat,&nRows,NULL);
    2691:     if (nRows <= 0) return(0);
    2692:     DMGetLocalSection(dm,&section);
    2693:     MatCreateVecs(cMat,NULL,&cVec);
    2694:     PetscSectionGetChart(cSec,&pStart,&pEnd);
    2695:     for (p = pStart; p < pEnd; p++) {
    2696:       PetscSectionGetDof(cSec,p,&dof);
    2697:       if (dof) {
    2698:         PetscInt d;
    2699:         PetscScalar *vals;
    2700:         VecGetValuesSection(l,section,p,&vals);
    2701:         VecSetValuesSection(cVec,cSec,p,vals,mode);
    2702:         /* for this to be the true transpose, we have to zero the values that
    2703:          * we just extracted */
    2704:         for (d = 0; d < dof; d++) {
    2705:           vals[d] = 0.;
    2706:         }
    2707:       }
    2708:     }
    2709:     MatMultTransposeAdd(cMat,cVec,l,l);
    2710:     VecDestroy(&cVec);
    2711:   }
    2712:   return(0);
    2713: }
    2714: /*@
    2715:     DMLocalToGlobal - updates global vectors from local vectors

    2717:     Neighbor-wise Collective on dm

    2719:     Input Parameters:
    2720: +   dm - the DM object
    2721: .   l - the local vector
    2722: .   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.
    2723: -   g - the global vector

    2725:     Notes:
    2726:     The communication involved in this update can be overlapped with computation by using
    2727:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

    2732:     Level: beginner

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

    2736: @*/
    2737: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
    2738: {

    2742:   DMLocalToGlobalBegin(dm,l,mode,g);
    2743:   DMLocalToGlobalEnd(dm,l,mode,g);
    2744:   return(0);
    2745: }

    2747: /*@
    2748:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

    2750:     Neighbor-wise Collective on dm

    2752:     Input Parameters:
    2753: +   dm - the DM object
    2754: .   l - the local vector
    2755: .   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.
    2756: -   g - the global vector

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

    2762:     Level: intermediate

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

    2766: @*/
    2767: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
    2768: {
    2769:   PetscSF                 sf;
    2770:   PetscSection            s, gs;
    2771:   DMLocalToGlobalHookLink link;
    2772:   Vec                     tmpl;
    2773:   const PetscScalar      *lArray;
    2774:   PetscScalar            *gArray;
    2775:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
    2776:   PetscErrorCode          ierr;
    2777:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

    2781:   for (link=dm->ltoghook; link; link=link->next) {
    2782:     if (link->beginhook) {
    2783:       (*link->beginhook)(dm,l,mode,g,link->ctx);
    2784:     }
    2785:   }
    2786:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
    2787:   DMGetSectionSF(dm, &sf);
    2788:   DMGetLocalSection(dm, &s);
    2789:   switch (mode) {
    2790:   case INSERT_VALUES:
    2791:   case INSERT_ALL_VALUES:
    2792:   case INSERT_BC_VALUES:
    2793:     isInsert = PETSC_TRUE; break;
    2794:   case ADD_VALUES:
    2795:   case ADD_ALL_VALUES:
    2796:   case ADD_BC_VALUES:
    2797:     isInsert = PETSC_FALSE; break;
    2798:   default:
    2799:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2800:   }
    2801:   if ((sf && !isInsert) || (s && isInsert)) {
    2802:     DMHasBasisTransform(dm, &transform);
    2803:     if (transform) {
    2804:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2805:       VecCopy(l, tmpl);
    2806:       DMPlexLocalToGlobalBasis(dm, tmpl);
    2807:       VecGetArrayRead(tmpl, &lArray);
    2808:     } else if (isInsert) {
    2809:       VecGetArrayRead(l, &lArray);
    2810:     } else {
    2811:       VecGetArrayReadAndMemType(l, &lArray, &lmtype);
    2812:       l_inplace = PETSC_TRUE;
    2813:     }
    2814:     if (s && isInsert) {
    2815:       VecGetArray(g, &gArray);
    2816:     } else {
    2817:       VecGetArrayAndMemType(g, &gArray, &gmtype);
    2818:       g_inplace = PETSC_TRUE;
    2819:     }
    2820:     if (sf && !isInsert) {
    2821:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
    2822:     } else if (s && isInsert) {
    2823:       PetscInt gStart, pStart, pEnd, p;

    2825:       DMGetGlobalSection(dm, &gs);
    2826:       PetscSectionGetChart(s, &pStart, &pEnd);
    2827:       VecGetOwnershipRange(g, &gStart, NULL);
    2828:       for (p = pStart; p < pEnd; ++p) {
    2829:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

    2831:         PetscSectionGetDof(s, p, &dof);
    2832:         PetscSectionGetDof(gs, p, &gdof);
    2833:         PetscSectionGetConstraintDof(s, p, &cdof);
    2834:         PetscSectionGetConstraintDof(gs, p, &gcdof);
    2835:         PetscSectionGetOffset(s, p, &off);
    2836:         PetscSectionGetOffset(gs, p, &goff);
    2837:         /* Ignore off-process data and points with no global data */
    2838:         if (!gdof || goff < 0) continue;
    2839:         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);
    2840:         /* If no constraints are enforced in the global vector */
    2841:         if (!gcdof) {
    2842:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
    2843:           /* If constraints are enforced in the global vector */
    2844:         } else if (cdof == gcdof) {
    2845:           const PetscInt *cdofs;
    2846:           PetscInt        cind = 0;

    2848:           PetscSectionGetConstraintIndices(s, p, &cdofs);
    2849:           for (d = 0, e = 0; d < dof; ++d) {
    2850:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
    2851:             gArray[goff-gStart+e++] = lArray[off+d];
    2852:           }
    2853:         } 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);
    2854:       }
    2855:     }
    2856:     if (g_inplace) {
    2857:       VecRestoreArrayAndMemType(g, &gArray);
    2858:     } else {
    2859:       VecRestoreArray(g, &gArray);
    2860:     }
    2861:     if (transform) {
    2862:       VecRestoreArrayRead(tmpl, &lArray);
    2863:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2864:     } else if (l_inplace) {
    2865:       VecRestoreArrayReadAndMemType(l, &lArray);
    2866:     } else {
    2867:       VecRestoreArrayRead(l, &lArray);
    2868:     }
    2869:   } else {
    2870:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
    2871:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2872:   }
    2873:   return(0);
    2874: }

    2876: /*@
    2877:     DMLocalToGlobalEnd - updates global vectors from local vectors

    2879:     Neighbor-wise Collective on dm

    2881:     Input Parameters:
    2882: +   dm - the DM object
    2883: .   l - the local vector
    2884: .   mode - INSERT_VALUES or ADD_VALUES
    2885: -   g - the global vector

    2887:     Level: intermediate

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

    2891: @*/
    2892: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
    2893: {
    2894:   PetscSF                 sf;
    2895:   PetscSection            s;
    2896:   DMLocalToGlobalHookLink link;
    2897:   PetscBool               isInsert, transform;
    2898:   PetscErrorCode          ierr;

    2902:   DMGetSectionSF(dm, &sf);
    2903:   DMGetLocalSection(dm, &s);
    2904:   switch (mode) {
    2905:   case INSERT_VALUES:
    2906:   case INSERT_ALL_VALUES:
    2907:     isInsert = PETSC_TRUE; break;
    2908:   case ADD_VALUES:
    2909:   case ADD_ALL_VALUES:
    2910:     isInsert = PETSC_FALSE; break;
    2911:   default:
    2912:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2913:   }
    2914:   if (sf && !isInsert) {
    2915:     const PetscScalar *lArray;
    2916:     PetscScalar       *gArray;
    2917:     Vec                tmpl;

    2919:     DMHasBasisTransform(dm, &transform);
    2920:     if (transform) {
    2921:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2922:       VecGetArrayRead(tmpl, &lArray);
    2923:     } else {
    2924:       VecGetArrayReadAndMemType(l, &lArray, NULL);
    2925:     }
    2926:     VecGetArrayAndMemType(g, &gArray, NULL);
    2927:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
    2928:     if (transform) {
    2929:       VecRestoreArrayRead(tmpl, &lArray);
    2930:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2931:     } else {
    2932:       VecRestoreArrayReadAndMemType(l, &lArray);
    2933:     }
    2934:     VecRestoreArrayAndMemType(g, &gArray);
    2935:   } else if (s && isInsert) {
    2936:   } else {
    2937:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
    2938:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2939:   }
    2940:   for (link=dm->ltoghook; link; link=link->next) {
    2941:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2942:   }
    2943:   return(0);
    2944: }

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

    2951:    Neighbor-wise Collective on dm

    2953:    Input Parameters:
    2954: +  dm - the DM object
    2955: .  g - the original local vector
    2956: -  mode - one of INSERT_VALUES or ADD_VALUES

    2958:    Output Parameter:
    2959: .  l  - the local vector with correct ghost values

    2961:    Level: intermediate

    2963:    Notes:
    2964:    The local vectors used here need not be the same as those
    2965:    obtained from DMCreateLocalVector(), BUT they
    2966:    must have the same parallel data layout; they could, for example, be
    2967:    obtained with VecDuplicate() from the DM originating vectors.

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

    2971: @*/
    2972: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
    2973: {
    2974:   PetscErrorCode          ierr;

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

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

    2988:    Neighbor-wise Collective on dm

    2990:    Input Parameters:
    2991: +  da - the DM object
    2992: .  g - the original local vector
    2993: -  mode - one of INSERT_VALUES or ADD_VALUES

    2995:    Output Parameter:
    2996: .  l  - the local vector with correct ghost values

    2998:    Level: intermediate

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

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

    3008: @*/
    3009: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    3010: {
    3011:   PetscErrorCode          ierr;

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

    3021: /*@
    3022:     DMCoarsen - Coarsens a DM object

    3024:     Collective on dm

    3026:     Input Parameter:
    3027: +   dm - the DM object
    3028: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    3030:     Output Parameter:
    3031: .   dmc - the coarsened DM

    3033:     Level: developer

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

    3037: @*/
    3038: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
    3039: {
    3040:   PetscErrorCode    ierr;
    3041:   DMCoarsenHookLink link;

    3045:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
    3046:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
    3047:   (*dm->ops->coarsen)(dm, comm, dmc);
    3048:   if (*dmc) {
    3049:     DMSetCoarseDM(dm,*dmc);
    3050:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
    3051:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
    3052:     (*dmc)->ctx               = dm->ctx;
    3053:     (*dmc)->levelup           = dm->levelup;
    3054:     (*dmc)->leveldown         = dm->leveldown + 1;
    3055:     DMSetMatType(*dmc,dm->mattype);
    3056:     for (link=dm->coarsenhook; link; link=link->next) {
    3057:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
    3058:     }
    3059:   }
    3060:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
    3061:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
    3062:   return(0);
    3063: }

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

    3068:    Logically Collective

    3070:    Input Arguments:
    3071: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
    3072: .  coarsenhook - function to run when setting up a coarser level
    3073: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
    3074: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    3079: +  fine - fine level DM
    3080: .  coarse - coarse level DM to restrict problem to
    3081: -  ctx - optional user-defined function context

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

    3086: +  fine - fine level DM
    3087: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
    3088: .  rscale - scaling vector for restriction
    3089: .  inject - matrix restricting by injection
    3090: .  coarse - coarse level DM to update
    3091: -  ctx - optional user-defined function context

    3093:    Level: advanced

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

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

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

    3103:    This function is currently not available from Fortran.

    3105: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3106: @*/
    3107: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3108: {
    3109:   PetscErrorCode    ierr;
    3110:   DMCoarsenHookLink link,*p;

    3114:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3115:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3116:   }
    3117:   PetscNew(&link);
    3118:   link->coarsenhook  = coarsenhook;
    3119:   link->restricthook = restricthook;
    3120:   link->ctx          = ctx;
    3121:   link->next         = NULL;
    3122:   *p                 = link;
    3123:   return(0);
    3124: }

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

    3129:    Logically Collective

    3131:    Input Arguments:
    3132: +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
    3133: .  coarsenhook - function to run when setting up a coarser level
    3134: .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
    3135: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

    3137:    Level: advanced

    3139:    Notes:
    3140:    This function does nothing if the hook is not in the list.

    3142:    This function is currently not available from Fortran.

    3144: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3145: @*/
    3146: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3147: {
    3148:   PetscErrorCode    ierr;
    3149:   DMCoarsenHookLink link,*p;

    3153:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3154:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3155:       link = *p;
    3156:       *p = link->next;
    3157:       PetscFree(link);
    3158:       break;
    3159:     }
    3160:   }
    3161:   return(0);
    3162: }

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

    3168:    Collective if any hooks are

    3170:    Input Arguments:
    3171: +  fine - finer DM to use as a base
    3172: .  restrct - restriction matrix, apply using MatRestrict()
    3173: .  rscale - scaling vector for restriction
    3174: .  inject - injection matrix, also use MatRestrict()
    3175: -  coarse - coarser DM to update

    3177:    Level: developer

    3179: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3180: @*/
    3181: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
    3182: {
    3183:   PetscErrorCode    ierr;
    3184:   DMCoarsenHookLink link;

    3187:   for (link=fine->coarsenhook; link; link=link->next) {
    3188:     if (link->restricthook) {
    3189:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
    3190:     }
    3191:   }
    3192:   return(0);
    3193: }

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

    3198:    Logically Collective on global

    3200:    Input Arguments:
    3201: +  global - global DM
    3202: .  ddhook - function to run to pass data to the decomposition DM upon its creation
    3203: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
    3204: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

    3207:    Calling sequence for ddhook:
    3208: $    ddhook(DM global,DM block,void *ctx)

    3210: +  global - global DM
    3211: .  block  - block DM
    3212: -  ctx - optional user-defined function context

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

    3217: +  global - global DM
    3218: .  out    - scatter to the outer (with ghost and overlap points) block vector
    3219: .  in     - scatter to block vector values only owned locally
    3220: .  block  - block DM
    3221: -  ctx - optional user-defined function context

    3223:    Level: advanced

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

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

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

    3233:    This function is currently not available from Fortran.

    3235: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3236: @*/
    3237: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3238: {
    3239:   PetscErrorCode      ierr;
    3240:   DMSubDomainHookLink link,*p;

    3244:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3245:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3246:   }
    3247:   PetscNew(&link);
    3248:   link->restricthook = restricthook;
    3249:   link->ddhook       = ddhook;
    3250:   link->ctx          = ctx;
    3251:   link->next         = NULL;
    3252:   *p                 = link;
    3253:   return(0);
    3254: }

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

    3259:    Logically Collective

    3261:    Input Arguments:
    3262: +  global - global DM
    3263: .  ddhook - function to run to pass data to the decomposition DM upon its creation
    3264: .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
    3265: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

    3267:    Level: advanced

    3269:    Notes:

    3271:    This function is currently not available from Fortran.

    3273: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3274: @*/
    3275: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3276: {
    3277:   PetscErrorCode      ierr;
    3278:   DMSubDomainHookLink link,*p;

    3282:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3283:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3284:       link = *p;
    3285:       *p = link->next;
    3286:       PetscFree(link);
    3287:       break;
    3288:     }
    3289:   }
    3290:   return(0);
    3291: }

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

    3296:    Collective if any hooks are

    3298:    Input Arguments:
    3299: +  fine - finer DM to use as a base
    3300: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
    3301: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
    3302: -  coarse - coarer DM to update

    3304:    Level: developer

    3306: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3307: @*/
    3308: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
    3309: {
    3310:   PetscErrorCode      ierr;
    3311:   DMSubDomainHookLink link;

    3314:   for (link=global->subdomainhook; link; link=link->next) {
    3315:     if (link->restricthook) {
    3316:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
    3317:     }
    3318:   }
    3319:   return(0);
    3320: }

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

    3325:     Not Collective

    3327:     Input Parameter:
    3328: .   dm - the DM object

    3330:     Output Parameter:
    3331: .   level - number of coarsenings

    3333:     Level: developer

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

    3337: @*/
    3338: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
    3339: {
    3343:   *level = dm->leveldown;
    3344:   return(0);
    3345: }

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

    3350:     Not Collective

    3352:     Input Parameters:
    3353: +   dm - the DM object
    3354: -   level - number of coarsenings

    3356:     Level: developer

    3358: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    3359: @*/
    3360: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
    3361: {
    3364:   dm->leveldown = level;
    3365:   return(0);
    3366: }

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

    3373:     Collective on dm

    3375:     Input Parameter:
    3376: +   dm - the DM object
    3377: -   nlevels - the number of levels of refinement

    3379:     Output Parameter:
    3380: .   dmf - the refined DM hierarchy

    3382:     Level: developer

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

    3386: @*/
    3387: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
    3388: {

    3393:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3394:   if (nlevels == 0) return(0);
    3396:   if (dm->ops->refinehierarchy) {
    3397:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
    3398:   } else if (dm->ops->refine) {
    3399:     PetscInt i;

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

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

    3412:     Collective on dm

    3414:     Input Parameter:
    3415: +   dm - the DM object
    3416: -   nlevels - the number of levels of coarsening

    3418:     Output Parameter:
    3419: .   dmc - the coarsened DM hierarchy

    3421:     Level: developer

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

    3425: @*/
    3426: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
    3427: {

    3432:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3433:   if (nlevels == 0) return(0);
    3435:   if (dm->ops->coarsenhierarchy) {
    3436:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
    3437:   } else if (dm->ops->coarsen) {
    3438:     PetscInt i;

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

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

    3451:     Not Collective

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

    3457:     Level: intermediate

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

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

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

    3473:     Not Collective

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

    3479:     Level: intermediate

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

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

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

    3495:     Not Collective

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

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

    3503:     Level: intermediate

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

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

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

    3519:     Logically Collective on dm

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

    3525:     Level: intermediate

    3527: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
    3528:          DMSetJacobian()

    3530: @*/
    3531: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
    3532: {
    3535:   dm->ops->computevariablebounds = f;
    3536:   return(0);
    3537: }

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

    3542:     Not Collective

    3544:     Input Parameter:
    3545: .   dm - the DM object to destroy

    3547:     Output Parameter:
    3548: .   flg - PETSC_TRUE if the variable bounds function exists

    3550:     Level: developer

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

    3554: @*/
    3555: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
    3556: {
    3560:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
    3561:   return(0);
    3562: }

    3564: /*@C
    3565:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

    3567:     Logically Collective on dm

    3569:     Input Parameters:
    3570: .   dm - the DM object

    3572:     Output parameters:
    3573: +   xl - lower bound
    3574: -   xu - upper bound

    3576:     Level: advanced

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

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

    3583: @*/
    3584: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
    3585: {

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

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

    3600:     Not Collective

    3602:     Input Parameter:
    3603: .   dm - the DM object

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

    3608:     Level: developer

    3610: .seealso DMCreateColoring()

    3612: @*/
    3613: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
    3614: {
    3618:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
    3619:   return(0);
    3620: }

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

    3625:     Not Collective

    3627:     Input Parameter:
    3628: .   dm - the DM object

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

    3633:     Level: developer

    3635: .seealso DMCreateRestriction()

    3637: @*/
    3638: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
    3639: {
    3643:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
    3644:   return(0);
    3645: }

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

    3651:     Not Collective

    3653:     Input Parameter:
    3654: .   dm - the DM object

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

    3659:     Level: developer

    3661: .seealso DMCreateInjection()

    3663: @*/
    3664: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
    3665: {

    3671:   if (dm->ops->hascreateinjection) {
    3672:     (*dm->ops->hascreateinjection)(dm,flg);
    3673:   } else {
    3674:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
    3675:   }
    3676:   return(0);
    3677: }

    3679: PetscFunctionList DMList              = NULL;
    3680: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

    3682: /*@C
    3683:   DMSetType - Builds a DM, for a particular DM implementation.

    3685:   Collective on dm

    3687:   Input Parameters:
    3688: + dm     - The DM object
    3689: - method - The name of the DM type

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

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

    3697:   Level: intermediate

    3699: .seealso: DMGetType(), DMCreate()
    3700: @*/
    3701: PetscErrorCode  DMSetType(DM dm, DMType method)
    3702: {
    3703:   PetscErrorCode (*r)(DM);
    3704:   PetscBool      match;

    3709:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
    3710:   if (match) return(0);

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

    3716:   if (dm->ops->destroy) {
    3717:     (*dm->ops->destroy)(dm);
    3718:   }
    3719:   PetscMemzero(dm->ops,sizeof(*dm->ops));
    3720:   PetscObjectChangeTypeName((PetscObject)dm,method);
    3721:   (*r)(dm);
    3722:   return(0);
    3723: }

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

    3728:   Not Collective

    3730:   Input Parameter:
    3731: . dm  - The DM

    3733:   Output Parameter:
    3734: . type - The DM type name

    3736:   Level: intermediate

    3738: .seealso: DMSetType(), DMCreate()
    3739: @*/
    3740: PetscErrorCode  DMGetType(DM dm, DMType *type)
    3741: {

    3747:   DMRegisterAll();
    3748:   *type = ((PetscObject)dm)->type_name;
    3749:   return(0);
    3750: }

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

    3755:   Collective on dm

    3757:   Input Parameters:
    3758: + dm - the DM
    3759: - newtype - new DM type (use "same" for the same type)

    3761:   Output Parameter:
    3762: . M - pointer to new DM

    3764:   Notes:
    3765:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
    3766:   the MPI communicator of the generated DM is always the same as the communicator
    3767:   of the input DM.

    3769:   Level: intermediate

    3771: .seealso: DMCreate()
    3772: @*/
    3773: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
    3774: {
    3775:   DM             B;
    3776:   char           convname[256];
    3777:   PetscBool      sametype/*, issame */;

    3784:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
    3785:   /* PetscStrcmp(newtype, "same", &issame); */
    3786:   if (sametype) {
    3787:     *M   = dm;
    3788:     PetscObjectReference((PetscObject) dm);
    3789:     return(0);
    3790:   } else {
    3791:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

    3793:     /*
    3794:        Order of precedence:
    3795:        1) See if a specialized converter is known to the current DM.
    3796:        2) See if a specialized converter is known to the desired DM class.
    3797:        3) See if a good general converter is registered for the desired class
    3798:        4) See if a good general converter is known for the current matrix.
    3799:        5) Use a really basic converter.
    3800:     */

    3802:     /* 1) See if a specialized converter is known to the current DM and the desired class */
    3803:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3804:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3805:     PetscStrlcat(convname,"_",sizeof(convname));
    3806:     PetscStrlcat(convname,newtype,sizeof(convname));
    3807:     PetscStrlcat(convname,"_C",sizeof(convname));
    3808:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
    3809:     if (conv) goto foundconv;

    3811:     /* 2)  See if a specialized converter is known to the desired DM class. */
    3812:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
    3813:     DMSetType(B, newtype);
    3814:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3815:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3816:     PetscStrlcat(convname,"_",sizeof(convname));
    3817:     PetscStrlcat(convname,newtype,sizeof(convname));
    3818:     PetscStrlcat(convname,"_C",sizeof(convname));
    3819:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
    3820:     if (conv) {
    3821:       DMDestroy(&B);
    3822:       goto foundconv;
    3823:     }

    3825: #if 0
    3826:     /* 3) See if a good general converter is registered for the desired class */
    3827:     conv = B->ops->convertfrom;
    3828:     DMDestroy(&B);
    3829:     if (conv) goto foundconv;

    3831:     /* 4) See if a good general converter is known for the current matrix */
    3832:     if (dm->ops->convert) {
    3833:       conv = dm->ops->convert;
    3834:     }
    3835:     if (conv) goto foundconv;
    3836: #endif

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

    3841: foundconv:
    3842:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
    3843:     (*conv)(dm,newtype,M);
    3844:     /* Things that are independent of DM type: We should consult DMClone() here */
    3845:     {
    3846:       PetscBool             isper;
    3847:       const PetscReal      *maxCell, *L;
    3848:       const DMBoundaryType *bd;
    3849:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
    3850:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
    3851:       (*M)->prealloc_only = dm->prealloc_only;
    3852:       PetscFree((*M)->vectype);
    3853:       PetscStrallocpy(dm->vectype,(char**)&(*M)->vectype);
    3854:       PetscFree((*M)->mattype);
    3855:       PetscStrallocpy(dm->mattype,(char**)&(*M)->mattype);
    3856:     }
    3857:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
    3858:   }
    3859:   PetscObjectStateIncrease((PetscObject) *M);
    3860:   return(0);
    3861: }

    3863: /*--------------------------------------------------------------------------------------------------------------------*/

    3865: /*@C
    3866:   DMRegister -  Adds a new DM component implementation

    3868:   Not Collective

    3870:   Input Parameters:
    3871: + name        - The name of a new user-defined creation routine
    3872: - create_func - The creation routine itself

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

    3878:   Sample usage:
    3879: .vb
    3880:     DMRegister("my_da", MyDMCreate);
    3881: .ve

    3883:   Then, your DM type can be chosen with the procedural interface via
    3884: .vb
    3885:     DMCreate(MPI_Comm, DM *);
    3886:     DMSetType(DM,"my_da");
    3887: .ve
    3888:    or at runtime via the option
    3889: .vb
    3890:     -da_type my_da
    3891: .ve

    3893:   Level: advanced

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

    3897: @*/
    3898: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
    3899: {

    3903:   DMInitializePackage();
    3904:   PetscFunctionListAdd(&DMList,sname,function);
    3905:   return(0);
    3906: }

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

    3911:   Collective on viewer

    3913:   Input Parameters:
    3914: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
    3915:            some related function before a call to DMLoad().
    3916: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
    3917:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

    3919:    Level: intermediate

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

    3924:   Notes for advanced users:
    3925:   Most users should not need to know the details of the binary storage
    3926:   format, since DMLoad() and DMView() completely hide these details.
    3927:   But for anyone who's interested, the standard binary matrix storage
    3928:   format is
    3929: .vb
    3930:      has not yet been determined
    3931: .ve

    3933: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
    3934: @*/
    3935: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
    3936: {
    3937:   PetscBool      isbinary, ishdf5;

    3943:   PetscViewerCheckReadable(viewer);
    3944:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
    3945:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
    3946:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
    3947:   if (isbinary) {
    3948:     PetscInt classid;
    3949:     char     type[256];

    3951:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
    3952:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
    3953:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
    3954:     DMSetType(newdm, type);
    3955:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    3956:   } else if (ishdf5) {
    3957:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    3958:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
    3959:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
    3960:   return(0);
    3961: }

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

    3966:   Not collective

    3968:   Input Parameter:
    3969: . dm - the DM

    3971:   Output Parameters:
    3972: + lmin - local minimum coordinates (length coord dim, optional)
    3973: - lmax - local maximim coordinates (length coord dim, optional)

    3975:   Level: beginner

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

    3980: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
    3981: @*/
    3982: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
    3983: {
    3984:   Vec                coords = NULL;
    3985:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
    3986:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
    3987:   const PetscScalar *local_coords;
    3988:   PetscInt           N, Ni;
    3989:   PetscInt           cdim, i, j;
    3990:   PetscErrorCode     ierr;

    3994:   DMGetCoordinateDim(dm, &cdim);
    3995:   DMGetCoordinates(dm, &coords);
    3996:   if (coords) {
    3997:     VecGetArrayRead(coords, &local_coords);
    3998:     VecGetLocalSize(coords, &N);
    3999:     Ni   = N/cdim;
    4000:     for (i = 0; i < Ni; ++i) {
    4001:       for (j = 0; j < 3; ++j) {
    4002:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    4003:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    4004:       }
    4005:     }
    4006:     VecRestoreArrayRead(coords, &local_coords);
    4007:   } else {
    4008:     PetscBool isda;

    4010:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
    4011:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
    4012:   }
    4013:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
    4014:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
    4015:   return(0);
    4016: }

    4018: /*@
    4019:   DMGetBoundingBox - Returns the global bounding box for the DM.

    4021:   Collective

    4023:   Input Parameter:
    4024: . dm - the DM

    4026:   Output Parameters:
    4027: + gmin - global minimum coordinates (length coord dim, optional)
    4028: - gmax - global maximim coordinates (length coord dim, optional)

    4030:   Level: beginner

    4032: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
    4033: @*/
    4034: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
    4035: {
    4036:   PetscReal      lmin[3], lmax[3];
    4037:   PetscInt       cdim;
    4038:   PetscMPIInt    count;

    4043:   DMGetCoordinateDim(dm, &cdim);
    4044:   PetscMPIIntCast(cdim, &count);
    4045:   DMGetLocalBoundingBox(dm, lmin, lmax);
    4046:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
    4047:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
    4048:   return(0);
    4049: }

    4051: /******************************** FEM Support **********************************/

    4053: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
    4054: {
    4055:   PetscInt       f;

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

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

    4072:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
    4073:   for (f = 0; f < rows; ++f) {
    4074:     PetscPrintf(PETSC_COMM_SELF, "  |");
    4075:     for (g = 0; g < cols; ++g) {
    4076:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
    4077:     }
    4078:     PetscPrintf(PETSC_COMM_SELF, " |\n");
    4079:   }
    4080:   return(0);
    4081: }

    4083: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
    4084: {
    4085:   PetscInt          localSize, bs;
    4086:   PetscMPIInt       size;
    4087:   Vec               x, xglob;
    4088:   const PetscScalar *xarray;
    4089:   PetscErrorCode    ierr;

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

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

    4117:   Input Parameter:
    4118: . dm - The DM

    4120:   Output Parameter:
    4121: . section - The PetscSection

    4123:   Options Database Keys:
    4124: . -dm_petscsection_view - View the Section created by the DM

    4126:   Level: advanced

    4128:   Notes:
    4129:   Use DMGetLocalSection() in new code.

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

    4133: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
    4134: @*/
    4135: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
    4136: {

    4140:   DMGetLocalSection(dm,section);
    4141:   return(0);
    4142: }

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

    4147:   Input Parameter:
    4148: . dm - The DM

    4150:   Output Parameter:
    4151: . section - The PetscSection

    4153:   Options Database Keys:
    4154: . -dm_petscsection_view - View the Section created by the DM

    4156:   Level: intermediate

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

    4160: .seealso: DMSetLocalSection(), DMGetGlobalSection()
    4161: @*/
    4162: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
    4163: {

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

    4172:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
    4173:     (*dm->ops->createlocalsection)(dm);
    4174:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
    4175:   }
    4176:   *section = dm->localSection;
    4177:   return(0);
    4178: }

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

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

    4187:   Level: advanced

    4189:   Notes:
    4190:   Use DMSetLocalSection() in new code.

    4192:   Any existing Section will be destroyed

    4194: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
    4195: @*/
    4196: PetscErrorCode DMSetSection(DM dm, PetscSection section)
    4197: {

    4201:   DMSetLocalSection(dm,section);
    4202:   return(0);
    4203: }

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

    4208:   Input Parameters:
    4209: + dm - The DM
    4210: - section - The PetscSection

    4212:   Level: intermediate

    4214:   Note: Any existing Section will be destroyed

    4216: .seealso: DMGetLocalSection(), DMSetGlobalSection()
    4217: @*/
    4218: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
    4219: {
    4220:   PetscInt       numFields = 0;
    4221:   PetscInt       f;

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

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

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

    4250:   not collective

    4252:   Input Parameter:
    4253: . dm - The DM

    4255:   Output Parameter:
    4256: + 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.
    4257: - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section.  Returns NULL if there are no local constraints.

    4259:   Level: advanced

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

    4263: .seealso: DMSetDefaultConstraints()
    4264: @*/
    4265: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
    4266: {

    4271:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
    4272:   if (section) {*section = dm->defaultConstraintSection;}
    4273:   if (mat) {*mat = dm->defaultConstraintMat;}
    4274:   return(0);
    4275: }

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

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

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

    4284:   collective on dm

    4286:   Input Parameters:
    4287: + dm - The DM
    4288: + 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).
    4289: - mat - The Mat that interpolates local constraints: its width should be the layout size of the default section:  NULL indicates no constraints.  Must have a local communicator (PETSC_COMM_SELF or derivative).

    4291:   Level: advanced

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

    4295: .seealso: DMGetDefaultConstraints()
    4296: @*/
    4297: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
    4298: {
    4299:   PetscMPIInt result;

    4304:   if (section) {
    4306:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
    4307:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
    4308:   }
    4309:   if (mat) {
    4311:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
    4312:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
    4313:   }
    4314:   PetscObjectReference((PetscObject)section);
    4315:   PetscSectionDestroy(&dm->defaultConstraintSection);
    4316:   dm->defaultConstraintSection = section;
    4317:   PetscObjectReference((PetscObject)mat);
    4318:   MatDestroy(&dm->defaultConstraintMat);
    4319:   dm->defaultConstraintMat = mat;
    4320:   return(0);
    4321: }

    4323: #if defined(PETSC_USE_DEBUG)
    4324: /*
    4325:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

    4327:   Input Parameters:
    4328: + dm - The DM
    4329: . localSection - PetscSection describing the local data layout
    4330: - globalSection - PetscSection describing the global data layout

    4332:   Level: intermediate

    4334: .seealso: DMGetSectionSF(), DMSetSectionSF()
    4335: */
    4336: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
    4337: {
    4338:   MPI_Comm        comm;
    4339:   PetscLayout     layout;
    4340:   const PetscInt *ranges;
    4341:   PetscInt        pStart, pEnd, p, nroots;
    4342:   PetscMPIInt     size, rank;
    4343:   PetscBool       valid = PETSC_TRUE, gvalid;
    4344:   PetscErrorCode  ierr;

    4347:   PetscObjectGetComm((PetscObject)dm,&comm);
    4349:   MPI_Comm_size(comm, &size);
    4350:   MPI_Comm_rank(comm, &rank);
    4351:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
    4352:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
    4353:   PetscLayoutCreate(comm, &layout);
    4354:   PetscLayoutSetBlockSize(layout, 1);
    4355:   PetscLayoutSetLocalSize(layout, nroots);
    4356:   PetscLayoutSetUp(layout);
    4357:   PetscLayoutGetRanges(layout, &ranges);
    4358:   for (p = pStart; p < pEnd; ++p) {
    4359:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

    4361:     PetscSectionGetDof(localSection, p, &dof);
    4362:     PetscSectionGetOffset(localSection, p, &off);
    4363:     PetscSectionGetConstraintDof(localSection, p, &cdof);
    4364:     PetscSectionGetDof(globalSection, p, &gdof);
    4365:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
    4366:     PetscSectionGetOffset(globalSection, p, &goff);
    4367:     if (!gdof) continue; /* Censored point */
    4368:     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;}
    4369:     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;}
    4370:     if (gdof < 0) {
    4371:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
    4372:       for (d = 0; d < gsize; ++d) {
    4373:         PetscInt offset = -(goff+1) + d, r;

    4375:         PetscFindInt(offset,size+1,ranges,&r);
    4376:         if (r < 0) r = -(r+2);
    4377:         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;}
    4378:       }
    4379:     }
    4380:   }
    4381:   PetscLayoutDestroy(&layout);
    4382:   PetscSynchronizedFlush(comm, NULL);
    4383:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
    4384:   if (!gvalid) {
    4385:     DMView(dm, NULL);
    4386:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
    4387:   }
    4388:   return(0);
    4389: }
    4390: #endif

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

    4395:   Collective on dm

    4397:   Input Parameter:
    4398: . dm - The DM

    4400:   Output Parameter:
    4401: . section - The PetscSection

    4403:   Level: intermediate

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

    4407: .seealso: DMSetLocalSection(), DMGetLocalSection()
    4408: @*/
    4409: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
    4410: {

    4416:   if (!dm->globalSection) {
    4417:     PetscSection s;

    4419:     DMGetLocalSection(dm, &s);
    4420:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
    4421:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
    4422:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
    4423:     PetscLayoutDestroy(&dm->map);
    4424:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
    4425:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
    4426:   }
    4427:   *section = dm->globalSection;
    4428:   return(0);
    4429: }

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

    4434:   Input Parameters:
    4435: + dm - The DM
    4436: - section - The PetscSection, or NULL

    4438:   Level: intermediate

    4440:   Note: Any existing Section will be destroyed

    4442: .seealso: DMGetGlobalSection(), DMSetLocalSection()
    4443: @*/
    4444: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
    4445: {

    4451:   PetscObjectReference((PetscObject)section);
    4452:   PetscSectionDestroy(&dm->globalSection);
    4453:   dm->globalSection = section;
    4454: #if defined(PETSC_USE_DEBUG)
    4455:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
    4456: #endif
    4457:   return(0);
    4458: }

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

    4464:   Input Parameter:
    4465: . dm - The DM

    4467:   Output Parameter:
    4468: . sf - The PetscSF

    4470:   Level: intermediate

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

    4474: .seealso: DMSetSectionSF(), DMCreateSectionSF()
    4475: @*/
    4476: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
    4477: {
    4478:   PetscInt       nroots;

    4484:   if (!dm->sectionSF) {
    4485:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
    4486:   }
    4487:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
    4488:   if (nroots < 0) {
    4489:     PetscSection section, gSection;

    4491:     DMGetLocalSection(dm, &section);
    4492:     if (section) {
    4493:       DMGetGlobalSection(dm, &gSection);
    4494:       DMCreateSectionSF(dm, section, gSection);
    4495:     } else {
    4496:       *sf = NULL;
    4497:       return(0);
    4498:     }
    4499:   }
    4500:   *sf = dm->sectionSF;
    4501:   return(0);
    4502: }

    4504: /*@
    4505:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

    4507:   Input Parameters:
    4508: + dm - The DM
    4509: - sf - The PetscSF

    4511:   Level: intermediate

    4513:   Note: Any previous SF is destroyed

    4515: .seealso: DMGetSectionSF(), DMCreateSectionSF()
    4516: @*/
    4517: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
    4518: {

    4524:   PetscObjectReference((PetscObject) sf);
    4525:   PetscSFDestroy(&dm->sectionSF);
    4526:   dm->sectionSF = sf;
    4527:   return(0);
    4528: }

    4530: /*@C
    4531:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
    4532:   describing the data layout.

    4534:   Input Parameters:
    4535: + dm - The DM
    4536: . localSection - PetscSection describing the local data layout
    4537: - globalSection - PetscSection describing the global data layout

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

    4541:   Level: developer

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

    4547: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
    4548: @*/
    4549: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
    4550: {

    4555:   PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);
    4556:   return(0);
    4557: }

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

    4562:   Input Parameter:
    4563: . dm - The DM

    4565:   Output Parameter:
    4566: . sf - The PetscSF

    4568:   Level: intermediate

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

    4572: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4573: @*/
    4574: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
    4575: {
    4579:   *sf = dm->sf;
    4580:   return(0);
    4581: }

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

    4586:   Input Parameters:
    4587: + dm - The DM
    4588: - sf - The PetscSF

    4590:   Level: intermediate

    4592: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4593: @*/
    4594: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
    4595: {

    4601:   PetscObjectReference((PetscObject) sf);
    4602:   PetscSFDestroy(&dm->sf);
    4603:   dm->sf = sf;
    4604:   return(0);
    4605: }

    4607: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
    4608: {
    4609:   PetscClassId   id;

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

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

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

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

    4644:   Logically collective on dm

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

    4649:   Level: intermediate

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

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

    4670: /*@
    4671:   DMGetNumFields - Get the number of fields in the DM

    4673:   Not collective

    4675:   Input Parameter:
    4676: . dm - The DM

    4678:   Output Parameter:
    4679: . Nf - The number of fields

    4681:   Level: intermediate

    4683: .seealso: DMSetNumFields(), DMSetField()
    4684: @*/
    4685: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
    4686: {
    4690:   *numFields = dm->Nf;
    4691:   return(0);
    4692: }

    4694: /*@
    4695:   DMSetNumFields - Set the number of fields in the DM

    4697:   Logically collective on dm

    4699:   Input Parameters:
    4700: + dm - The DM
    4701: - Nf - The number of fields

    4703:   Level: intermediate

    4705: .seealso: DMGetNumFields(), DMSetField()
    4706: @*/
    4707: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
    4708: {
    4709:   PetscInt       Nf, f;

    4714:   DMGetNumFields(dm, &Nf);
    4715:   for (f = Nf; f < numFields; ++f) {
    4716:     PetscContainer obj;

    4718:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
    4719:     DMAddField(dm, NULL, (PetscObject) obj);
    4720:     PetscContainerDestroy(&obj);
    4721:   }
    4722:   return(0);
    4723: }

    4725: /*@
    4726:   DMGetField - Return the discretization object for a given DM field

    4728:   Not collective

    4730:   Input Parameters:
    4731: + dm - The DM
    4732: - f  - The field number

    4734:   Output Parameters:
    4735: + label - The label indicating the support of the field, or NULL for the entire mesh
    4736: - field - The discretization object

    4738:   Level: intermediate

    4740: .seealso: DMAddField(), DMSetField()
    4741: @*/
    4742: PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
    4743: {
    4747:   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);
    4748:   if (label) *label = dm->fields[f].label;
    4749:   if (field) *field = dm->fields[f].disc;
    4750:   return(0);
    4751: }

    4753: /* Does not clear the DS */
    4754: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4755: {

    4759:   DMFieldEnlarge_Static(dm, f+1);
    4760:   DMLabelDestroy(&dm->fields[f].label);
    4761:   PetscObjectDestroy(&dm->fields[f].disc);
    4762:   dm->fields[f].label = label;
    4763:   dm->fields[f].disc  = field;
    4764:   PetscObjectReference((PetscObject) label);
    4765:   PetscObjectReference((PetscObject) field);
    4766:   return(0);
    4767: }

    4769: /*@
    4770:   DMSetField - Set the discretization object for a given DM field

    4772:   Logically collective on dm

    4774:   Input Parameters:
    4775: + dm    - The DM
    4776: . f     - The field number
    4777: . label - The label indicating the support of the field, or NULL for the entire mesh
    4778: - field - The discretization object

    4780:   Level: intermediate

    4782: .seealso: DMAddField(), DMGetField()
    4783: @*/
    4784: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4785: {

    4792:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    4793:   DMSetField_Internal(dm, f, label, field);
    4794:   DMSetDefaultAdjacency_Private(dm, f, field);
    4795:   DMClearDS(dm);
    4796:   return(0);
    4797: }

    4799: /*@
    4800:   DMAddField - Add the discretization object for the given DM field

    4802:   Logically collective on dm

    4804:   Input Parameters:
    4805: + dm    - The DM
    4806: . label - The label indicating the support of the field, or NULL for the entire mesh
    4807: - field - The discretization object

    4809:   Level: intermediate

    4811: .seealso: DMSetField(), DMGetField()
    4812: @*/
    4813: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
    4814: {
    4815:   PetscInt       Nf = dm->Nf;

    4822:   DMFieldEnlarge_Static(dm, Nf+1);
    4823:   dm->fields[Nf].label = label;
    4824:   dm->fields[Nf].disc  = field;
    4825:   PetscObjectReference((PetscObject) label);
    4826:   PetscObjectReference((PetscObject) field);
    4827:   DMSetDefaultAdjacency_Private(dm, Nf, field);
    4828:   DMClearDS(dm);
    4829:   return(0);
    4830: }

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

    4835:   Logically collective on dm

    4837:   Input Parameters:
    4838: + dm          - The DM
    4839: . f           - The field index
    4840: - avoidTensor - The flag to avoid defining the field on tensor cells

    4842:   Level: intermediate

    4844: .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
    4845: @*/
    4846: PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
    4847: {
    4849:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
    4850:   dm->fields[f].avoidTensor = avoidTensor;
    4851:   return(0);
    4852: }

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

    4857:   Logically collective on dm

    4859:   Input Parameters:
    4860: + dm          - The DM
    4861: - f           - The field index

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

    4866:   Level: intermediate

    4868: .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
    4869: @*/
    4870: PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
    4871: {
    4873:   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
    4874:   *avoidTensor = dm->fields[f].avoidTensor;
    4875:   return(0);
    4876: }

    4878: /*@
    4879:   DMCopyFields - Copy the discretizations for the DM into another DM

    4881:   Collective on dm

    4883:   Input Parameter:
    4884: . dm - The DM

    4886:   Output Parameter:
    4887: . newdm - The DM

    4889:   Level: advanced

    4891: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
    4892: @*/
    4893: PetscErrorCode DMCopyFields(DM dm, DM newdm)
    4894: {
    4895:   PetscInt       Nf, f;

    4899:   if (dm == newdm) return(0);
    4900:   DMGetNumFields(dm, &Nf);
    4901:   DMClearFields(newdm);
    4902:   for (f = 0; f < Nf; ++f) {
    4903:     DMLabel     label;
    4904:     PetscObject field;
    4905:     PetscBool   useCone, useClosure;

    4907:     DMGetField(dm, f, &label, &field);
    4908:     DMSetField(newdm, f, label, field);
    4909:     DMGetAdjacency(dm, f, &useCone, &useClosure);
    4910:     DMSetAdjacency(newdm, f, useCone, useClosure);
    4911:   }
    4912:   return(0);
    4913: }

    4915: /*@
    4916:   DMGetAdjacency - Returns the flags for determining variable influence

    4918:   Not collective

    4920:   Input Parameters:
    4921: + dm - The DM object
    4922: - f  - The field number, or PETSC_DEFAULT for the default adjacency

    4924:   Output Parameter:
    4925: + useCone    - Flag for variable influence starting with the cone operation
    4926: - useClosure - Flag for variable influence using transitive closure

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

    4934:   Level: developer

    4936: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
    4937: @*/
    4938: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
    4939: {
    4944:   if (f < 0) {
    4945:     if (useCone)    *useCone    = dm->adjacency[0];
    4946:     if (useClosure) *useClosure = dm->adjacency[1];
    4947:   } else {
    4948:     PetscInt       Nf;

    4951:     DMGetNumFields(dm, &Nf);
    4952:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
    4953:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
    4954:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
    4955:   }
    4956:   return(0);
    4957: }

    4959: /*@
    4960:   DMSetAdjacency - Set the flags for determining variable influence

    4962:   Not collective

    4964:   Input Parameters:
    4965: + dm         - The DM object
    4966: . f          - The field number
    4967: . useCone    - Flag for variable influence starting with the cone operation
    4968: - useClosure - Flag for variable influence using transitive closure

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

    4976:   Level: developer

    4978: .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
    4979: @*/
    4980: PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
    4981: {
    4984:   if (f < 0) {
    4985:     dm->adjacency[0] = useCone;
    4986:     dm->adjacency[1] = useClosure;
    4987:   } else {
    4988:     PetscInt       Nf;

    4991:     DMGetNumFields(dm, &Nf);
    4992:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
    4993:     dm->fields[f].adjacency[0] = useCone;
    4994:     dm->fields[f].adjacency[1] = useClosure;
    4995:   }
    4996:   return(0);
    4997: }

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

    5002:   Not collective

    5004:   Input Parameters:
    5005: . dm - The DM object

    5007:   Output Parameter:
    5008: + useCone    - Flag for variable influence starting with the cone operation
    5009: - useClosure - Flag for variable influence using transitive closure

    5011:   Notes:
    5012: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
    5013: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
    5014: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

    5016:   Level: developer

    5018: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
    5019: @*/
    5020: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
    5021: {
    5022:   PetscInt       Nf;

    5029:   DMGetNumFields(dm, &Nf);
    5030:   if (!Nf) {
    5031:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    5032:   } else {
    5033:     DMGetAdjacency(dm, 0, useCone, useClosure);
    5034:   }
    5035:   return(0);
    5036: }

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

    5041:   Not collective

    5043:   Input Parameters:
    5044: + dm         - The DM object
    5045: . useCone    - Flag for variable influence starting with the cone operation
    5046: - useClosure - Flag for variable influence using transitive closure

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

    5053:   Level: developer

    5055: .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
    5056: @*/
    5057: PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
    5058: {
    5059:   PetscInt       Nf;

    5064:   DMGetNumFields(dm, &Nf);
    5065:   if (!Nf) {
    5066:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    5067:   } else {
    5068:     DMSetAdjacency(dm, 0, useCone, useClosure);
    5069:   }
    5070:   return(0);
    5071: }

    5073: /* Complete labels that are being used for FEM BC */
    5074: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
    5075: {
    5076:   DMLabel        label;
    5077:   PetscObject    obj;
    5078:   PetscClassId   id;
    5079:   PetscInt       Nbd, bd;
    5080:   PetscBool      isFE      = PETSC_FALSE;
    5081:   PetscBool      duplicate = PETSC_FALSE;

    5085:   DMGetField(dm, field, NULL, &obj);
    5086:   PetscObjectGetClassId(obj, &id);
    5087:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
    5088:   DMGetLabel(dm, labelname, &label);
    5089:   if (isFE && label) {
    5090:     /* Only want to modify label once */
    5091:     PetscDSGetNumBoundary(ds, &Nbd);
    5092:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
    5093:       const char *lname;

    5095:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5096:       PetscStrcmp(lname, labelname, &duplicate);
    5097:       if (duplicate) break;
    5098:     }
    5099:     if (!duplicate) {
    5100:       DM plex;

    5102:       DMConvert(dm, DMPLEX, &plex);
    5103:       if (plex) {DMPlexLabelComplete(plex, label);}
    5104:       DMDestroy(&plex);
    5105:     }
    5106:   }
    5107:   return(0);
    5108: }

    5110: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
    5111: {
    5112:   DMSpace       *tmpd;
    5113:   PetscInt       Nds = dm->Nds, s;

    5117:   if (Nds >= NdsNew) return(0);
    5118:   PetscMalloc1(NdsNew, &tmpd);
    5119:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
    5120:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
    5121:   PetscFree(dm->probs);
    5122:   dm->Nds   = NdsNew;
    5123:   dm->probs = tmpd;
    5124:   return(0);
    5125: }

    5127: /*@
    5128:   DMGetNumDS - Get the number of discrete systems in the DM

    5130:   Not collective

    5132:   Input Parameter:
    5133: . dm - The DM

    5135:   Output Parameter:
    5136: . Nds - The number of PetscDS objects

    5138:   Level: intermediate

    5140: .seealso: DMGetDS(), DMGetCellDS()
    5141: @*/
    5142: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
    5143: {
    5147:   *Nds = dm->Nds;
    5148:   return(0);
    5149: }

    5151: /*@
    5152:   DMClearDS - Remove all discrete systems from the DM

    5154:   Logically collective on dm

    5156:   Input Parameter:
    5157: . dm - The DM

    5159:   Level: intermediate

    5161: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
    5162: @*/
    5163: PetscErrorCode DMClearDS(DM dm)
    5164: {
    5165:   PetscInt       s;

    5170:   for (s = 0; s < dm->Nds; ++s) {
    5171:     PetscDSDestroy(&dm->probs[s].ds);
    5172:     DMLabelDestroy(&dm->probs[s].label);
    5173:     ISDestroy(&dm->probs[s].fields);
    5174:   }
    5175:   PetscFree(dm->probs);
    5176:   dm->probs = NULL;
    5177:   dm->Nds   = 0;
    5178:   return(0);
    5179: }

    5181: /*@
    5182:   DMGetDS - Get the default PetscDS

    5184:   Not collective

    5186:   Input Parameter:
    5187: . dm    - The DM

    5189:   Output Parameter:
    5190: . prob - The default PetscDS

    5192:   Level: intermediate

    5194: .seealso: DMGetCellDS(), DMGetRegionDS()
    5195: @*/
    5196: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
    5197: {

    5203:   if (dm->Nds <= 0) {
    5204:     PetscDS ds;

    5206:     PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);
    5207:     DMSetRegionDS(dm, NULL, NULL, ds);
    5208:     PetscDSDestroy(&ds);
    5209:   }
    5210:   *prob = dm->probs[0].ds;
    5211:   return(0);
    5212: }

    5214: /*@
    5215:   DMGetCellDS - Get the PetscDS defined on a given cell

    5217:   Not collective

    5219:   Input Parameters:
    5220: + dm    - The DM
    5221: - point - Cell for the DS

    5223:   Output Parameter:
    5224: . prob - The PetscDS defined on the given cell

    5226:   Level: developer

    5228: .seealso: DMGetDS(), DMSetRegionDS()
    5229: @*/
    5230: PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
    5231: {
    5232:   PetscDS        probDef = NULL;
    5233:   PetscInt       s;

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

    5244:     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
    5245:     else {
    5246:       DMLabelGetValue(dm->probs[s].label, point, &val);
    5247:       if (val >= 0) {*prob = dm->probs[s].ds; break;}
    5248:     }
    5249:   }
    5250:   if (!*prob) *prob = probDef;
    5251:   return(0);
    5252: }

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

    5257:   Not collective

    5259:   Input Parameters:
    5260: + dm    - The DM
    5261: - label - The DMLabel defining the mesh region, or NULL for the entire mesh

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

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

    5269:   Level: advanced

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

    5282:   for (s = 0; s < Nds; ++s) {
    5283:     if (dm->probs[s].label == label) {
    5284:       if (fields) *fields = dm->probs[s].fields;
    5285:       if (ds)     *ds     = dm->probs[s].ds;
    5286:       return(0);
    5287:     }
    5288:   }
    5289:   return(0);
    5290: }

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

    5295:   Collective on dm

    5297:   Input Parameters:
    5298: + dm     - The DM
    5299: . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
    5300: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
    5301: - prob   - The PetscDS defined on the given cell

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

    5306:   Level: advanced

    5308: .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
    5309: @*/
    5310: PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
    5311: {
    5312:   PetscInt       Nds = dm->Nds, s;

    5319:   for (s = 0; s < Nds; ++s) {
    5320:     if (dm->probs[s].label == label) {
    5321:       PetscDSDestroy(&dm->probs[s].ds);
    5322:       dm->probs[s].ds = ds;
    5323:       return(0);
    5324:     }
    5325:   }
    5326:   DMDSEnlarge_Static(dm, Nds+1);
    5327:   PetscObjectReference((PetscObject) label);
    5328:   PetscObjectReference((PetscObject) fields);
    5329:   PetscObjectReference((PetscObject) ds);
    5330:   if (!label) {
    5331:     /* Put the NULL label at the front, so it is returned as the default */
    5332:     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
    5333:     Nds = 0;
    5334:   }
    5335:   dm->probs[Nds].label  = label;
    5336:   dm->probs[Nds].fields = fields;
    5337:   dm->probs[Nds].ds     = ds;
    5338:   return(0);
    5339: }

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

    5344:   Not collective

    5346:   Input Parameters:
    5347: + dm  - The DM
    5348: - num - The region number, in [0, Nds)

    5350:   Output Parameters:
    5351: + label  - The region label, or NULL
    5352: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
    5353: - ds     - The PetscDS defined on the given region, or NULL

    5355:   Level: advanced

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

    5366:   DMGetNumDS(dm, &Nds);
    5367:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5368:   if (label) {
    5370:     *label = dm->probs[num].label;
    5371:   }
    5372:   if (fields) {
    5374:     *fields = dm->probs[num].fields;
    5375:   }
    5376:   if (ds) {
    5378:     *ds = dm->probs[num].ds;
    5379:   }
    5380:   return(0);
    5381: }

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

    5386:   Not collective

    5388:   Input Parameters:
    5389: + dm     - The DM
    5390: . num    - The region number, in [0, Nds)
    5391: . label  - The region label, or NULL
    5392: . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
    5393: - ds     - The PetscDS defined on the given region, or NULL to prevent setting

    5395:   Level: advanced

    5397: .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
    5398: @*/
    5399: PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
    5400: {
    5401:   PetscInt       Nds;

    5407:   DMGetNumDS(dm, &Nds);
    5408:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5409:   PetscObjectReference((PetscObject) label);
    5410:   DMLabelDestroy(&dm->probs[num].label);
    5411:   dm->probs[num].label = label;
    5412:   if (fields) {
    5414:     PetscObjectReference((PetscObject) fields);
    5415:     ISDestroy(&dm->probs[num].fields);
    5416:     dm->probs[num].fields = fields;
    5417:   }
    5418:   if (ds) {
    5420:     PetscObjectReference((PetscObject) ds);
    5421:     PetscDSDestroy(&dm->probs[num].ds);
    5422:     dm->probs[num].ds = ds;
    5423:   }
    5424:   return(0);
    5425: }

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

    5430:   Not collective

    5432:   Input Parameters:
    5433: + dm  - The DM
    5434: - ds  - The PetscDS defined on the given region

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

    5439:   Level: advanced

    5441: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
    5442: @*/
    5443: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
    5444: {
    5445:   PetscInt       Nds, n;

    5452:   DMGetNumDS(dm, &Nds);
    5453:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
    5454:   if (n >= Nds) *num = -1;
    5455:   else          *num = n;
    5456:   return(0);
    5457: }

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

    5462:   Collective on dm

    5464:   Input Parameter:
    5465: . dm - The DM

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

    5469:   Level: intermediate

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

    5484:   if (!dm->fields) return(0);
    5485:   PetscObjectGetComm((PetscObject) dm, &comm);
    5486:   DMGetCoordinateDim(dm, &dE);
    5487:   /* Determine how many regions we have */
    5488:   PetscMalloc1(Nf, &labelSet);
    5489:   Nl   = 0;
    5490:   Ndef = 0;
    5491:   for (f = 0; f < Nf; ++f) {
    5492:     DMLabel  label = dm->fields[f].label;
    5493:     PetscInt l;

    5495:     if (!label) {++Ndef; continue;}
    5496:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
    5497:     if (l < Nl) continue;
    5498:     labelSet[Nl++] = label;
    5499:   }
    5500:   /* Create default DS if there are no labels to intersect with */
    5501:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5502:   if (!dsDef && Ndef && !Nl) {
    5503:     IS        fields;
    5504:     PetscInt *fld, nf;

    5506:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
    5507:     if (nf) {
    5508:       PetscMalloc1(nf, &fld);
    5509:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
    5510:       ISCreate(PETSC_COMM_SELF, &fields);
    5511:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
    5512:       ISSetType(fields, ISGENERAL);
    5513:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

    5515:       PetscDSCreate(comm, &dsDef);
    5516:       DMSetRegionDS(dm, NULL, fields, dsDef);
    5517:       PetscDSDestroy(&dsDef);
    5518:       ISDestroy(&fields);
    5519:     }
    5520:   }
    5521:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5522:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
    5523:   /* Intersect labels with default fields */
    5524:   if (Ndef && Nl) {
    5525:     DM              plex;
    5526:     DMLabel         cellLabel;
    5527:     IS              fieldIS, allcellIS, defcellIS = NULL;
    5528:     PetscInt       *fields;
    5529:     const PetscInt *cells;
    5530:     PetscInt        depth, nf = 0, n, c;

    5532:     DMConvert(dm, DMPLEX, &plex);
    5533:     DMPlexGetDepth(plex, &depth);
    5534:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
    5535:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
    5536:     for (l = 0; l < Nl; ++l) {
    5537:       DMLabel label = labelSet[l];
    5538:       IS      pointIS;

    5540:       ISDestroy(&defcellIS);
    5541:       DMLabelGetStratumIS(label, 1, &pointIS);
    5542:       ISDifference(allcellIS, pointIS, &defcellIS);
    5543:       ISDestroy(&pointIS);
    5544:     }
    5545:     ISDestroy(&allcellIS);

    5547:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
    5548:     ISGetLocalSize(defcellIS, &n);
    5549:     ISGetIndices(defcellIS, &cells);
    5550:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
    5551:     ISRestoreIndices(defcellIS, &cells);
    5552:     ISDestroy(&defcellIS);
    5553:     DMPlexLabelComplete(plex, cellLabel);

    5555:     PetscMalloc1(Ndef, &fields);
    5556:     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
    5557:     ISCreate(PETSC_COMM_SELF, &fieldIS);
    5558:     PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");
    5559:     ISSetType(fieldIS, ISGENERAL);
    5560:     ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);

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

    5580:     PetscDSCreate(comm, &ds);
    5581:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
    5582:     PetscMalloc1(nf, &fld);
    5583:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !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);
    5588:     DMSetRegionDS(dm, label, fields, ds);
    5589:     ISDestroy(&fields);
    5590:     PetscDSSetCoordinateDimension(ds, dE);
    5591:     {
    5592:       DMPolytopeType ct;
    5593:       PetscInt       lStart, lEnd;
    5594:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

    5596:       DMLabelGetBounds(label, &lStart, &lEnd);
    5597:       if (lStart >= 0) {
    5598:         DMPlexGetCellType(dm, lStart, &ct);
    5599:         switch (ct) {
    5600:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
    5601:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
    5602:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
    5603:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
    5604:             isHybridLocal = PETSC_TRUE;break;
    5605:           default: break;
    5606:         }
    5607:       }
    5608:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
    5609:       PetscDSSetHybrid(ds, isHybrid);
    5610:     }
    5611:     PetscDSDestroy(&ds);
    5612:   }
    5613:   PetscFree(labelSet);
    5614:   /* Set fields in DSes */
    5615:   for (s = 0; s < dm->Nds; ++s) {
    5616:     PetscDS         ds     = dm->probs[s].ds;
    5617:     IS              fields = dm->probs[s].fields;
    5618:     const PetscInt *fld;
    5619:     PetscInt        nf;

    5621:     ISGetLocalSize(fields, &nf);
    5622:     ISGetIndices(fields, &fld);
    5623:     for (f = 0; f < nf; ++f) {
    5624:       PetscObject  disc  = dm->fields[fld[f]].disc;
    5625:       PetscBool    isHybrid;
    5626:       PetscClassId id;

    5628:       PetscDSGetHybrid(ds, &isHybrid);
    5629:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
    5630:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
    5631:       PetscDSSetDiscretization(ds, f, disc);
    5632:       /* We allow people to have placeholder fields and construct the Section by hand */
    5633:       PetscObjectGetClassId(disc, &id);
    5634:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
    5635:     }
    5636:     ISRestoreIndices(fields, &fld);
    5637:   }
    5638:   /* Allow k-jet tabulation */
    5639:   PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg);
    5640:   if (flg) {
    5641:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetJetDegree(dm->probs[s].ds, 0, k);}
    5642:   }
    5643:   /* Setup DSes */
    5644:   if (doSetup) {
    5645:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
    5646:   }
    5647:   return(0);
    5648: }

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

    5653:   Collective on DM

    5655:   Input Parameters:
    5656: + dm   - The DM
    5657: - time - The time

    5659:   Output Parameters:
    5660: + u    - The vector will be filled with exact solution values, or NULL
    5661: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

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

    5665:   Level: developer

    5667: .seealso: PetscDSSetExactSolution()
    5668: @*/
    5669: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
    5670: {
    5671:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
    5672:   void            **ectxs;
    5673:   PetscInt          Nf, Nds, s;
    5674:   PetscErrorCode    ierr;

    5680:   DMGetNumFields(dm, &Nf);
    5681:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
    5682:   DMGetNumDS(dm, &Nds);
    5683:   for (s = 0; s < Nds; ++s) {
    5684:     PetscDS         ds;
    5685:     DMLabel         label;
    5686:     IS              fieldIS;
    5687:     const PetscInt *fields, id = 1;
    5688:     PetscInt        dsNf, f;

    5690:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    5691:     PetscDSGetNumFields(ds, &dsNf);
    5692:     ISGetIndices(fieldIS, &fields);
    5693:     PetscArrayzero(exacts, Nf);
    5694:     PetscArrayzero(ectxs, Nf);
    5695:     if (u) {
    5696:       for (f = 0; f < dsNf; ++f) {
    5697:         const PetscInt field = fields[f];
    5698:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
    5699:       }
    5700:       ISRestoreIndices(fieldIS, &fields);
    5701:       if (label) {
    5702:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
    5703:       } else {
    5704:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
    5705:       }
    5706:     }
    5707:     if (u_t) {
    5708:       PetscArrayzero(exacts, Nf);
    5709:       PetscArrayzero(ectxs, Nf);
    5710:       for (f = 0; f < dsNf; ++f) {
    5711:         const PetscInt field = fields[f];
    5712:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
    5713:       }
    5714:       ISRestoreIndices(fieldIS, &fields);
    5715:       if (label) {
    5716:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5717:       } else {
    5718:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5719:       }
    5720:     }
    5721:   }
    5722:   if (u) {
    5723:     PetscObjectSetName((PetscObject) u, "Exact Solution");
    5724:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
    5725:   }
    5726:   if (u_t) {
    5727:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
    5728:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
    5729:   }
    5730:   PetscFree2(exacts, ectxs);
    5731:   return(0);
    5732: }

    5734: /*@
    5735:   DMCopyDS - Copy the discrete systems for the DM into another DM

    5737:   Collective on dm

    5739:   Input Parameter:
    5740: . dm - The DM

    5742:   Output Parameter:
    5743: . newdm - The DM

    5745:   Level: advanced

    5747: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5748: @*/
    5749: PetscErrorCode DMCopyDS(DM dm, DM newdm)
    5750: {
    5751:   PetscInt       Nds, s;

    5755:   if (dm == newdm) return(0);
    5756:   DMGetNumDS(dm, &Nds);
    5757:   DMClearDS(newdm);
    5758:   for (s = 0; s < Nds; ++s) {
    5759:     DMLabel  label;
    5760:     IS       fields;
    5761:     PetscDS  ds;
    5762:     PetscInt Nbd, bd;

    5764:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
    5765:     DMSetRegionDS(newdm, label, fields, ds);
    5766:     PetscDSGetNumBoundary(ds, &Nbd);
    5767:     for (bd = 0; bd < Nbd; ++bd) {
    5768:       const char *labelname, *name;
    5769:       PetscInt    field;

    5771:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    5772:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5773:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
    5774:     }
    5775:   }
    5776:   return(0);
    5777: }

    5779: /*@
    5780:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

    5782:   Collective on dm

    5784:   Input Parameter:
    5785: . dm - The DM

    5787:   Output Parameter:
    5788: . newdm - The DM

    5790:   Level: advanced

    5792: .seealso: DMCopyFields(), DMCopyDS()
    5793: @*/
    5794: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
    5795: {

    5799:   DMCopyFields(dm, newdm);
    5800:   DMCopyDS(dm, newdm);
    5801:   return(0);
    5802: }

    5804: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
    5805: {
    5806:   DM dm_coord,dmc_coord;
    5808:   Vec coords,ccoords;
    5809:   Mat inject;
    5811:   DMGetCoordinateDM(dm,&dm_coord);
    5812:   DMGetCoordinateDM(dmc,&dmc_coord);
    5813:   DMGetCoordinates(dm,&coords);
    5814:   DMGetCoordinates(dmc,&ccoords);
    5815:   if (coords && !ccoords) {
    5816:     DMCreateGlobalVector(dmc_coord,&ccoords);
    5817:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5818:     DMCreateInjection(dmc_coord,dm_coord,&inject);
    5819:     MatRestrict(inject,coords,ccoords);
    5820:     MatDestroy(&inject);
    5821:     DMSetCoordinates(dmc,ccoords);
    5822:     VecDestroy(&ccoords);
    5823:   }
    5824:   return(0);
    5825: }

    5827: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
    5828: {
    5829:   DM dm_coord,subdm_coord;
    5831:   Vec coords,ccoords,clcoords;
    5832:   VecScatter *scat_i,*scat_g;
    5834:   DMGetCoordinateDM(dm,&dm_coord);
    5835:   DMGetCoordinateDM(subdm,&subdm_coord);
    5836:   DMGetCoordinates(dm,&coords);
    5837:   DMGetCoordinates(subdm,&ccoords);
    5838:   if (coords && !ccoords) {
    5839:     DMCreateGlobalVector(subdm_coord,&ccoords);
    5840:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5841:     DMCreateLocalVector(subdm_coord,&clcoords);
    5842:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
    5843:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
    5844:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5845:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5846:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5847:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5848:     DMSetCoordinates(subdm,ccoords);
    5849:     DMSetCoordinatesLocal(subdm,clcoords);
    5850:     VecScatterDestroy(&scat_i[0]);
    5851:     VecScatterDestroy(&scat_g[0]);
    5852:     VecDestroy(&ccoords);
    5853:     VecDestroy(&clcoords);
    5854:     PetscFree(scat_i);
    5855:     PetscFree(scat_g);
    5856:   }
    5857:   return(0);
    5858: }

    5860: /*@
    5861:   DMGetDimension - Return the topological dimension of the DM

    5863:   Not collective

    5865:   Input Parameter:
    5866: . dm - The DM

    5868:   Output Parameter:
    5869: . dim - The topological dimension

    5871:   Level: beginner

    5873: .seealso: DMSetDimension(), DMCreate()
    5874: @*/
    5875: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
    5876: {
    5880:   *dim = dm->dim;
    5881:   return(0);
    5882: }

    5884: /*@
    5885:   DMSetDimension - Set the topological dimension of the DM

    5887:   Collective on dm

    5889:   Input Parameters:
    5890: + dm - The DM
    5891: - dim - The topological dimension

    5893:   Level: beginner

    5895: .seealso: DMGetDimension(), DMCreate()
    5896: @*/
    5897: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
    5898: {
    5899:   PetscDS        ds;

    5905:   dm->dim = dim;
    5906:   DMGetDS(dm, &ds);
    5907:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
    5908:   return(0);
    5909: }

    5911: /*@
    5912:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

    5914:   Collective on dm

    5916:   Input Parameters:
    5917: + dm - the DM
    5918: - dim - the dimension

    5920:   Output Parameters:
    5921: + pStart - The first point of the given dimension
    5922: - pEnd - The first point following points of the given dimension

    5924:   Note:
    5925:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
    5926:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
    5927:   then the interval is empty.

    5929:   Level: intermediate

    5931: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
    5932: @*/
    5933: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
    5934: {
    5935:   PetscInt       d;

    5940:   DMGetDimension(dm, &d);
    5941:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
    5942:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
    5943:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
    5944:   return(0);
    5945: }

    5947: /*@
    5948:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

    5950:   Collective on dm

    5952:   Input Parameters:
    5953: + dm - the DM
    5954: - c - coordinate vector

    5956:   Notes:
    5957:   The coordinates do include those for ghost points, which are in the local vector.

    5959:   The vector c should be destroyed by the caller.

    5961:   Level: intermediate

    5963: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    5964: @*/
    5965: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
    5966: {

    5972:   PetscObjectReference((PetscObject) c);
    5973:   VecDestroy(&dm->coordinates);
    5974:   dm->coordinates = c;
    5975:   VecDestroy(&dm->coordinatesLocal);
    5976:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
    5977:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
    5978:   return(0);
    5979: }

    5981: /*@
    5982:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

    5984:   Not collective

    5986:    Input Parameters:
    5987: +  dm - the DM
    5988: -  c - coordinate vector

    5990:   Notes:
    5991:   The coordinates of ghost points can be set using DMSetCoordinates()
    5992:   followed by DMGetCoordinatesLocal(). This is intended to enable the
    5993:   setting of ghost coordinates outside of the domain.

    5995:   The vector c should be destroyed by the caller.

    5997:   Level: intermediate

    5999: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
    6000: @*/
    6001: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
    6002: {

    6008:   PetscObjectReference((PetscObject) c);
    6009:   VecDestroy(&dm->coordinatesLocal);

    6011:   dm->coordinatesLocal = c;

    6013:   VecDestroy(&dm->coordinates);
    6014:   return(0);
    6015: }

    6017: /*@
    6018:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

    6020:   Collective on dm

    6022:   Input Parameter:
    6023: . dm - the DM

    6025:   Output Parameter:
    6026: . c - global coordinate vector

    6028:   Note:
    6029:   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
    6030:   destroyed the array will no longer be valid.

    6032:   Each process has only the local coordinates (does NOT have the ghost coordinates).

    6034:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6035:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6037:   Level: intermediate

    6039: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates()
    6040: @*/
    6041: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
    6042: {

    6048:   if (!dm->coordinates && dm->coordinatesLocal) {
    6049:     DM        cdm = NULL;
    6050:     PetscBool localized;

    6052:     DMGetCoordinateDM(dm, &cdm);
    6053:     DMCreateGlobalVector(cdm, &dm->coordinates);
    6054:     DMGetCoordinatesLocalized(dm, &localized);
    6055:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
    6056:     if (localized) {
    6057:       PetscInt cdim;

    6059:       DMGetCoordinateDim(dm, &cdim);
    6060:       VecSetBlockSize(dm->coordinates, cdim);
    6061:     }
    6062:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
    6063:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6064:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6065:   }
    6066:   *c = dm->coordinates;
    6067:   return(0);
    6068: }

    6070: /*@
    6071:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

    6073:   Collective on dm

    6075:   Input Parameter:
    6076: . dm - the DM

    6078:   Level: advanced

    6080: .seealso: DMGetCoordinatesLocalNoncollective()
    6081: @*/
    6082: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
    6083: {

    6088:   if (!dm->coordinatesLocal && dm->coordinates) {
    6089:     DM        cdm = NULL;
    6090:     PetscBool localized;

    6092:     DMGetCoordinateDM(dm, &cdm);
    6093:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
    6094:     DMGetCoordinatesLocalized(dm, &localized);
    6095:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
    6096:     if (localized) {
    6097:       PetscInt cdim;

    6099:       DMGetCoordinateDim(dm, &cdim);
    6100:       VecSetBlockSize(dm->coordinates, cdim);
    6101:     }
    6102:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
    6103:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6104:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6105:   }
    6106:   return(0);
    6107: }

    6109: /*@
    6110:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

    6112:   Collective on dm

    6114:   Input Parameter:
    6115: . dm - the DM

    6117:   Output Parameter:
    6118: . c - coordinate vector

    6120:   Note:
    6121:   This is a borrowed reference, so the user should NOT destroy this vector

    6123:   Each process has the local and ghost coordinates

    6125:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6126:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6128:   Level: intermediate

    6130: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
    6131: @*/
    6132: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
    6133: {

    6139:   DMGetCoordinatesLocalSetUp(dm);
    6140:   *c = dm->coordinatesLocal;
    6141:   return(0);
    6142: }

    6144: /*@
    6145:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

    6147:   Not collective

    6149:   Input Parameter:
    6150: . dm - the DM

    6152:   Output Parameter:
    6153: . c - coordinate vector

    6155:   Level: advanced

    6157: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6158: @*/
    6159: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
    6160: {
    6164:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
    6165:   *c = dm->coordinatesLocal;
    6166:   return(0);
    6167: }

    6169: /*@
    6170:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

    6172:   Not collective

    6174:   Input Parameter:
    6175: + dm - the DM
    6176: - p - the IS of points whose coordinates will be returned

    6178:   Output Parameter:
    6179: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
    6180: - pCoord - the Vec with coordinates of points in p

    6182:   Note:
    6183:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

    6185:   This creates a new vector, so the user SHOULD destroy this vector

    6187:   Each process has the local and ghost coordinates

    6189:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6190:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6192:   Level: advanced

    6194: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6195: @*/
    6196: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
    6197: {
    6198:   PetscSection        cs, newcs;
    6199:   Vec                 coords;
    6200:   const PetscScalar   *arr;
    6201:   PetscScalar         *newarr=NULL;
    6202:   PetscInt            n;
    6203:   PetscErrorCode      ierr;

    6210:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
    6211:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
    6212:   cs = dm->coordinateDM->localSection;
    6213:   coords = dm->coordinatesLocal;
    6214:   VecGetArrayRead(coords, &arr);
    6215:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
    6216:   VecRestoreArrayRead(coords, &arr);
    6217:   if (pCoord) {
    6218:     PetscSectionGetStorageSize(newcs, &n);
    6219:     /* set array in two steps to mimic PETSC_OWN_POINTER */
    6220:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
    6221:     VecReplaceArray(*pCoord, newarr);
    6222:   } else {
    6223:     PetscFree(newarr);
    6224:   }
    6225:   if (pCoordSection) {*pCoordSection = newcs;}
    6226:   else               {PetscSectionDestroy(&newcs);}
    6227:   return(0);
    6228: }

    6230: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
    6231: {

    6237:   if (!dm->coordinateField) {
    6238:     if (dm->ops->createcoordinatefield) {
    6239:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
    6240:     }
    6241:   }
    6242:   *field = dm->coordinateField;
    6243:   return(0);
    6244: }

    6246: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
    6247: {

    6253:   PetscObjectReference((PetscObject)field);
    6254:   DMFieldDestroy(&dm->coordinateField);
    6255:   dm->coordinateField = field;
    6256:   return(0);
    6257: }

    6259: /*@
    6260:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6262:   Collective on dm

    6264:   Input Parameter:
    6265: . dm - the DM

    6267:   Output Parameter:
    6268: . cdm - coordinate DM

    6270:   Level: intermediate

    6272: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6273: @*/
    6274: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
    6275: {

    6281:   if (!dm->coordinateDM) {
    6282:     DM cdm;

    6284:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
    6285:     (*dm->ops->createcoordinatedm)(dm, &cdm);
    6286:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
    6287:      * until the call to CreateCoordinateDM) */
    6288:     DMDestroy(&dm->coordinateDM);
    6289:     dm->coordinateDM = cdm;
    6290:   }
    6291:   *cdm = dm->coordinateDM;
    6292:   return(0);
    6293: }

    6295: /*@
    6296:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6298:   Logically Collective on dm

    6300:   Input Parameters:
    6301: + dm - the DM
    6302: - cdm - coordinate DM

    6304:   Level: intermediate

    6306: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6307: @*/
    6308: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
    6309: {

    6315:   PetscObjectReference((PetscObject)cdm);
    6316:   DMDestroy(&dm->coordinateDM);
    6317:   dm->coordinateDM = cdm;
    6318:   return(0);
    6319: }

    6321: /*@
    6322:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

    6324:   Not Collective

    6326:   Input Parameter:
    6327: . dm - The DM object

    6329:   Output Parameter:
    6330: . dim - The embedding dimension

    6332:   Level: intermediate

    6334: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6335: @*/
    6336: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
    6337: {
    6341:   if (dm->dimEmbed == PETSC_DEFAULT) {
    6342:     dm->dimEmbed = dm->dim;
    6343:   }
    6344:   *dim = dm->dimEmbed;
    6345:   return(0);
    6346: }

    6348: /*@
    6349:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

    6351:   Not Collective

    6353:   Input Parameters:
    6354: + dm  - The DM object
    6355: - dim - The embedding dimension

    6357:   Level: intermediate

    6359: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6360: @*/
    6361: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
    6362: {
    6363:   PetscDS        ds;

    6368:   dm->dimEmbed = dim;
    6369:   DMGetDS(dm, &ds);
    6370:   PetscDSSetCoordinateDimension(ds, dim);
    6371:   return(0);
    6372: }

    6374: /*@
    6375:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

    6377:   Collective on dm

    6379:   Input Parameter:
    6380: . dm - The DM object

    6382:   Output Parameter:
    6383: . section - The PetscSection object

    6385:   Level: intermediate

    6387: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6388: @*/
    6389: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
    6390: {
    6391:   DM             cdm;

    6397:   DMGetCoordinateDM(dm, &cdm);
    6398:   DMGetLocalSection(cdm, section);
    6399:   return(0);
    6400: }

    6402: /*@
    6403:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

    6405:   Not Collective

    6407:   Input Parameters:
    6408: + dm      - The DM object
    6409: . dim     - The embedding dimension, or PETSC_DETERMINE
    6410: - section - The PetscSection object

    6412:   Level: intermediate

    6414: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6415: @*/
    6416: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
    6417: {
    6418:   DM             cdm;

    6424:   DMGetCoordinateDM(dm, &cdm);
    6425:   DMSetLocalSection(cdm, section);
    6426:   if (dim == PETSC_DETERMINE) {
    6427:     PetscInt d = PETSC_DEFAULT;
    6428:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

    6430:     PetscSectionGetChart(section, &pStart, &pEnd);
    6431:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
    6432:     pStart = PetscMax(vStart, pStart);
    6433:     pEnd   = PetscMin(vEnd, pEnd);
    6434:     for (v = pStart; v < pEnd; ++v) {
    6435:       PetscSectionGetDof(section, v, &dd);
    6436:       if (dd) {d = dd; break;}
    6437:     }
    6438:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
    6439:   }
    6440:   return(0);
    6441: }

    6443: /*@
    6444:   DMProjectCoordinates - Project coordinates to a different space

    6446:   Input Parameters:
    6447: + dm      - The DM object
    6448: - disc    - The new coordinate discretization

    6450:   Level: intermediate

    6452: .seealso: DMGetCoordinateField()
    6453: @*/
    6454: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
    6455: {
    6456:   PetscObject    discOld;
    6457:   PetscClassId   classid;
    6458:   DM             cdmOld,cdmNew;
    6459:   Vec            coordsOld,coordsNew;
    6460:   Mat            matInterp;

    6467:   DMGetCoordinateDM(dm, &cdmOld);
    6468:   /* Check current discretization is compatible */
    6469:   DMGetField(cdmOld, 0, NULL, &discOld);
    6470:   PetscObjectGetClassId(discOld, &classid);
    6471:   if (classid != PETSCFE_CLASSID) {
    6472:     if (classid == PETSC_CONTAINER_CLASSID) {
    6473:       PetscFE        feLinear;
    6474:       DMPolytopeType ct;
    6475:       PetscInt       dim, dE, cStart;
    6476:       PetscBool      simplex;

    6478:       /* Assume linear vertex coordinates */
    6479:       DMGetDimension(dm, &dim);
    6480:       DMGetCoordinateDim(dm, &dE);
    6481:       DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);
    6482:       DMPlexGetCellType(dm, cStart, &ct);
    6483:       switch (ct) {
    6484:         case DM_POLYTOPE_TRI_PRISM:
    6485:         case DM_POLYTOPE_TRI_PRISM_TENSOR:
    6486:           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
    6487:         default: break;
    6488:       }
    6489:       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
    6490:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);
    6491:       DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);
    6492:       PetscFEDestroy(&feLinear);
    6493:       DMCreateDS(cdmOld);
    6494:     } else {
    6495:       const char *discname;

    6497:       PetscObjectGetType(discOld, &discname);
    6498:       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
    6499:     }
    6500:   }
    6501:   /* Make a fresh clone of the coordinate DM */
    6502:   DMClone(cdmOld, &cdmNew);
    6503:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
    6504:   DMCreateDS(cdmNew);
    6505:   /* Project the coordinate vector from old to new space  */
    6506:   DMGetCoordinates(dm, &coordsOld);
    6507:   DMCreateGlobalVector(cdmNew, &coordsNew);
    6508:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
    6509:   MatInterpolate(matInterp, coordsOld, coordsNew);
    6510:   MatDestroy(&matInterp);
    6511:   /* Set new coordinate structures */
    6512:   DMSetCoordinateField(dm, NULL);
    6513:   DMSetCoordinateDM(dm, cdmNew);
    6514:   DMSetCoordinates(dm, coordsNew);
    6515:   VecDestroy(&coordsNew);
    6516:   DMDestroy(&cdmNew);
    6517:   return(0);
    6518: }

    6520: /*@C
    6521:   DMGetPeriodicity - Get the description of mesh periodicity

    6523:   Input Parameters:
    6524: . dm      - The DM object

    6526:   Output Parameters:
    6527: + per     - Whether the DM is periodic or not
    6528: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
    6529: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6530: - bd      - This describes the type of periodicity in each topological dimension

    6532:   Level: developer

    6534: .seealso: DMGetPeriodicity()
    6535: @*/
    6536: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
    6537: {
    6540:   if (per)     *per     = dm->periodic;
    6541:   if (L)       *L       = dm->L;
    6542:   if (maxCell) *maxCell = dm->maxCell;
    6543:   if (bd)      *bd      = dm->bdtype;
    6544:   return(0);
    6545: }

    6547: /*@C
    6548:   DMSetPeriodicity - Set the description of mesh periodicity

    6550:   Input Parameters:
    6551: + dm      - The DM object
    6552: . per     - Whether the DM is periodic or not.
    6553: . 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.
    6554: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6555: - bd      - This describes the type of periodicity in each topological dimension

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

    6559:   Level: developer

    6561: .seealso: DMGetPeriodicity()
    6562: @*/
    6563: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
    6564: {
    6565:   PetscInt       dim, d;

    6574:   DMGetDimension(dm, &dim);
    6575:   if (maxCell) {
    6576:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
    6577:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
    6578:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
    6579:     PetscFree(dm->maxCell);
    6580:   }

    6582:   if (L) {
    6583:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
    6584:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
    6585:   }
    6586:   if (bd) {
    6587:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
    6588:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
    6589:   }
    6590:   dm->periodic = per;
    6591:   return(0);
    6592: }

    6594: /*@
    6595:   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.

    6597:   Input Parameters:
    6598: + dm     - The DM
    6599: . in     - The input coordinate point (dim numbers)
    6600: - endpoint - Include the endpoint L_i

    6602:   Output Parameter:
    6603: . out - The localized coordinate point

    6605:   Level: developer

    6607: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6608: @*/
    6609: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
    6610: {
    6611:   PetscInt       dim, d;

    6615:   DMGetCoordinateDim(dm, &dim);
    6616:   if (!dm->maxCell) {
    6617:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6618:   } else {
    6619:     if (endpoint) {
    6620:       for (d = 0; d < dim; ++d) {
    6621:         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)) {
    6622:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
    6623:         } else {
    6624:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6625:         }
    6626:       }
    6627:     } else {
    6628:       for (d = 0; d < dim; ++d) {
    6629:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6630:       }
    6631:     }
    6632:   }
    6633:   return(0);
    6634: }

    6636: /*
    6637:   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.

    6639:   Input Parameters:
    6640: + dm     - The DM
    6641: . dim    - The spatial dimension
    6642: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6643: - in     - The input coordinate point (dim numbers)

    6645:   Output Parameter:
    6646: . out - The localized coordinate point

    6648:   Level: developer

    6650:   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

    6652: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6653: */
    6654: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6655: {
    6656:   PetscInt d;

    6659:   if (!dm->maxCell) {
    6660:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6661:   } else {
    6662:     for (d = 0; d < dim; ++d) {
    6663:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
    6664:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6665:       } else {
    6666:         out[d] = in[d];
    6667:       }
    6668:     }
    6669:   }
    6670:   return(0);
    6671: }

    6673: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
    6674: {
    6675:   PetscInt d;

    6678:   if (!dm->maxCell) {
    6679:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6680:   } else {
    6681:     for (d = 0; d < dim; ++d) {
    6682:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
    6683:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6684:       } else {
    6685:         out[d] = in[d];
    6686:       }
    6687:     }
    6688:   }
    6689:   return(0);
    6690: }

    6692: /*
    6693:   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.

    6695:   Input Parameters:
    6696: + dm     - The DM
    6697: . dim    - The spatial dimension
    6698: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6699: . in     - The input coordinate delta (dim numbers)
    6700: - out    - The input coordinate point (dim numbers)

    6702:   Output Parameter:
    6703: . out    - The localized coordinate in + out

    6705:   Level: developer

    6707:   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

    6709: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
    6710: */
    6711: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6712: {
    6713:   PetscInt d;

    6716:   if (!dm->maxCell) {
    6717:     for (d = 0; d < dim; ++d) out[d] += in[d];
    6718:   } else {
    6719:     for (d = 0; d < dim; ++d) {
    6720:       const PetscReal maxC = dm->maxCell[d];

    6722:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
    6723:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

    6725:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
    6726:           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]));
    6727:         out[d] += newCoord;
    6728:       } else {
    6729:         out[d] += in[d];
    6730:       }
    6731:     }
    6732:   }
    6733:   return(0);
    6734: }

    6736: /*@
    6737:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

    6739:   Not collective

    6741:   Input Parameter:
    6742: . dm - The DM

    6744:   Output Parameter:
    6745:   areLocalized - True if localized

    6747:   Level: developer

    6749: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
    6750: @*/
    6751: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
    6752: {
    6753:   DM             cdm;
    6754:   PetscSection   coordSection;
    6755:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
    6756:   PetscBool      isPlex, alreadyLocalized;

    6762:   *areLocalized = PETSC_FALSE;

    6764:   /* We need some generic way of refering to cells/vertices */
    6765:   DMGetCoordinateDM(dm, &cdm);
    6766:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
    6767:   if (!isPlex) return(0);

    6769:   DMGetCoordinateSection(dm, &coordSection);
    6770:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
    6771:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
    6772:   alreadyLocalized = PETSC_FALSE;
    6773:   for (c = cStart; c < cEnd; ++c) {
    6774:     if (c < sStart || c >= sEnd) continue;
    6775:     PetscSectionGetDof(coordSection, c, &dof);
    6776:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
    6777:   }
    6778:   *areLocalized = alreadyLocalized;
    6779:   return(0);
    6780: }

    6782: /*@
    6783:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

    6785:   Collective on dm

    6787:   Input Parameter:
    6788: . dm - The DM

    6790:   Output Parameter:
    6791:   areLocalized - True if localized

    6793:   Level: developer

    6795: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
    6796: @*/
    6797: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
    6798: {
    6799:   PetscBool      localized;

    6805:   DMGetCoordinatesLocalizedLocal(dm,&localized);
    6806:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
    6807:   return(0);
    6808: }

    6810: /*@
    6811:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

    6813:   Collective on dm

    6815:   Input Parameter:
    6816: . dm - The DM

    6818:   Level: developer

    6820: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
    6821: @*/
    6822: PetscErrorCode DMLocalizeCoordinates(DM dm)
    6823: {
    6824:   DM             cdm;
    6825:   PetscSection   coordSection, cSection;
    6826:   Vec            coordinates,  cVec;
    6827:   PetscScalar   *coords, *coords2, *anchor, *localized;
    6828:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
    6829:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
    6830:   PetscInt       maxHeight = 0, h;
    6831:   PetscInt       *pStart = NULL, *pEnd = NULL;

    6836:   if (!dm->periodic) return(0);
    6837:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
    6838:   if (alreadyLocalized) return(0);

    6840:   /* We need some generic way of refering to cells/vertices */
    6841:   DMGetCoordinateDM(dm, &cdm);
    6842:   {
    6843:     PetscBool isplex;

    6845:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
    6846:     if (isplex) {
    6847:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
    6848:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
    6849:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6850:       pEnd = &pStart[maxHeight + 1];
    6851:       newStart = vStart;
    6852:       newEnd   = vEnd;
    6853:       for (h = 0; h <= maxHeight; h++) {
    6854:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
    6855:         newStart = PetscMin(newStart,pStart[h]);
    6856:         newEnd   = PetscMax(newEnd,pEnd[h]);
    6857:       }
    6858:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
    6859:   }
    6860:   DMGetCoordinatesLocal(dm, &coordinates);
    6861:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
    6862:   DMGetCoordinateSection(dm, &coordSection);
    6863:   VecGetBlockSize(coordinates, &bs);
    6864:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

    6866:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
    6867:   PetscSectionSetNumFields(cSection, 1);
    6868:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
    6869:   PetscSectionSetFieldComponents(cSection, 0, Nc);
    6870:   PetscSectionSetChart(cSection, newStart, newEnd);

    6872:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6873:   localized = &anchor[bs];
    6874:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
    6875:   for (h = 0; h <= maxHeight; h++) {
    6876:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6878:     for (c = cStart; c < cEnd; ++c) {
    6879:       PetscScalar *cellCoords = NULL;
    6880:       PetscInt     b;

    6882:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
    6883:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6884:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6885:       for (d = 0; d < dof/bs; ++d) {
    6886:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
    6887:         for (b = 0; b < bs; b++) {
    6888:           if (cellCoords[d*bs + b] != localized[b]) break;
    6889:         }
    6890:         if (b < bs) break;
    6891:       }
    6892:       if (d < dof/bs) {
    6893:         if (c >= sStart && c < sEnd) {
    6894:           PetscInt cdof;

    6896:           PetscSectionGetDof(coordSection, c, &cdof);
    6897:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
    6898:         }
    6899:         PetscSectionSetDof(cSection, c, dof);
    6900:         PetscSectionSetFieldDof(cSection, c, 0, dof);
    6901:       }
    6902:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6903:     }
    6904:   }
    6905:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
    6906:   if (alreadyLocalizedGlobal) {
    6907:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6908:     PetscSectionDestroy(&cSection);
    6909:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6910:     return(0);
    6911:   }
    6912:   for (v = vStart; v < vEnd; ++v) {
    6913:     PetscSectionGetDof(coordSection, v, &dof);
    6914:     PetscSectionSetDof(cSection, v, dof);
    6915:     PetscSectionSetFieldDof(cSection, v, 0, dof);
    6916:   }
    6917:   PetscSectionSetUp(cSection);
    6918:   PetscSectionGetStorageSize(cSection, &coordSize);
    6919:   VecCreate(PETSC_COMM_SELF, &cVec);
    6920:   PetscObjectSetName((PetscObject)cVec,"coordinates");
    6921:   VecSetBlockSize(cVec, bs);
    6922:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
    6923:   VecSetType(cVec, VECSTANDARD);
    6924:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
    6925:   VecGetArray(cVec, &coords2);
    6926:   for (v = vStart; v < vEnd; ++v) {
    6927:     PetscSectionGetDof(coordSection, v, &dof);
    6928:     PetscSectionGetOffset(coordSection, v, &off);
    6929:     PetscSectionGetOffset(cSection,     v, &off2);
    6930:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
    6931:   }
    6932:   for (h = 0; h <= maxHeight; h++) {
    6933:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6935:     for (c = cStart; c < cEnd; ++c) {
    6936:       PetscScalar *cellCoords = NULL;
    6937:       PetscInt     b, cdof;

    6939:       PetscSectionGetDof(cSection,c,&cdof);
    6940:       if (!cdof) continue;
    6941:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6942:       PetscSectionGetOffset(cSection, c, &off2);
    6943:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6944:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
    6945:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6946:     }
    6947:   }
    6948:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6949:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6950:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
    6951:   VecRestoreArray(cVec, &coords2);
    6952:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
    6953:   DMSetCoordinatesLocal(dm, cVec);
    6954:   VecDestroy(&cVec);
    6955:   PetscSectionDestroy(&cSection);
    6956:   return(0);
    6957: }

    6959: /*@
    6960:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

    6962:   Collective on v (see explanation below)

    6964:   Input Parameters:
    6965: + dm - The DM
    6966: . v - The Vec of points
    6967: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
    6968: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

    6970:   Output Parameter:
    6971: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
    6972: - cells - The PetscSF containing the ranks and local indices of the containing points.

    6975:   Level: developer

    6977:   Notes:
    6978:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
    6979:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

    6981:   If *cellSF is NULL on input, a PetscSF will be created.
    6982:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

    6984:   An array that maps each point to its containing cell can be obtained with

    6986: $    const PetscSFNode *cells;
    6987: $    PetscInt           nFound;
    6988: $    const PetscInt    *found;
    6989: $
    6990: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

    6992:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
    6993:   the index of the cell in its rank's local numbering.

    6995: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
    6996: @*/
    6997: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
    6998: {

    7005:   if (*cellSF) {
    7006:     PetscMPIInt result;

    7009:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
    7010:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
    7011:   } else {
    7012:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
    7013:   }
    7014:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
    7015:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
    7016:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
    7017:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
    7018:   return(0);
    7019: }

    7021: /*@
    7022:   DMGetOutputDM - Retrieve the DM associated with the layout for output

    7024:   Collective on dm

    7026:   Input Parameter:
    7027: . dm - The original DM

    7029:   Output Parameter:
    7030: . odm - The DM which provides the layout for output

    7032:   Level: intermediate

    7034: .seealso: VecView(), DMGetGlobalSection()
    7035: @*/
    7036: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
    7037: {
    7038:   PetscSection   section;
    7039:   PetscBool      hasConstraints, ghasConstraints;

    7045:   DMGetLocalSection(dm, &section);
    7046:   PetscSectionHasConstraints(section, &hasConstraints);
    7047:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
    7048:   if (!ghasConstraints) {
    7049:     *odm = dm;
    7050:     return(0);
    7051:   }
    7052:   if (!dm->dmBC) {
    7053:     PetscSection newSection, gsection;
    7054:     PetscSF      sf;

    7056:     DMClone(dm, &dm->dmBC);
    7057:     DMCopyDisc(dm, dm->dmBC);
    7058:     PetscSectionClone(section, &newSection);
    7059:     DMSetLocalSection(dm->dmBC, newSection);
    7060:     PetscSectionDestroy(&newSection);
    7061:     DMGetPointSF(dm->dmBC, &sf);
    7062:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
    7063:     DMSetGlobalSection(dm->dmBC, gsection);
    7064:     PetscSectionDestroy(&gsection);
    7065:   }
    7066:   *odm = dm->dmBC;
    7067:   return(0);
    7068: }

    7070: /*@
    7071:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

    7073:   Input Parameter:
    7074: . dm - The original DM

    7076:   Output Parameters:
    7077: + num - The output sequence number
    7078: - val - The output sequence value

    7080:   Level: intermediate

    7082:   Note: This is intended for output that should appear in sequence, for instance
    7083:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7085: .seealso: VecView()
    7086: @*/
    7087: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
    7088: {
    7093:   return(0);
    7094: }

    7096: /*@
    7097:   DMSetOutputSequenceNumber - Set the sequence number/value for output

    7099:   Input Parameters:
    7100: + dm - The original DM
    7101: . num - The output sequence number
    7102: - val - The output sequence value

    7104:   Level: intermediate

    7106:   Note: This is intended for output that should appear in sequence, for instance
    7107:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7109: .seealso: VecView()
    7110: @*/
    7111: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
    7112: {
    7115:   dm->outputSequenceNum = num;
    7116:   dm->outputSequenceVal = val;
    7117:   return(0);
    7118: }

    7120: /*@C
    7121:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

    7123:   Input Parameters:
    7124: + dm   - The original DM
    7125: . name - The sequence name
    7126: - num  - The output sequence number

    7128:   Output Parameter:
    7129: . val  - The output sequence value

    7131:   Level: intermediate

    7133:   Note: This is intended for output that should appear in sequence, for instance
    7134:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7136: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
    7137: @*/
    7138: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
    7139: {
    7140:   PetscBool      ishdf5;

    7147:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    7148:   if (ishdf5) {
    7149: #if defined(PETSC_HAVE_HDF5)
    7150:     PetscScalar value;

    7152:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
    7153:     *val = PetscRealPart(value);
    7154: #endif
    7155:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
    7156:   return(0);
    7157: }

    7159: /*@
    7160:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

    7162:   Not collective

    7164:   Input Parameter:
    7165: . dm - The DM

    7167:   Output Parameter:
    7168: . useNatural - The flag to build the mapping to a natural order during distribution

    7170:   Level: beginner

    7172: .seealso: DMSetUseNatural(), DMCreate()
    7173: @*/
    7174: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
    7175: {
    7179:   *useNatural = dm->useNatural;
    7180:   return(0);
    7181: }

    7183: /*@
    7184:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

    7186:   Collective on dm

    7188:   Input Parameters:
    7189: + dm - The DM
    7190: - useNatural - The flag to build the mapping to a natural order during distribution

    7192:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

    7194:   Level: beginner

    7196: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
    7197: @*/
    7198: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
    7199: {
    7203:   dm->useNatural = useNatural;
    7204:   return(0);
    7205: }

    7208: /*@C
    7209:   DMCreateLabel - Create a label of the given name if it does not already exist

    7211:   Not Collective

    7213:   Input Parameters:
    7214: + dm   - The DM object
    7215: - name - The label name

    7217:   Level: intermediate

    7219: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7220: @*/
    7221: PetscErrorCode DMCreateLabel(DM dm, const char name[])
    7222: {
    7223:   PetscBool      flg;
    7224:   DMLabel        label;

    7230:   DMHasLabel(dm, name, &flg);
    7231:   if (!flg) {
    7232:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7233:     DMAddLabel(dm, label);
    7234:     DMLabelDestroy(&label);
    7235:   }
    7236:   return(0);
    7237: }

    7239: /*@C
    7240:   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.

    7242:   Not Collective

    7244:   Input Parameters:
    7245: + dm   - The DM object
    7246: . l    - The index for the label
    7247: - name - The label name

    7249:   Level: intermediate

    7251: .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7252: @*/
    7253: PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
    7254: {
    7255:   DMLabelLink    orig, prev = NULL;
    7256:   DMLabel        label;
    7257:   PetscInt       Nl, m;
    7258:   PetscBool      flg, match;
    7259:   const char    *lname;

    7265:   DMHasLabel(dm, name, &flg);
    7266:   if (!flg) {
    7267:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7268:     DMAddLabel(dm, label);
    7269:     DMLabelDestroy(&label);
    7270:   }
    7271:   DMGetNumLabels(dm, &Nl);
    7272:   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
    7273:   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
    7274:     PetscObjectGetName((PetscObject) orig->label, &lname);
    7275:     PetscStrcmp(name, lname, &match);
    7276:     if (match) break;
    7277:   }
    7278:   if (m == l) return(0);
    7279:   if (!m) dm->labels = orig->next;
    7280:   else    prev->next = orig->next;
    7281:   if (!l) {
    7282:     orig->next = dm->labels;
    7283:     dm->labels = orig;
    7284:   } else {
    7285:     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
    7286:     orig->next = prev->next;
    7287:     prev->next = orig;
    7288:   }
    7289:   return(0);
    7290: }

    7292: /*@C
    7293:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

    7295:   Not Collective

    7297:   Input Parameters:
    7298: + dm   - The DM object
    7299: . name - The label name
    7300: - point - The mesh point

    7302:   Output Parameter:
    7303: . value - The label value for this point, or -1 if the point is not in the label

    7305:   Level: beginner

    7307: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
    7308: @*/
    7309: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
    7310: {
    7311:   DMLabel        label;

    7317:   DMGetLabel(dm, name, &label);
    7318:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
    7319:   DMLabelGetValue(label, point, value);
    7320:   return(0);
    7321: }

    7323: /*@C
    7324:   DMSetLabelValue - Add a point to a Sieve Label with given value

    7326:   Not Collective

    7328:   Input Parameters:
    7329: + dm   - The DM object
    7330: . name - The label name
    7331: . point - The mesh point
    7332: - value - The label value for this point

    7334:   Output Parameter:

    7336:   Level: beginner

    7338: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
    7339: @*/
    7340: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7341: {
    7342:   DMLabel        label;

    7348:   DMGetLabel(dm, name, &label);
    7349:   if (!label) {
    7350:     DMCreateLabel(dm, name);
    7351:     DMGetLabel(dm, name, &label);
    7352:   }
    7353:   DMLabelSetValue(label, point, value);
    7354:   return(0);
    7355: }

    7357: /*@C
    7358:   DMClearLabelValue - Remove a point from a Sieve Label with given value

    7360:   Not Collective

    7362:   Input Parameters:
    7363: + dm   - The DM object
    7364: . name - The label name
    7365: . point - The mesh point
    7366: - value - The label value for this point

    7368:   Output Parameter:

    7370:   Level: beginner

    7372: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
    7373: @*/
    7374: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7375: {
    7376:   DMLabel        label;

    7382:   DMGetLabel(dm, name, &label);
    7383:   if (!label) return(0);
    7384:   DMLabelClearValue(label, point, value);
    7385:   return(0);
    7386: }

    7388: /*@C
    7389:   DMGetLabelSize - Get the number of different integer ids in a Label

    7391:   Not Collective

    7393:   Input Parameters:
    7394: + dm   - The DM object
    7395: - name - The label name

    7397:   Output Parameter:
    7398: . size - The number of different integer ids, or 0 if the label does not exist

    7400:   Level: beginner

    7402: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
    7403: @*/
    7404: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
    7405: {
    7406:   DMLabel        label;

    7413:   DMGetLabel(dm, name, &label);
    7414:   *size = 0;
    7415:   if (!label) return(0);
    7416:   DMLabelGetNumValues(label, size);
    7417:   return(0);
    7418: }

    7420: /*@C
    7421:   DMGetLabelIdIS - Get the integer ids in a label

    7423:   Not Collective

    7425:   Input Parameters:
    7426: + mesh - The DM object
    7427: - name - The label name

    7429:   Output Parameter:
    7430: . ids - The integer ids, or NULL if the label does not exist

    7432:   Level: beginner

    7434: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
    7435: @*/
    7436: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
    7437: {
    7438:   DMLabel        label;

    7445:   DMGetLabel(dm, name, &label);
    7446:   *ids = NULL;
    7447:  if (label) {
    7448:     DMLabelGetValueIS(label, ids);
    7449:   } else {
    7450:     /* returning an empty IS */
    7451:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
    7452:   }
    7453:   return(0);
    7454: }

    7456: /*@C
    7457:   DMGetStratumSize - Get the number of points in a label stratum

    7459:   Not Collective

    7461:   Input Parameters:
    7462: + dm - The DM object
    7463: . name - The label name
    7464: - value - The stratum value

    7466:   Output Parameter:
    7467: . size - The stratum size

    7469:   Level: beginner

    7471: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
    7472: @*/
    7473: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
    7474: {
    7475:   DMLabel        label;

    7482:   DMGetLabel(dm, name, &label);
    7483:   *size = 0;
    7484:   if (!label) return(0);
    7485:   DMLabelGetStratumSize(label, value, size);
    7486:   return(0);
    7487: }

    7489: /*@C
    7490:   DMGetStratumIS - Get the points in a label stratum

    7492:   Not Collective

    7494:   Input Parameters:
    7495: + dm - The DM object
    7496: . name - The label name
    7497: - value - The stratum value

    7499:   Output Parameter:
    7500: . points - The stratum points, or NULL if the label does not exist or does not have that value

    7502:   Level: beginner

    7504: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
    7505: @*/
    7506: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
    7507: {
    7508:   DMLabel        label;

    7515:   DMGetLabel(dm, name, &label);
    7516:   *points = NULL;
    7517:   if (!label) return(0);
    7518:   DMLabelGetStratumIS(label, value, points);
    7519:   return(0);
    7520: }

    7522: /*@C
    7523:   DMSetStratumIS - Set the points in a label stratum

    7525:   Not Collective

    7527:   Input Parameters:
    7528: + dm - The DM object
    7529: . name - The label name
    7530: . value - The stratum value
    7531: - points - The stratum points

    7533:   Level: beginner

    7535: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
    7536: @*/
    7537: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
    7538: {
    7539:   DMLabel        label;

    7546:   DMGetLabel(dm, name, &label);
    7547:   if (!label) return(0);
    7548:   DMLabelSetStratumIS(label, value, points);
    7549:   return(0);
    7550: }

    7552: /*@C
    7553:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

    7555:   Not Collective

    7557:   Input Parameters:
    7558: + dm   - The DM object
    7559: . name - The label name
    7560: - value - The label value for this point

    7562:   Output Parameter:

    7564:   Level: beginner

    7566: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
    7567: @*/
    7568: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
    7569: {
    7570:   DMLabel        label;

    7576:   DMGetLabel(dm, name, &label);
    7577:   if (!label) return(0);
    7578:   DMLabelClearStratum(label, value);
    7579:   return(0);
    7580: }

    7582: /*@
    7583:   DMGetNumLabels - Return the number of labels defined by the mesh

    7585:   Not Collective

    7587:   Input Parameter:
    7588: . dm   - The DM object

    7590:   Output Parameter:
    7591: . numLabels - the number of Labels

    7593:   Level: intermediate

    7595: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7596: @*/
    7597: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
    7598: {
    7599:   DMLabelLink next = dm->labels;
    7600:   PetscInt  n    = 0;

    7605:   while (next) {++n; next = next->next;}
    7606:   *numLabels = n;
    7607:   return(0);
    7608: }

    7610: /*@C
    7611:   DMGetLabelName - Return the name of nth label

    7613:   Not Collective

    7615:   Input Parameters:
    7616: + dm - The DM object
    7617: - n  - the label number

    7619:   Output Parameter:
    7620: . name - the label name

    7622:   Level: intermediate

    7624: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7625: @*/
    7626: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
    7627: {
    7628:   DMLabelLink    next = dm->labels;
    7629:   PetscInt       l    = 0;

    7635:   while (next) {
    7636:     if (l == n) {
    7637:       PetscObjectGetName((PetscObject) next->label, name);
    7638:       return(0);
    7639:     }
    7640:     ++l;
    7641:     next = next->next;
    7642:   }
    7643:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7644: }

    7646: /*@C
    7647:   DMHasLabel - Determine whether the mesh has a label of a given name

    7649:   Not Collective

    7651:   Input Parameters:
    7652: + dm   - The DM object
    7653: - name - The label name

    7655:   Output Parameter:
    7656: . hasLabel - PETSC_TRUE if the label is present

    7658:   Level: intermediate

    7660: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7661: @*/
    7662: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
    7663: {
    7664:   DMLabelLink    next = dm->labels;
    7665:   const char    *lname;

    7672:   *hasLabel = PETSC_FALSE;
    7673:   while (next) {
    7674:     PetscObjectGetName((PetscObject) next->label, &lname);
    7675:     PetscStrcmp(name, lname, hasLabel);
    7676:     if (*hasLabel) break;
    7677:     next = next->next;
    7678:   }
    7679:   return(0);
    7680: }

    7682: /*@C
    7683:   DMGetLabel - Return the label of a given name, or NULL

    7685:   Not Collective

    7687:   Input Parameters:
    7688: + dm   - The DM object
    7689: - name - The label name

    7691:   Output Parameter:
    7692: . label - The DMLabel, or NULL if the label is absent

    7694:   Note: Some of the default labels in a DMPlex will be
    7695: $ "depth"       - Holds the depth (co-dimension) of each mesh point
    7696: $ "celltype"    - Holds the topological type of each cell
    7697: $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
    7698: $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
    7699: $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
    7700: $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh

    7702:   Level: intermediate

    7704: .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType()
    7705: @*/
    7706: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
    7707: {
    7708:   DMLabelLink    next = dm->labels;
    7709:   PetscBool      hasLabel;
    7710:   const char    *lname;

    7717:   *label = NULL;
    7718:   while (next) {
    7719:     PetscObjectGetName((PetscObject) next->label, &lname);
    7720:     PetscStrcmp(name, lname, &hasLabel);
    7721:     if (hasLabel) {
    7722:       *label = next->label;
    7723:       break;
    7724:     }
    7725:     next = next->next;
    7726:   }
    7727:   return(0);
    7728: }

    7730: /*@C
    7731:   DMGetLabelByNum - Return the nth label

    7733:   Not Collective

    7735:   Input Parameters:
    7736: + dm - The DM object
    7737: - n  - the label number

    7739:   Output Parameter:
    7740: . label - the label

    7742:   Level: intermediate

    7744: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7745: @*/
    7746: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
    7747: {
    7748:   DMLabelLink next = dm->labels;
    7749:   PetscInt    l    = 0;

    7754:   while (next) {
    7755:     if (l == n) {
    7756:       *label = next->label;
    7757:       return(0);
    7758:     }
    7759:     ++l;
    7760:     next = next->next;
    7761:   }
    7762:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7763: }

    7765: /*@C
    7766:   DMAddLabel - Add the label to this mesh

    7768:   Not Collective

    7770:   Input Parameters:
    7771: + dm   - The DM object
    7772: - label - The DMLabel

    7774:   Level: developer

    7776: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7777: @*/
    7778: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
    7779: {
    7780:   DMLabelLink    l, *p, tmpLabel;
    7781:   PetscBool      hasLabel;
    7782:   const char    *lname;
    7783:   PetscBool      flg;

    7788:   PetscObjectGetName((PetscObject) label, &lname);
    7789:   DMHasLabel(dm, lname, &hasLabel);
    7790:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
    7791:   PetscCalloc1(1, &tmpLabel);
    7792:   tmpLabel->label  = label;
    7793:   tmpLabel->output = PETSC_TRUE;
    7794:   for (p=&dm->labels; (l=*p); p=&l->next) {}
    7795:   *p = tmpLabel;
    7796:   PetscObjectReference((PetscObject)label);
    7797:   PetscStrcmp(lname, "depth", &flg);
    7798:   if (flg) dm->depthLabel = label;
    7799:   PetscStrcmp(lname, "celltype", &flg);
    7800:   if (flg) dm->celltypeLabel = label;
    7801:   return(0);
    7802: }

    7804: /*@C
    7805:   DMRemoveLabel - Remove the label given by name from this mesh

    7807:   Not Collective

    7809:   Input Parameters:
    7810: + dm   - The DM object
    7811: - name - The label name

    7813:   Output Parameter:
    7814: . label - The DMLabel, or NULL if the label is absent

    7816:   Level: developer

    7818:   Notes:
    7819:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
    7820:   DMLabelDestroy() on the label.

    7822:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
    7823:   call DMLabelDestroy(). Instead, the label is returned and the user is
    7824:   responsible of calling DMLabelDestroy() at some point.

    7826: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
    7827: @*/
    7828: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
    7829: {
    7830:   DMLabelLink    link, *pnext;
    7831:   PetscBool      hasLabel;
    7832:   const char    *lname;

    7838:   if (label) {
    7840:     *label = NULL;
    7841:   }
    7842:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7843:     PetscObjectGetName((PetscObject) link->label, &lname);
    7844:     PetscStrcmp(name, lname, &hasLabel);
    7845:     if (hasLabel) {
    7846:       *pnext = link->next; /* Remove from list */
    7847:       PetscStrcmp(name, "depth", &hasLabel);
    7848:       if (hasLabel) dm->depthLabel = NULL;
    7849:       PetscStrcmp(name, "celltype", &hasLabel);
    7850:       if (hasLabel) dm->celltypeLabel = NULL;
    7851:       if (label) *label = link->label;
    7852:       else       {DMLabelDestroy(&link->label);}
    7853:       PetscFree(link);
    7854:       break;
    7855:     }
    7856:   }
    7857:   return(0);
    7858: }

    7860: /*@
    7861:   DMRemoveLabelBySelf - Remove the label from this mesh

    7863:   Not Collective

    7865:   Input Parameters:
    7866: + dm   - The DM object
    7867: . label - (Optional) The DMLabel to be removed from the DM
    7868: - failNotFound - Should it fail if the label is not found in the DM?

    7870:   Level: developer

    7872:   Notes:
    7873:   Only exactly the same instance is removed if found, name match is ignored.
    7874:   If the DM has an exclusive reference to the label, it gets destroyed and
    7875:   *label nullified.

    7877: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
    7878: @*/
    7879: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
    7880: {
    7881:   DMLabelLink    link, *pnext;
    7882:   PetscBool      hasLabel = PETSC_FALSE;

    7888:   if (!*label && !failNotFound) return(0);
    7891:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7892:     if (*label == link->label) {
    7893:       hasLabel = PETSC_TRUE;
    7894:       *pnext = link->next; /* Remove from list */
    7895:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
    7896:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    7897:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
    7898:       DMLabelDestroy(&link->label);
    7899:       PetscFree(link);
    7900:       break;
    7901:     }
    7902:   }
    7903:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
    7904:   return(0);
    7905: }

    7907: /*@C
    7908:   DMGetLabelOutput - Get the output flag for a given label

    7910:   Not Collective

    7912:   Input Parameters:
    7913: + dm   - The DM object
    7914: - name - The label name

    7916:   Output Parameter:
    7917: . output - The flag for output

    7919:   Level: developer

    7921: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7922: @*/
    7923: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
    7924: {
    7925:   DMLabelLink    next = dm->labels;
    7926:   const char    *lname;

    7933:   while (next) {
    7934:     PetscBool flg;

    7936:     PetscObjectGetName((PetscObject) next->label, &lname);
    7937:     PetscStrcmp(name, lname, &flg);
    7938:     if (flg) {*output = next->output; return(0);}
    7939:     next = next->next;
    7940:   }
    7941:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7942: }

    7944: /*@C
    7945:   DMSetLabelOutput - Set the output flag for a given label

    7947:   Not Collective

    7949:   Input Parameters:
    7950: + dm     - The DM object
    7951: . name   - The label name
    7952: - output - The flag for output

    7954:   Level: developer

    7956: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7957: @*/
    7958: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
    7959: {
    7960:   DMLabelLink    next = dm->labels;
    7961:   const char    *lname;

    7967:   while (next) {
    7968:     PetscBool flg;

    7970:     PetscObjectGetName((PetscObject) next->label, &lname);
    7971:     PetscStrcmp(name, lname, &flg);
    7972:     if (flg) {next->output = output; return(0);}
    7973:     next = next->next;
    7974:   }
    7975:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7976: }

    7978: /*@
    7979:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

    7981:   Collective on dmA

    7983:   Input Parameter:
    7984: + dmA - The DM object with initial labels
    7985: . dmB - The DM object with copied labels
    7986: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
    7987: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

    7989:   Level: intermediate

    7991:   Note: This is typically used when interpolating or otherwise adding to a mesh

    7993: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
    7994: @*/
    7995: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
    7996: {
    7997:   DMLabel        label, labelNew;
    7998:   const char    *name;
    7999:   PetscBool      flg;
    8000:   DMLabelLink    link;

    8008:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
    8009:   if (dmA == dmB) return(0);
    8010:   for (link=dmA->labels; link; link=link->next) {
    8011:     label=link->label;
    8012:     PetscObjectGetName((PetscObject)label, &name);
    8013:     if (!all) {
    8014:       PetscStrcmp(name, "depth", &flg);
    8015:       if (flg) continue;
    8016:       PetscStrcmp(name, "dim", &flg);
    8017:       if (flg) continue;
    8018:       PetscStrcmp(name, "celltype", &flg);
    8019:       if (flg) continue;
    8020:     }
    8021:     if (mode==PETSC_COPY_VALUES) {
    8022:       DMLabelDuplicate(label, &labelNew);
    8023:     } else {
    8024:       labelNew = label;
    8025:     }
    8026:     DMAddLabel(dmB, labelNew);
    8027:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
    8028:   }
    8029:   return(0);
    8030: }
    8031: /*
    8032:   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
    8033:   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
    8034:   (label, id) pair in the DM.

    8036:   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
    8037:   each label.
    8038: */
    8039: PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
    8040: {
    8041:   DMUniversalLabel ul;
    8042:   PetscBool       *active;
    8043:   PetscInt         pStart, pEnd, p, Nl, l, m;
    8044:   PetscErrorCode   ierr;

    8047:   PetscMalloc1(1, &ul);
    8048:   DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);
    8049:   DMGetNumLabels(dm, &Nl);
    8050:   PetscCalloc1(Nl, &active);
    8051:   ul->Nl = 0;
    8052:   for (l = 0; l < Nl; ++l) {
    8053:     PetscBool   isdepth, iscelltype;
    8054:     const char *name;

    8056:     DMGetLabelName(dm, l, &name);
    8057:     PetscStrncmp(name, "depth", 6, &isdepth);
    8058:     PetscStrncmp(name, "celltype", 9, &iscelltype);
    8059:     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
    8060:     if (active[l]) ++ul->Nl;
    8061:   }
    8062:   PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);
    8063:   ul->Nv = 0;
    8064:   for (l = 0, m = 0; l < Nl; ++l) {
    8065:     DMLabel     label;
    8066:     PetscInt    nv;
    8067:     const char *name;

    8069:     if (!active[l]) continue;
    8070:     DMGetLabelName(dm, l, &name);
    8071:     DMGetLabelByNum(dm, l, &label);
    8072:     DMLabelGetNumValues(label, &nv);
    8073:     PetscStrallocpy(name, &ul->names[m]);
    8074:     ul->indices[m]   = l;
    8075:     ul->Nv          += nv;
    8076:     ul->offsets[m+1] = nv;
    8077:     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
    8078:     ++m;
    8079:   }
    8080:   for (l = 1; l <= ul->Nl; ++l) {
    8081:     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
    8082:     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
    8083:   }
    8084:   for (l = 0; l < ul->Nl; ++l) {
    8085:     PetscInt b;

    8087:     ul->masks[l] = 0;
    8088:     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
    8089:   }
    8090:   PetscMalloc1(ul->Nv, &ul->values);
    8091:   for (l = 0, m = 0; l < Nl; ++l) {
    8092:     DMLabel         label;
    8093:     IS              valueIS;
    8094:     const PetscInt *varr;
    8095:     PetscInt        nv, v;

    8097:     if (!active[l]) continue;
    8098:     DMGetLabelByNum(dm, l, &label);
    8099:     DMLabelGetNumValues(label, &nv);
    8100:     DMLabelGetValueIS(label, &valueIS);
    8101:     ISGetIndices(valueIS, &varr);
    8102:     for (v = 0; v < nv; ++v) {
    8103:       ul->values[ul->offsets[m]+v] = varr[v];
    8104:     }
    8105:     ISRestoreIndices(valueIS, &varr);
    8106:     ISDestroy(&valueIS);
    8107:     PetscSortInt(nv, &ul->values[ul->offsets[m]]);
    8108:     ++m;
    8109:   }
    8110:   DMPlexGetChart(dm, &pStart, &pEnd);
    8111:   for (p = pStart; p < pEnd; ++p) {
    8112:     PetscInt  uval = 0;
    8113:     PetscBool marked = PETSC_FALSE;

    8115:     for (l = 0, m = 0; l < Nl; ++l) {
    8116:       DMLabel  label;
    8117:       PetscInt val, defval, loc, nv;

    8119:       if (!active[l]) continue;
    8120:       DMGetLabelByNum(dm, l, &label);
    8121:       DMLabelGetValue(label, p, &val);
    8122:       DMLabelGetDefaultValue(label, &defval);
    8123:       if (val == defval) {++m; continue;}
    8124:       nv = ul->offsets[m+1]-ul->offsets[m];
    8125:       marked = PETSC_TRUE;
    8126:       PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);
    8127:       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
    8128:       uval += (loc+1) << ul->bits[m];
    8129:       ++m;
    8130:     }
    8131:     if (marked) {DMLabelSetValue(ul->label, p, uval);}
    8132:   }
    8133:   PetscFree(active);
    8134:   *universal = ul;
    8135:   return(0);
    8136: }

    8138: PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
    8139: {
    8140:   PetscInt       l;

    8144:   for (l = 0; l < (*universal)->Nl; ++l) {PetscFree((*universal)->names[l]);}
    8145:   DMLabelDestroy(&(*universal)->label);
    8146:   PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);
    8147:   PetscFree((*universal)->values);
    8148:   PetscFree(*universal);
    8149:   *universal = NULL;
    8150:   return(0);
    8151: }

    8153: PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
    8154: {
    8157:   *ulabel = ul->label;
    8158:   return(0);
    8159: }

    8161: PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
    8162: {
    8163:   PetscInt       Nl = ul->Nl, l;

    8168:   for (l = 0; l < Nl; ++l) {
    8169:     if (preserveOrder) {DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);}
    8170:     else               {DMCreateLabel(dm, ul->names[l]);}
    8171:   }
    8172:   if (preserveOrder) {
    8173:     for (l = 0; l < ul->Nl; ++l) {
    8174:       const char *name;
    8175:       PetscBool   match;

    8177:       DMGetLabelName(dm, ul->indices[l], &name);
    8178:       PetscStrcmp(name, ul->names[l], &match);
    8179:       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]);
    8180:     }
    8181:   }
    8182:   return(0);
    8183: }

    8185: PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
    8186: {
    8187:   PetscInt       l;

    8191:   for (l = 0; l < ul->Nl; ++l) {
    8192:     DMLabel  label;
    8193:     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];

    8195:     if (lval) {
    8196:       if (useIndex) {DMGetLabelByNum(dm, ul->indices[l], &label);}
    8197:       else          {DMGetLabel(dm, ul->names[l], &label);}
    8198:       DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);
    8199:     }
    8200:   }
    8201:   return(0);
    8202: }

    8204: /*@
    8205:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

    8207:   Input Parameter:
    8208: . dm - The DM object

    8210:   Output Parameter:
    8211: . cdm - The coarse DM

    8213:   Level: intermediate

    8215: .seealso: DMSetCoarseDM()
    8216: @*/
    8217: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
    8218: {
    8222:   *cdm = dm->coarseMesh;
    8223:   return(0);
    8224: }

    8226: /*@
    8227:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

    8229:   Input Parameters:
    8230: + dm - The DM object
    8231: - cdm - The coarse DM

    8233:   Level: intermediate

    8235: .seealso: DMGetCoarseDM()
    8236: @*/
    8237: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
    8238: {

    8244:   PetscObjectReference((PetscObject)cdm);
    8245:   DMDestroy(&dm->coarseMesh);
    8246:   dm->coarseMesh = cdm;
    8247:   return(0);
    8248: }

    8250: /*@
    8251:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

    8253:   Input Parameter:
    8254: . dm - The DM object

    8256:   Output Parameter:
    8257: . fdm - The fine DM

    8259:   Level: intermediate

    8261: .seealso: DMSetFineDM()
    8262: @*/
    8263: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
    8264: {
    8268:   *fdm = dm->fineMesh;
    8269:   return(0);
    8270: }

    8272: /*@
    8273:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

    8275:   Input Parameters:
    8276: + dm - The DM object
    8277: - fdm - The fine DM

    8279:   Level: intermediate

    8281: .seealso: DMGetFineDM()
    8282: @*/
    8283: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
    8284: {

    8290:   PetscObjectReference((PetscObject)fdm);
    8291:   DMDestroy(&dm->fineMesh);
    8292:   dm->fineMesh = fdm;
    8293:   return(0);
    8294: }

    8296: /*=== DMBoundary code ===*/

    8298: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
    8299: {
    8300:   PetscInt       d;

    8304:   for (d = 0; d < dm->Nds; ++d) {
    8305:     PetscDSCopyBoundary(dm->probs[d].ds, PETSC_DETERMINE, NULL, dmNew->probs[d].ds);
    8306:   }
    8307:   return(0);
    8308: }

    8310: /*@C
    8311:   DMAddBoundary - Add a boundary condition to the model

    8313:   Collective on dm

    8315:   Input Parameters:
    8316: + dm          - The DM, with a PetscDS that matches the problem being constrained
    8317: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8318: . name        - The BC name
    8319: . labelname   - The label defining constrained points
    8320: . field       - The field to constrain
    8321: . numcomps    - The number of constrained field components (0 will constrain all fields)
    8322: . comps       - An array of constrained component numbers
    8323: . bcFunc      - A pointwise function giving boundary values
    8324: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
    8325: . numids      - The number of DMLabel ids for constrained points
    8326: . ids         - An array of ids for constrained points
    8327: - ctx         - An optional user context for bcFunc

    8329:   Options Database Keys:
    8330: + -bc_<boundary name> <num> - Overrides the boundary ids
    8331: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8333:   Note:
    8334:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

    8336: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

    8338:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    8340: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8341: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8342: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8343: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    8345: + dim - the spatial dimension
    8346: . Nf - the number of fields
    8347: . uOff - the offset into u[] and u_t[] for each field
    8348: . uOff_x - the offset into u_x[] for each field
    8349: . u - each field evaluated at the current point
    8350: . u_t - the time derivative of each field evaluated at the current point
    8351: . u_x - the gradient of each field evaluated at the current point
    8352: . aOff - the offset into a[] and a_t[] for each auxiliary field
    8353: . aOff_x - the offset into a_x[] for each auxiliary field
    8354: . a - each auxiliary field evaluated at the current point
    8355: . a_t - the time derivative of each auxiliary field evaluated at the current point
    8356: . a_x - the gradient of auxiliary each field evaluated at the current point
    8357: . t - current time
    8358: . x - coordinates of the current point
    8359: . numConstants - number of constant parameters
    8360: . constants - constant parameters
    8361: - bcval - output values at the current point

    8363:   Level: developer

    8365: .seealso: DMGetBoundary(), PetscDSAddBoundary()
    8366: @*/
    8367: PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), void (*bcFunc_t)(void), PetscInt numids, const PetscInt *ids, void *ctx)
    8368: {
    8369:   PetscDS        ds;

    8378:   DMGetDS(dm, &ds);
    8379:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
    8380:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
    8381:   return(0);
    8382: }

    8384: /*@
    8385:   DMGetNumBoundary - Get the number of registered BC

    8387:   Input Parameters:
    8388: . dm - The mesh object

    8390:   Output Parameters:
    8391: . numBd - The number of BC

    8393:   Level: intermediate

    8395: .seealso: DMAddBoundary(), DMGetBoundary()
    8396: @*/
    8397: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
    8398: {
    8399:   PetscDS        ds;

    8404:   DMGetDS(dm, &ds);
    8405:   PetscDSGetNumBoundary(ds, numBd);
    8406:   return(0);
    8407: }

    8409: /*@C
    8410:   DMGetBoundary - Get a model boundary condition

    8412:   Input Parameters:
    8413: + dm          - The mesh object
    8414: - bd          - The BC number

    8416:   Output Parameters:
    8417: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8418: . name        - The BC name
    8419: . labelname   - The label defining constrained points
    8420: . field       - The field to constrain
    8421: . numcomps    - The number of constrained field components
    8422: . comps       - An array of constrained component numbers
    8423: . bcFunc      - A pointwise function giving boundary values
    8424: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
    8425: . numids      - The number of DMLabel ids for constrained points
    8426: . ids         - An array of ids for constrained points
    8427: - ctx         - An optional user context for bcFunc

    8429:   Options Database Keys:
    8430: + -bc_<boundary name> <num> - Overrides the boundary ids
    8431: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8433:   Level: developer

    8435: .seealso: DMAddBoundary()
    8436: @*/
    8437: PetscErrorCode DMGetBoundary(DM dm, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), void (**func_t)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
    8438: {
    8439:   PetscDS        ds;

    8444:   DMGetDS(dm, &ds);
    8445:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
    8446:   return(0);
    8447: }

    8449: static PetscErrorCode DMPopulateBoundary(DM dm)
    8450: {
    8451:   PetscDS        ds;
    8452:   DMBoundary    *lastnext;
    8453:   DSBoundary     dsbound;

    8457:   DMGetDS(dm, &ds);
    8458:   dsbound = ds->boundary;
    8459:   if (dm->boundary) {
    8460:     DMBoundary next = dm->boundary;

    8462:     /* quick check to see if the PetscDS has changed */
    8463:     if (next->dsboundary == dsbound) return(0);
    8464:     /* the PetscDS has changed: tear down and rebuild */
    8465:     while (next) {
    8466:       DMBoundary b = next;

    8468:       next = b->next;
    8469:       PetscFree(b);
    8470:     }
    8471:     dm->boundary = NULL;
    8472:   }

    8474:   lastnext = &(dm->boundary);
    8475:   while (dsbound) {
    8476:     DMBoundary dmbound;

    8478:     PetscNew(&dmbound);
    8479:     dmbound->dsboundary = dsbound;
    8480:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
    8481:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
    8482:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
    8483:     *lastnext = dmbound;
    8484:     lastnext = &(dmbound->next);
    8485:     dsbound = dsbound->next;
    8486:   }
    8487:   return(0);
    8488: }

    8490: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
    8491: {
    8492:   DMBoundary     b;

    8498:   *isBd = PETSC_FALSE;
    8499:   DMPopulateBoundary(dm);
    8500:   b = dm->boundary;
    8501:   while (b && !(*isBd)) {
    8502:     DMLabel    label = b->label;
    8503:     DSBoundary dsb = b->dsboundary;

    8505:     if (label) {
    8506:       PetscInt i;

    8508:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
    8509:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
    8510:       }
    8511:     }
    8512:     b = b->next;
    8513:   }
    8514:   return(0);
    8515: }

    8517: /*@C
    8518:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

    8520:   Collective on DM

    8522:   Input Parameters:
    8523: + dm      - The DM
    8524: . time    - The time
    8525: . funcs   - The coordinate functions to evaluate, one per field
    8526: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8527: - mode    - The insertion mode for values

    8529:   Output Parameter:
    8530: . X - vector

    8532:    Calling sequence of func:
    8533: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8535: +  dim - The spatial dimension
    8536: .  time - The time at which to sample
    8537: .  x   - The coordinates
    8538: .  Nf  - The number of fields
    8539: .  u   - The output field values
    8540: -  ctx - optional user-defined function context

    8542:   Level: developer

    8544: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8545: @*/
    8546: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
    8547: {
    8548:   Vec            localX;

    8553:   DMGetLocalVector(dm, &localX);
    8554:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
    8555:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8556:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8557:   DMRestoreLocalVector(dm, &localX);
    8558:   return(0);
    8559: }

    8561: /*@C
    8562:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

    8564:   Not collective

    8566:   Input Parameters:
    8567: + dm      - The DM
    8568: . time    - The time
    8569: . funcs   - The coordinate functions to evaluate, one per field
    8570: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8571: - mode    - The insertion mode for values

    8573:   Output Parameter:
    8574: . localX - vector

    8576:    Calling sequence of func:
    8577: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8579: +  dim - The spatial dimension
    8580: .  x   - The coordinates
    8581: .  Nf  - The number of fields
    8582: .  u   - The output field values
    8583: -  ctx - optional user-defined function context

    8585:   Level: developer

    8587: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8588: @*/
    8589: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
    8590: {

    8596:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
    8597:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
    8598:   return(0);
    8599: }

    8601: /*@C
    8602:   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.

    8604:   Collective on DM

    8606:   Input Parameters:
    8607: + dm      - The DM
    8608: . time    - The time
    8609: . label   - The DMLabel selecting the portion of the mesh for projection
    8610: . funcs   - The coordinate functions to evaluate, one per field
    8611: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8612: - mode    - The insertion mode for values

    8614:   Output Parameter:
    8615: . X - vector

    8617:    Calling sequence of func:
    8618: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8620: +  dim - The spatial dimension
    8621: .  x   - The coordinates
    8622: .  Nf  - The number of fields
    8623: .  u   - The output field values
    8624: -  ctx - optional user-defined function context

    8626:   Level: developer

    8628: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
    8629: @*/
    8630: 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)
    8631: {
    8632:   Vec            localX;

    8637:   DMGetLocalVector(dm, &localX);
    8638:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8639:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8640:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8641:   DMRestoreLocalVector(dm, &localX);
    8642:   return(0);
    8643: }

    8645: /*@C
    8646:   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.

    8648:   Not collective

    8650:   Input Parameters:
    8651: + dm      - The DM
    8652: . time    - The time
    8653: . label   - The DMLabel selecting the portion of the mesh for projection
    8654: . funcs   - The coordinate functions to evaluate, one per field
    8655: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8656: - mode    - The insertion mode for values

    8658:   Output Parameter:
    8659: . localX - vector

    8661:    Calling sequence of func:
    8662: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8664: +  dim - The spatial dimension
    8665: .  x   - The coordinates
    8666: .  Nf  - The number of fields
    8667: .  u   - The output field values
    8668: -  ctx - optional user-defined function context

    8670:   Level: developer

    8672: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8673: @*/
    8674: 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)
    8675: {

    8681:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
    8682:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8683:   return(0);
    8684: }

    8686: /*@C
    8687:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

    8689:   Not collective

    8691:   Input Parameters:
    8692: + dm      - The DM
    8693: . time    - The time
    8694: . localU  - The input field vector
    8695: . funcs   - The functions to evaluate, one per field
    8696: - mode    - The insertion mode for values

    8698:   Output Parameter:
    8699: . localX  - The output vector

    8701:    Calling sequence of func:
    8702: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8703: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8704: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8705: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8707: +  dim          - The spatial dimension
    8708: .  Nf           - The number of input fields
    8709: .  NfAux        - The number of input auxiliary fields
    8710: .  uOff         - The offset of each field in u[]
    8711: .  uOff_x       - The offset of each field in u_x[]
    8712: .  u            - The field values at this point in space
    8713: .  u_t          - The field time derivative at this point in space (or NULL)
    8714: .  u_x          - The field derivatives at this point in space
    8715: .  aOff         - The offset of each auxiliary field in u[]
    8716: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8717: .  a            - The auxiliary field values at this point in space
    8718: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8719: .  a_x          - The auxiliary field derivatives at this point in space
    8720: .  t            - The current time
    8721: .  x            - The coordinates of this point
    8722: .  numConstants - The number of constants
    8723: .  constants    - The value of each constant
    8724: -  f            - The value of the function at this point in space

    8726:   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.
    8727:   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
    8728:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8729:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8731:   Level: intermediate

    8733: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8734: @*/
    8735: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
    8736:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
    8737:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8738:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8739:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8740:                                    InsertMode mode, Vec localX)
    8741: {

    8748:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
    8749:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
    8750:   return(0);
    8751: }

    8753: /*@C
    8754:   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.

    8756:   Not collective

    8758:   Input Parameters:
    8759: + dm      - The DM
    8760: . time    - The time
    8761: . label   - The DMLabel marking the portion of the domain to output
    8762: . numIds  - The number of label ids to use
    8763: . ids     - The label ids to use for marking
    8764: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8765: . comps   - The components to set in the output, or NULL for all components
    8766: . localU  - The input field vector
    8767: . funcs   - The functions to evaluate, one per field
    8768: - mode    - The insertion mode for values

    8770:   Output Parameter:
    8771: . localX  - The output vector

    8773:    Calling sequence of func:
    8774: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8775: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8776: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8777: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8779: +  dim          - The spatial dimension
    8780: .  Nf           - The number of input fields
    8781: .  NfAux        - The number of input auxiliary fields
    8782: .  uOff         - The offset of each field in u[]
    8783: .  uOff_x       - The offset of each field in u_x[]
    8784: .  u            - The field values at this point in space
    8785: .  u_t          - The field time derivative at this point in space (or NULL)
    8786: .  u_x          - The field derivatives at this point in space
    8787: .  aOff         - The offset of each auxiliary field in u[]
    8788: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8789: .  a            - The auxiliary field values at this point in space
    8790: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8791: .  a_x          - The auxiliary field derivatives at this point in space
    8792: .  t            - The current time
    8793: .  x            - The coordinates of this point
    8794: .  numConstants - The number of constants
    8795: .  constants    - The value of each constant
    8796: -  f            - The value of the function at this point in space

    8798:   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.
    8799:   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
    8800:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8801:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8803:   Level: intermediate

    8805: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8806: @*/
    8807: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8808:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
    8809:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8810:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8811:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8812:                                         InsertMode mode, Vec localX)
    8813: {

    8820:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
    8821:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8822:   return(0);
    8823: }

    8825: /*@C
    8826:   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.

    8828:   Not collective

    8830:   Input Parameters:
    8831: + dm      - The DM
    8832: . time    - The time
    8833: . label   - The DMLabel marking the portion of the domain boundary to output
    8834: . numIds  - The number of label ids to use
    8835: . ids     - The label ids to use for marking
    8836: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8837: . comps   - The components to set in the output, or NULL for all components
    8838: . localU  - The input field vector
    8839: . funcs   - The functions to evaluate, one per field
    8840: - mode    - The insertion mode for values

    8842:   Output Parameter:
    8843: . localX  - The output vector

    8845:    Calling sequence of func:
    8846: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8847: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8848: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8849: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8851: +  dim          - The spatial dimension
    8852: .  Nf           - The number of input fields
    8853: .  NfAux        - The number of input auxiliary fields
    8854: .  uOff         - The offset of each field in u[]
    8855: .  uOff_x       - The offset of each field in u_x[]
    8856: .  u            - The field values at this point in space
    8857: .  u_t          - The field time derivative at this point in space (or NULL)
    8858: .  u_x          - The field derivatives at this point in space
    8859: .  aOff         - The offset of each auxiliary field in u[]
    8860: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8861: .  a            - The auxiliary field values at this point in space
    8862: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8863: .  a_x          - The auxiliary field derivatives at this point in space
    8864: .  t            - The current time
    8865: .  x            - The coordinates of this point
    8866: .  n            - The face normal
    8867: .  numConstants - The number of constants
    8868: .  constants    - The value of each constant
    8869: -  f            - The value of the function at this point in space

    8871:   Note:
    8872:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8873:   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
    8874:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8875:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8877:   Level: intermediate

    8879: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8880: @*/
    8881: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8882:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
    8883:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8884:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8885:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8886:                                           InsertMode mode, Vec localX)
    8887: {

    8894:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
    8895:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8896:   return(0);
    8897: }

    8899: /*@C
    8900:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

    8902:   Input Parameters:
    8903: + dm    - The DM
    8904: . time  - The time
    8905: . funcs - The functions to evaluate for each field component
    8906: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8907: - X     - The coefficient vector u_h, a global vector

    8909:   Output Parameter:
    8910: . diff - The diff ||u - u_h||_2

    8912:   Level: developer

    8914: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8915: @*/
    8916: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
    8917: {

    8923:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
    8924:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
    8925:   return(0);
    8926: }

    8928: /*@C
    8929:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

    8931:   Collective on dm

    8933:   Input Parameters:
    8934: + dm    - The DM
    8935: , time  - The time
    8936: . funcs - The gradient functions to evaluate for each field component
    8937: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8938: . X     - The coefficient vector u_h, a global vector
    8939: - n     - The vector to project along

    8941:   Output Parameter:
    8942: . diff - The diff ||(grad u - grad u_h) . n||_2

    8944:   Level: developer

    8946: .seealso: DMProjectFunction(), DMComputeL2Diff()
    8947: @*/
    8948: 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)
    8949: {

    8955:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
    8956:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
    8957:   return(0);
    8958: }

    8960: /*@C
    8961:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

    8963:   Collective on dm

    8965:   Input Parameters:
    8966: + dm    - The DM
    8967: . time  - The time
    8968: . funcs - The functions to evaluate for each field component
    8969: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8970: - X     - The coefficient vector u_h, a global vector

    8972:   Output Parameter:
    8973: . diff - The array of differences, ||u^f - u^f_h||_2

    8975:   Level: developer

    8977: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8978: @*/
    8979: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
    8980: {

    8986:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
    8987:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
    8988:   return(0);
    8989: }

    8991: /*@C
    8992:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
    8993:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

    8995:   Collective on dm

    8997:   Input parameters:
    8998: + dm - the pre-adaptation DM object
    8999: - label - label with the flags

    9001:   Output parameters:
    9002: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

    9004:   Level: intermediate

    9006: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
    9007: @*/
    9008: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
    9009: {

    9016:   *dmAdapt = NULL;
    9017:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
    9018:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
    9019:   if (*dmAdapt) {
    9020:     (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
    9021:     PetscFree((*dmAdapt)->vectype);
    9022:     PetscStrallocpy(dm->vectype,(char**)&(*dmAdapt)->vectype);
    9023:     PetscFree((*dmAdapt)->mattype);
    9024:     PetscStrallocpy(dm->mattype,(char**)&(*dmAdapt)->mattype);
    9025:   }
    9026:   return(0);
    9027: }

    9029: /*@C
    9030:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

    9032:   Input Parameters:
    9033: + dm - The DM object
    9034: . metric - The metric to which the mesh is adapted, defined vertex-wise.
    9035: - 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_".

    9037:   Output Parameter:
    9038: . dmAdapt  - Pointer to the DM object containing the adapted mesh

    9040:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

    9042:   Level: advanced

    9044: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
    9045: @*/
    9046: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
    9047: {

    9055:   *dmAdapt = NULL;
    9056:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
    9057:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
    9058:   return(0);
    9059: }

    9061: /*@C
    9062:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

    9064:  Not Collective

    9066:  Input Parameter:
    9067: .  dm    - The DM

    9069:  Output Parameters:
    9070: +  nranks - the number of neighbours
    9071: -  ranks - the neighbors ranks

    9073:  Notes:
    9074:  Do not free the array, it is freed when the DM is destroyed.

    9076:  Level: beginner

    9078:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
    9079: @*/
    9080: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
    9081: {

    9086:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
    9087:   (dm->ops->getneighbors)(dm,nranks,ranks);
    9088:   return(0);
    9089: }

    9091: #include <petsc/private/matimpl.h>

    9093: /*
    9094:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
    9095:     This has be a different function because it requires DM which is not defined in the Mat library
    9096: */
    9097: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
    9098: {

    9102:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9103:     Vec x1local;
    9104:     DM  dm;
    9105:     MatGetDM(J,&dm);
    9106:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
    9107:     DMGetLocalVector(dm,&x1local);
    9108:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
    9109:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
    9110:     x1   = x1local;
    9111:   }
    9112:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
    9113:   if (coloring->ctype == IS_COLORING_LOCAL) {
    9114:     DM  dm;
    9115:     MatGetDM(J,&dm);
    9116:     DMRestoreLocalVector(dm,&x1);
    9117:   }
    9118:   return(0);
    9119: }

    9121: /*@
    9122:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

    9124:     Input Parameter:
    9125: .    coloring - the MatFDColoring object

    9127:     Developer Notes:
    9128:     this routine exists because the PETSc Mat library does not know about the DM objects

    9130:     Level: advanced

    9132: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
    9133: @*/
    9134: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
    9135: {
    9137:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
    9138:   return(0);
    9139: }

    9141: /*@
    9142:     DMGetCompatibility - determine if two DMs are compatible

    9144:     Collective

    9146:     Input Parameters:
    9147: +    dm1 - the first DM
    9148: -    dm2 - the second DM

    9150:     Output Parameters:
    9151: +    compatible - whether or not the two DMs are compatible
    9152: -    set - whether or not the compatible value was set

    9154:     Notes:
    9155:     Two DMs are deemed compatible if they represent the same parallel decomposition
    9156:     of the same topology. This implies that the section (field data) on one
    9157:     "makes sense" with respect to the topology and parallel decomposition of the other.
    9158:     Loosely speaking, compatible DMs represent the same domain and parallel
    9159:     decomposition, but hold different data.

    9161:     Typically, one would confirm compatibility if intending to simultaneously iterate
    9162:     over a pair of vectors obtained from different DMs.

    9164:     For example, two DMDA objects are compatible if they have the same local
    9165:     and global sizes and the same stencil width. They can have different numbers
    9166:     of degrees of freedom per node. Thus, one could use the node numbering from
    9167:     either DM in bounds for a loop over vectors derived from either DM.

    9169:     Consider the operation of summing data living on a 2-dof DMDA to data living
    9170:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
    9171: .vb
    9172:   ...
    9173:   DMGetCompatibility(da1,da2,&compatible,&set);
    9174:   if (set && compatible)  {
    9175:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
    9176:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
    9177:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
    9178:     for (j=y; j<y+n; ++j) {
    9179:       for (i=x; i<x+m, ++i) {
    9180:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
    9181:       }
    9182:     }
    9183:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
    9184:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
    9185:   } else {
    9186:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
    9187:   }
    9188:   ...
    9189: .ve

    9191:     Checking compatibility might be expensive for a given implementation of DM,
    9192:     or might be impossible to unambiguously confirm or deny. For this reason,
    9193:     this function may decline to determine compatibility, and hence users should
    9194:     always check the "set" output parameter.

    9196:     A DM is always compatible with itself.

    9198:     In the current implementation, DMs which live on "unequal" communicators
    9199:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
    9200:     incompatible.

    9202:     This function is labeled "Collective," as information about all subdomains
    9203:     is required on each rank. However, in DM implementations which store all this
    9204:     information locally, this function may be merely "Logically Collective".

    9206:     Developer Notes:
    9207:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
    9208:     iff B is compatible with A. Thus, this function checks the implementations
    9209:     of both dm and dmc (if they are of different types), attempting to determine
    9210:     compatibility. It is left to DM implementers to ensure that symmetry is
    9211:     preserved. The simplest way to do this is, when implementing type-specific
    9212:     logic for this function, is to check for existing logic in the implementation
    9213:     of other DM types and let *set = PETSC_FALSE if found.

    9215:     Level: advanced

    9217: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
    9218: @*/

    9220: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
    9221: {
    9223:   PetscMPIInt    compareResult;
    9224:   DMType         type,type2;
    9225:   PetscBool      sameType;

    9231:   /* Declare a DM compatible with itself */
    9232:   if (dm1 == dm2) {
    9233:     *set = PETSC_TRUE;
    9234:     *compatible = PETSC_TRUE;
    9235:     return(0);
    9236:   }

    9238:   /* Declare a DM incompatible with a DM that lives on an "unequal"
    9239:      communicator. Note that this does not preclude compatibility with
    9240:      DMs living on "congruent" or "similar" communicators, but this must be
    9241:      determined by the implementation-specific logic */
    9242:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
    9243:   if (compareResult == MPI_UNEQUAL) {
    9244:     *set = PETSC_TRUE;
    9245:     *compatible = PETSC_FALSE;
    9246:     return(0);
    9247:   }

    9249:   /* Pass to the implementation-specific routine, if one exists. */
    9250:   if (dm1->ops->getcompatibility) {
    9251:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
    9252:     if (*set) return(0);
    9253:   }

    9255:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
    9256:      with an implementation of this function from dm2 */
    9257:   DMGetType(dm1,&type);
    9258:   DMGetType(dm2,&type2);
    9259:   PetscStrcmp(type,type2,&sameType);
    9260:   if (!sameType && dm2->ops->getcompatibility) {
    9261:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
    9262:   } else {
    9263:     *set = PETSC_FALSE;
    9264:   }
    9265:   return(0);
    9266: }

    9268: /*@C
    9269:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

    9271:   Logically Collective on DM

    9273:   Input Parameters:
    9274: + DM - the DM
    9275: . f - the monitor function
    9276: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
    9277: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

    9279:   Options Database Keys:
    9280: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
    9281:                             does not cancel those set via the options database.

    9283:   Notes:
    9284:   Several different monitoring routines may be set by calling
    9285:   DMMonitorSet() multiple times; all will be called in the
    9286:   order in which they were set.

    9288:   Fortran Notes:
    9289:   Only a single monitor function can be set for each DM object

    9291:   Level: intermediate

    9293: .seealso: DMMonitorCancel()
    9294: @*/
    9295: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
    9296: {
    9297:   PetscInt       m;

    9302:   for (m = 0; m < dm->numbermonitors; ++m) {
    9303:     PetscBool identical;

    9305:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
    9306:     if (identical) return(0);
    9307:   }
    9308:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
    9309:   dm->monitor[dm->numbermonitors]          = f;
    9310:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
    9311:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
    9312:   return(0);
    9313: }

    9315: /*@
    9316:   DMMonitorCancel - Clears all the monitor functions for a DM object.

    9318:   Logically Collective on DM

    9320:   Input Parameter:
    9321: . dm - the DM

    9323:   Options Database Key:
    9324: . -dm_monitor_cancel - cancels all monitors that have been hardwired
    9325:   into a code by calls to DMonitorSet(), but does not cancel those
    9326:   set via the options database

    9328:   Notes:
    9329:   There is no way to clear one specific monitor from a DM object.

    9331:   Level: intermediate

    9333: .seealso: DMMonitorSet()
    9334: @*/
    9335: PetscErrorCode DMMonitorCancel(DM dm)
    9336: {
    9338:   PetscInt       m;

    9342:   for (m = 0; m < dm->numbermonitors; ++m) {
    9343:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
    9344:   }
    9345:   dm->numbermonitors = 0;
    9346:   return(0);
    9347: }

    9349: /*@C
    9350:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

    9352:   Collective on DM

    9354:   Input Parameters:
    9355: + dm   - DM object you wish to monitor
    9356: . name - the monitor type one is seeking
    9357: . help - message indicating what monitoring is done
    9358: . manual - manual page for the monitor
    9359: . monitor - the monitor function
    9360: - 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

    9362:   Output Parameter:
    9363: . flg - Flag set if the monitor was created

    9365:   Level: developer

    9367: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
    9368:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
    9369:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
    9370:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
    9371:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
    9372:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
    9373:           PetscOptionsFList(), PetscOptionsEList()
    9374: @*/
    9375: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
    9376: {
    9377:   PetscViewer       viewer;
    9378:   PetscViewerFormat format;
    9379:   PetscErrorCode    ierr;

    9383:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
    9384:   if (*flg) {
    9385:     PetscViewerAndFormat *vf;

    9387:     PetscViewerAndFormatCreate(viewer, format, &vf);
    9388:     PetscObjectDereference((PetscObject) viewer);
    9389:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
    9390:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
    9391:   }
    9392:   return(0);
    9393: }

    9395: /*@
    9396:    DMMonitor - runs the user provided monitor routines, if they exist

    9398:    Collective on DM

    9400:    Input Parameters:
    9401: .  dm - The DM

    9403:    Level: developer

    9405: .seealso: DMMonitorSet()
    9406: @*/
    9407: PetscErrorCode DMMonitor(DM dm)
    9408: {
    9409:   PetscInt       m;

    9413:   if (!dm) return(0);
    9415:   for (m = 0; m < dm->numbermonitors; ++m) {
    9416:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
    9417:   }
    9418:   return(0);
    9419: }

    9421: /*@
    9422:   DMComputeError - Computes the error assuming the user has given exact solution functions

    9424:   Collective on DM

    9426:   Input Parameters:
    9427: + dm     - The DM
    9428: . sol    - The solution vector
    9429: . errors - An array of length Nf, the number of fields, or NULL for no output
    9430: - errorVec - A Vec pointer, or NULL for no output

    9432:   Output Parameters:
    9433: + errors   - The error in each field
    9434: - errorVec - Creates a vector to hold the cellwise error

    9436:   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().

    9438:   Level: developer

    9440: .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber()
    9441: @*/
    9442: PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
    9443: {
    9444:   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
    9445:   void            **ctxs;
    9446:   PetscReal         time;
    9447:   PetscInt          Nf, f, Nds, s;
    9448:   PetscErrorCode    ierr;

    9451:   DMGetNumFields(dm, &Nf);
    9452:   PetscCalloc2(Nf, &exactSol, Nf, &ctxs);
    9453:   DMGetNumDS(dm, &Nds);
    9454:   for (s = 0; s < Nds; ++s) {
    9455:     PetscDS         ds;
    9456:     DMLabel         label;
    9457:     IS              fieldIS;
    9458:     const PetscInt *fields;
    9459:     PetscInt        dsNf;

    9461:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    9462:     PetscDSGetNumFields(ds, &dsNf);
    9463:     if (fieldIS) {ISGetIndices(fieldIS, &fields);}
    9464:     for (f = 0; f < dsNf; ++f) {
    9465:       const PetscInt field = fields[f];
    9466:       PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]);
    9467:     }
    9468:     if (fieldIS) {ISRestoreIndices(fieldIS, &fields);}
    9469:   }
    9470:   for (f = 0; f < Nf; ++f) {
    9471:     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);
    9472:   }
    9473:   DMGetOutputSequenceNumber(dm, NULL, &time);
    9474:   if (errors) {DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors);}
    9475:   if (errorVec) {
    9476:     DM             edm;
    9477:     DMPolytopeType ct;
    9478:     PetscBool      simplex;
    9479:     PetscInt       dim, cStart, Nf;

    9481:     DMClone(dm, &edm);
    9482:     DMGetDimension(edm, &dim);
    9483:     DMPlexGetHeightStratum(dm, 0, &cStart, NULL);
    9484:     DMPlexGetCellType(dm, cStart, &ct);
    9485:     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
    9486:     DMGetNumFields(dm, &Nf);
    9487:     for (f = 0; f < Nf; ++f) {
    9488:       PetscFE         fe, efe;
    9489:       PetscQuadrature q;
    9490:       const char     *name;

    9492:       DMGetField(dm, f, NULL, (PetscObject *) &fe);
    9493:       PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe);
    9494:       PetscObjectGetName((PetscObject) fe, &name);
    9495:       PetscObjectSetName((PetscObject) efe, name);
    9496:       PetscFEGetQuadrature(fe, &q);
    9497:       PetscFESetQuadrature(efe, q);
    9498:       DMSetField(edm, f, NULL, (PetscObject) efe);
    9499:       PetscFEDestroy(&efe);
    9500:     }
    9501:     DMCreateDS(edm);

    9503:     DMCreateGlobalVector(edm, errorVec);
    9504:     PetscObjectSetName((PetscObject) *errorVec, "Error");
    9505:     DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec);
    9506:     DMDestroy(&edm);
    9507:   }
    9508:   PetscFree2(exactSol, ctxs);
    9509:   return(0);
    9510: }