Date: 2021-03-03T22:26:58+00:00

Actual source code: dm.c
petsc-3.14.5 2021-03-03
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", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL};
     21: /*@
     22:   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().

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

     27:   Collective

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

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

     35:   Level: beginner

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

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

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

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

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

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

     97:   Collective

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

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

    105:   Level: beginner

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

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

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

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

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

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

    177:     DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure);
    178:     DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure);
    179:   }
    180:   return(0);
    181: }

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

    186:    Logically Collective on da

    188:    Input Parameter:
    189: +  da - initial distributed array
    190: .  ctype - the vector type, currently either VECSTANDARD, VECCUDA, or VECVIENNACL

    192:    Options Database:
    193: .   -dm_vec_type ctype

    195:    Level: intermediate

    197: .seealso: DMCreate(), DMDestroy(), DM, DMDAInterpolationType, VecType, DMGetVecType(), DMSetMatType(), DMGetMatType()
    198: @*/
    199: PetscErrorCode  DMSetVecType(DM da,VecType ctype)
    200: {

    205:   PetscFree(da->vectype);
    206:   PetscStrallocpy(ctype,(char**)&da->vectype);
    207:   return(0);
    208: }

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

    213:    Logically Collective on da

    215:    Input Parameter:
    216: .  da - initial distributed array

    218:    Output Parameter:
    219: .  ctype - the vector type

    221:    Level: intermediate

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

    233: /*@
    234:   VecGetDM - Gets the DM defining the data layout of the vector

    236:   Not collective

    238:   Input Parameter:
    239: . v - The Vec

    241:   Output Parameter:
    242: . dm - The DM

    244:   Level: intermediate

    246: .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    247: @*/
    248: PetscErrorCode VecGetDM(Vec v, DM *dm)
    249: {

    255:   PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);
    256:   return(0);
    257: }

    259: /*@
    260:   VecSetDM - Sets the DM defining the data layout of the vector.

    262:   Not collective

    264:   Input Parameters:
    265: + v - The Vec
    266: - dm - The DM

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

    270:   Level: intermediate

    272: .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
    273: @*/
    274: PetscErrorCode VecSetDM(Vec v, DM dm)
    275: {

    281:   PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);
    282:   return(0);
    283: }

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

    288:    Logically Collective on dm

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

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

    297:    Level: intermediate

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

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

    313:    Logically Collective on dm

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

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

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

    324:    Level: intermediate

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

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

    340:    Logically Collective on dm

    342:    Input Parameters:
    343: +  dm - the DM context
    344: -  ctype - the matrix type

    346:    Options Database:
    347: .   -dm_mat_type ctype

    349:    Level: intermediate

    351: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType(), DMSetMatType(), DMGetMatType()
    352: @*/
    353: PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
    354: {

    359:   PetscFree(dm->mattype);
    360:   PetscStrallocpy(ctype,(char**)&dm->mattype);
    361:   return(0);
    362: }

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

    367:    Logically Collective on dm

    369:    Input Parameter:
    370: .  dm - the DM context

    372:    Output Parameter:
    373: .  ctype - the matrix type

    375:    Options Database:
    376: .   -dm_mat_type ctype

    378:    Level: intermediate

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

    390: /*@
    391:   MatGetDM - Gets the DM defining the data layout of the matrix

    393:   Not collective

    395:   Input Parameter:
    396: . A - The Mat

    398:   Output Parameter:
    399: . dm - The DM

    401:   Level: intermediate

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

    406: .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
    407: @*/
    408: PetscErrorCode MatGetDM(Mat A, DM *dm)
    409: {

    415:   PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);
    416:   return(0);
    417: }

    419: /*@
    420:   MatSetDM - Sets the DM defining the data layout of the matrix

    422:   Not collective

    424:   Input Parameters:
    425: + A - The Mat
    426: - dm - The DM

    428:   Level: intermediate

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

    434: .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
    435: @*/
    436: PetscErrorCode MatSetDM(Mat A, DM dm)
    437: {

    443:   PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);
    444:   return(0);
    445: }

    447: /*@C
    448:    DMSetOptionsPrefix - Sets the prefix used for searching for all
    449:    DM options in the database.

    451:    Logically Collective on dm

    453:    Input Parameter:
    454: +  da - the DM context
    455: -  prefix - the prefix to prepend to all option names

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

    461:    Level: advanced

    463: .seealso: DMSetFromOptions()
    464: @*/
    465: PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
    466: {

    471:   PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);
    472:   if (dm->sf) {
    473:     PetscObjectSetOptionsPrefix((PetscObject)dm->sf,prefix);
    474:   }
    475:   if (dm->sectionSF) {
    476:     PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF,prefix);
    477:   }
    478:   return(0);
    479: }

    481: /*@C
    482:    DMAppendOptionsPrefix - Appends to the prefix used for searching for all
    483:    DM options in the database.

    485:    Logically Collective on dm

    487:    Input Parameters:
    488: +  dm - the DM context
    489: -  prefix - the prefix string to prepend to all DM option requests

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

    495:    Level: advanced

    497: .seealso: DMSetOptionsPrefix(), DMGetOptionsPrefix()
    498: @*/
    499: PetscErrorCode  DMAppendOptionsPrefix(DM dm,const char prefix[])
    500: {

    505:   PetscObjectAppendOptionsPrefix((PetscObject)dm,prefix);
    506:   return(0);
    507: }

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

    513:    Not Collective

    515:    Input Parameters:
    516: .  dm - the DM context

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

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

    525:    Level: advanced

    527: .seealso: DMSetOptionsPrefix(), DMAppendOptionsPrefix()
    528: @*/
    529: PetscErrorCode  DMGetOptionsPrefix(DM dm,const char *prefix[])
    530: {

    535:   PetscObjectGetOptionsPrefix((PetscObject)dm,prefix);
    536:   return(0);
    537: }

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

    545:   *ncrefct = 0;
    546:   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
    547:     refct--;
    548:     if (recurseCoarse) {
    549:       PetscInt coarseCount;

    551:       DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE,&coarseCount);
    552:       refct += coarseCount;
    553:     }
    554:   }
    555:   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
    556:     refct--;
    557:     if (recurseFine) {
    558:       PetscInt fineCount;

    560:       DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE,&fineCount);
    561:       refct += fineCount;
    562:     }
    563:   }
    564:   *ncrefct = refct;
    565:   return(0);
    566: }

    568: PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
    569: {
    570:   DMLabelLink    next = dm->labels;

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

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

    588: /*@
    589:     DMDestroy - Destroys a vector packer or DM.

    591:     Collective on dm

    593:     Input Parameter:
    594: .   dm - the DM object to destroy

    596:     Level: developer

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

    600: @*/
    601: PetscErrorCode  DMDestroy(DM *dm)
    602: {
    603:   PetscInt       cnt;
    604:   DMNamedVecLink nlink,nnext;

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

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

    618:   DMClearGlobalVectors(*dm);
    619:   DMClearLocalVectors(*dm);

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

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

    702:       next = b->next;
    703:       PetscFree(b);
    704:     }
    705:   }

    707:   PetscObjectDestroy(&(*dm)->dmksp);
    708:   PetscObjectDestroy(&(*dm)->dmsnes);
    709:   PetscObjectDestroy(&(*dm)->dmts);

    711:   if ((*dm)->ctx && (*dm)->ctxdestroy) {
    712:     (*(*dm)->ctxdestroy)(&(*dm)->ctx);
    713:   }
    714:   MatFDColoringDestroy(&(*dm)->fd);
    715:   ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);
    716:   PetscFree((*dm)->vectype);
    717:   PetscFree((*dm)->mattype);

    719:   PetscSectionDestroy(&(*dm)->localSection);
    720:   PetscSectionDestroy(&(*dm)->globalSection);
    721:   PetscLayoutDestroy(&(*dm)->map);
    722:   PetscSectionDestroy(&(*dm)->defaultConstraintSection);
    723:   MatDestroy(&(*dm)->defaultConstraintMat);
    724:   PetscSFDestroy(&(*dm)->sf);
    725:   PetscSFDestroy(&(*dm)->sectionSF);
    726:   if ((*dm)->useNatural) {
    727:     if ((*dm)->sfNatural) {
    728:       PetscSFDestroy(&(*dm)->sfNatural);
    729:     }
    730:     PetscObjectDereference((PetscObject) (*dm)->sfMigration);
    731:   }
    732:   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) {
    733:     DMSetFineDM((*dm)->coarseMesh,NULL);
    734:   }

    736:   DMDestroy(&(*dm)->coarseMesh);
    737:   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) {
    738:     DMSetCoarseDM((*dm)->fineMesh,NULL);
    739:   }
    740:   DMDestroy(&(*dm)->fineMesh);
    741:   DMFieldDestroy(&(*dm)->coordinateField);
    742:   DMDestroy(&(*dm)->coordinateDM);
    743:   VecDestroy(&(*dm)->coordinates);
    744:   VecDestroy(&(*dm)->coordinatesLocal);
    745:   PetscFree((*dm)->L);
    746:   PetscFree((*dm)->maxCell);
    747:   PetscFree((*dm)->bdtype);
    748:   if ((*dm)->transformDestroy) {(*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx);}
    749:   DMDestroy(&(*dm)->transformDM);
    750:   VecDestroy(&(*dm)->transform);

    752:   DMClearDS(*dm);
    753:   DMDestroy(&(*dm)->dmBC);
    754:   /* if memory was published with SAWs then destroy it */
    755:   PetscObjectSAWsViewOff((PetscObject)*dm);

    757:   if ((*dm)->ops->destroy) {
    758:     (*(*dm)->ops->destroy)(*dm);
    759:   }
    760:   DMMonitorCancel(*dm);
    761:   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
    762:   PetscHeaderDestroy(dm);
    763:   return(0);
    764: }

    766: /*@
    767:     DMSetUp - sets up the data structures inside a DM object

    769:     Collective on dm

    771:     Input Parameter:
    772: .   dm - the DM object to setup

    774:     Level: developer

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

    778: @*/
    779: PetscErrorCode  DMSetUp(DM dm)
    780: {

    785:   if (dm->setupcalled) return(0);
    786:   if (dm->ops->setup) {
    787:     (*dm->ops->setup)(dm);
    788:   }
    789:   dm->setupcalled = PETSC_TRUE;
    790:   return(0);
    791: }

    793: /*@
    794:     DMSetFromOptions - sets parameters in a DM from the options database

    796:     Collective on dm

    798:     Input Parameter:
    799: .   dm - the DM object to set options for

    801:     Options Database:
    802: +   -dm_preallocate_only - Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
    803: .   -dm_vec_type <type>  - type of vector to create inside DM
    804: .   -dm_mat_type <type>  - type of matrix to create inside DM
    805: -   -dm_is_coloring_type - <global or local>

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

    816:     Level: intermediate

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

    821: @*/
    822: PetscErrorCode DMSetFromOptions(DM dm)
    823: {
    824:   char           typeName[256];
    825:   PetscBool      flg;

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

    853: /*@C
    854:    DMViewFromOptions - View from Options

    856:    Collective on DM

    858:    Input Parameters:
    859: +  dm - the DM object
    860: .  obj - Optional object
    861: -  name - command line option

    863:    Level: intermediate
    864: .seealso:  DM, DMView, PetscObjectViewFromOptions(), DMCreate()
    865: @*/
    866: PetscErrorCode  DMViewFromOptions(DM dm,PetscObject obj,const char name[])
    867: {

    872:   PetscObjectViewFromOptions((PetscObject)dm,obj,name);
    873:   return(0);
    874: }

    876: /*@C
    877:     DMView - Views a DM

    879:     Collective on dm

    881:     Input Parameter:
    882: +   dm - the DM object to view
    883: -   v - the viewer

    885:     Level: beginner

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

    889: @*/
    890: PetscErrorCode  DMView(DM dm,PetscViewer v)
    891: {
    892:   PetscErrorCode    ierr;
    893:   PetscBool         isbinary;
    894:   PetscMPIInt       size;
    895:   PetscViewerFormat format;

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

    913:   PetscViewerGetFormat(v,&format);
    914:   MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);
    915:   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) return(0);
    916:   PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);
    917:   PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);
    918:   if (isbinary) {
    919:     PetscInt classid = DM_FILE_CLASSID;
    920:     char     type[256];

    922:     PetscViewerBinaryWrite(v,&classid,1,PETSC_INT);
    923:     PetscStrncpy(type,((PetscObject)dm)->type_name,256);
    924:     PetscViewerBinaryWrite(v,type,256,PETSC_CHAR);
    925:   }
    926:   if (dm->ops->view) {
    927:     (*dm->ops->view)(dm,v);
    928:   }
    929:   return(0);
    930: }

    932: /*@
    933:     DMCreateGlobalVector - Creates a global vector from a DM object

    935:     Collective on dm

    937:     Input Parameter:
    938: .   dm - the DM object

    940:     Output Parameter:
    941: .   vec - the global vector

    943:     Level: beginner

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

    947: @*/
    948: PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
    949: {

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

    960:     VecGetDM(*vec,&vdm);
    961:     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);
    962:   }
    963:   return(0);
    964: }

    966: /*@
    967:     DMCreateLocalVector - Creates a local vector from a DM object

    969:     Not Collective

    971:     Input Parameter:
    972: .   dm - the DM object

    974:     Output Parameter:
    975: .   vec - the local vector

    977:     Level: beginner

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

    981: @*/
    982: PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
    983: {

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

    994:     VecGetDM(*vec,&vdm);
    995:     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);
    996:   }
    997:   return(0);
    998: }

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

    1003:    Collective on dm

    1005:    Input Parameter:
    1006: .  dm - the DM that provides the mapping

    1008:    Output Parameter:
    1009: .  ltog - the mapping

    1011:    Level: intermediate

    1013:    Notes:
    1014:    This mapping can then be used by VecSetLocalToGlobalMapping() or
    1015:    MatSetLocalToGlobalMapping().

    1017: .seealso: DMCreateLocalVector()
    1018: @*/
    1019: PetscErrorCode DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
    1020: {
    1021:   PetscInt       bs = -1, bsLocal[2], bsMinMax[2];

    1027:   if (!dm->ltogmap) {
    1028:     PetscSection section, sectionGlobal;

    1030:     DMGetLocalSection(dm, &section);
    1031:     if (section) {
    1032:       const PetscInt *cdofs;
    1033:       PetscInt       *ltog;
    1034:       PetscInt        pStart, pEnd, n, p, k, l;

    1036:       DMGetGlobalSection(dm, &sectionGlobal);
    1037:       PetscSectionGetChart(section, &pStart, &pEnd);
    1038:       PetscSectionGetStorageSize(section, &n);
    1039:       PetscMalloc1(n, &ltog); /* We want the local+overlap size */
    1040:       for (p = pStart, l = 0; p < pEnd; ++p) {
    1041:         PetscInt bdof, cdof, dof, off, c, cind = 0;

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

    1081: /*@
    1082:    DMGetBlockSize - Gets the inherent block size associated with a DM

    1084:    Not Collective

    1086:    Input Parameter:
    1087: .  dm - the DM with block structure

    1089:    Output Parameter:
    1090: .  bs - the block size, 1 implies no exploitable block structure

    1092:    Level: intermediate

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

    1106: /*@C
    1107:     DMCreateInterpolation - Gets interpolation matrix between two DM objects

    1109:     Collective on dmc

    1111:     Input Parameter:
    1112: +   dmc - the DM object
    1113: -   dmf - the second, finer DM object

    1115:     Output Parameter:
    1116: +  mat - the interpolation
    1117: -  vec - the scaling (optional)

    1119:     Level: developer

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

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

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

    1131: @*/
    1132: PetscErrorCode  DMCreateInterpolation(DM dmc,DM dmf,Mat *mat,Vec *vec)
    1133: {

    1140:   if (!dmc->ops->createinterpolation) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInterpolation",((PetscObject)dmc)->type_name);
    1141:   PetscLogEventBegin(DM_CreateInterpolation,dmc,dmf,0,0);
    1142:   (*dmc->ops->createinterpolation)(dmc,dmf,mat,vec);
    1143:   PetscLogEventEnd(DM_CreateInterpolation,dmc,dmf,0,0);
    1144:   return(0);
    1145: }

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

    1150:   Input Parameters:
    1151: +      dac - DM that defines a coarse mesh
    1152: .      daf - DM that defines a fine mesh
    1153: -      mat - the restriction (or interpolation operator) from fine to coarse

    1155:   Output Parameter:
    1156: .    scale - the scaled vector

    1158:   Level: developer

    1160: .seealso: DMCreateInterpolation()

    1162: @*/
    1163: PetscErrorCode  DMCreateInterpolationScale(DM dac,DM daf,Mat mat,Vec *scale)
    1164: {
    1166:   Vec            fine;
    1167:   PetscScalar    one = 1.0;

    1170:   DMCreateGlobalVector(daf,&fine);
    1171:   DMCreateGlobalVector(dac,scale);
    1172:   VecSet(fine,one);
    1173:   MatRestrict(mat,fine,*scale);
    1174:   VecDestroy(&fine);
    1175:   VecReciprocal(*scale);
    1176:   return(0);
    1177: }

    1179: /*@
    1180:     DMCreateRestriction - Gets restriction matrix between two DM objects

    1182:     Collective on dmc

    1184:     Input Parameter:
    1185: +   dmc - the DM object
    1186: -   dmf - the second, finer DM object

    1188:     Output Parameter:
    1189: .  mat - the restriction

    1192:     Level: developer

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

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

    1201: @*/
    1202: PetscErrorCode  DMCreateRestriction(DM dmc,DM dmf,Mat *mat)
    1203: {

    1210:   if (!dmc->ops->createrestriction) SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_SUP,"DM type %s does not implement DMCreateRestriction",((PetscObject)dmc)->type_name);
    1211:   PetscLogEventBegin(DM_CreateRestriction,dmc,dmf,0,0);
    1212:   (*dmc->ops->createrestriction)(dmc,dmf,mat);
    1213:   PetscLogEventEnd(DM_CreateRestriction,dmc,dmf,0,0);
    1214:   return(0);
    1215: }

    1217: /*@
    1218:     DMCreateInjection - Gets injection matrix between two DM objects

    1220:     Collective on dac

    1222:     Input Parameter:
    1223: +   dac - the DM object
    1224: -   daf - the second, finer DM object

    1226:     Output Parameter:
    1227: .   mat - the injection

    1229:     Level: developer

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

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

    1237: @*/
    1238: PetscErrorCode  DMCreateInjection(DM dac,DM daf,Mat *mat)
    1239: {

    1246:   if (!dac->ops->createinjection) SETERRQ1(PetscObjectComm((PetscObject)dac),PETSC_ERR_SUP,"DM type %s does not implement DMCreateInjection",((PetscObject)dac)->type_name);
    1247:   PetscLogEventBegin(DM_CreateInjection,dac,daf,0,0);
    1248:   (*dac->ops->createinjection)(dac,daf,mat);
    1249:   PetscLogEventEnd(DM_CreateInjection,dac,daf,0,0);
    1250:   return(0);
    1251: }

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

    1256:   Collective on dac

    1258:   Input Parameter:
    1259: + dac - the DM object
    1260: - daf - the second, finer DM object

    1262:   Output Parameter:
    1263: . mat - the interpolation

    1265:   Level: developer

    1267: .seealso DMCreateMatrix(), DMRefine(), DMCoarsen(), DMCreateRestriction(), DMCreateInterpolation(), DMCreateInjection()
    1268: @*/
    1269: PetscErrorCode DMCreateMassMatrix(DM dac, DM daf, Mat *mat)
    1270: {

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

    1282: /*@
    1283:     DMCreateColoring - Gets coloring for a DM

    1285:     Collective on dm

    1287:     Input Parameter:
    1288: +   dm - the DM object
    1289: -   ctype - IS_COLORING_LOCAL or IS_COLORING_GLOBAL

    1291:     Output Parameter:
    1292: .   coloring - the coloring

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

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

    1300:     Level: developer

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

    1304: @*/
    1305: PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
    1306: {

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

    1317: /*@
    1318:     DMCreateMatrix - Gets empty Jacobian for a DM

    1320:     Collective on dm

    1322:     Input Parameter:
    1323: .   dm - the DM object

    1325:     Output Parameter:
    1326: .   mat - the empty Jacobian

    1328:     Level: beginner

    1330:     Notes:
    1331:     This properly preallocates the number of nonzeros in the sparse matrix so you
    1332:        do not need to do it yourself.

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

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

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

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

    1345: @*/
    1346: PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
    1347: {

    1353:   if (!dm->ops->creatematrix) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateMatrix",((PetscObject)dm)->type_name);
    1354:   MatInitializePackage();
    1355:   PetscLogEventBegin(DM_CreateMatrix,0,0,0,0);
    1356:   (*dm->ops->creatematrix)(dm,mat);
    1357:   if (PetscDefined(USE_DEBUG)) {
    1358:     DM mdm;

    1360:     MatGetDM(*mat,&mdm);
    1361:     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);
    1362:   }
    1363:   /* Handle nullspace and near nullspace */
    1364:   if (dm->Nf) {
    1365:     MatNullSpace nullSpace;
    1366:     PetscInt     Nf;

    1368:     DMGetNumFields(dm, &Nf);
    1369:     if (Nf == 1) {
    1370:       if (dm->nullspaceConstructors[0]) {
    1371:         (*dm->nullspaceConstructors[0])(dm, 0, 0, &nullSpace);
    1372:         MatSetNullSpace(*mat, nullSpace);
    1373:         MatNullSpaceDestroy(&nullSpace);
    1374:       }
    1375:       if (dm->nearnullspaceConstructors[0]) {
    1376:         (*dm->nearnullspaceConstructors[0])(dm, 0, 0, &nullSpace);
    1377:         MatSetNearNullSpace(*mat, nullSpace);
    1378:         MatNullSpaceDestroy(&nullSpace);
    1379:       }
    1380:     }
    1381:   }
    1382:   PetscLogEventEnd(DM_CreateMatrix,0,0,0,0);
    1383:   return(0);
    1384: }

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

    1390:   Logically Collective on dm

    1392:   Input Parameter:
    1393: + dm - the DM
    1394: - only - PETSC_TRUE if only want preallocation

    1396:   Level: developer
    1397: .seealso DMCreateMatrix(), DMSetMatrixStructureOnly()
    1398: @*/
    1399: PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
    1400: {
    1403:   dm->prealloc_only = only;
    1404:   return(0);
    1405: }

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

    1411:   Logically Collective on dm

    1413:   Input Parameter:
    1414: + dm - the DM
    1415: - only - PETSC_TRUE if only want matrix stucture

    1417:   Level: developer
    1418: .seealso DMCreateMatrix(), DMSetMatrixPreallocateOnly()
    1419: @*/
    1420: PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
    1421: {
    1424:   dm->structure_only = only;
    1425:   return(0);
    1426: }

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

    1431:   Not Collective

    1433:   Input Parameters:
    1434: + dm - the DM object
    1435: . count - The minium size
    1436: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT)

    1438:   Output Parameter:
    1439: . array - the work array

    1441:   Level: developer

    1443: .seealso DMDestroy(), DMCreate()
    1444: @*/
    1445: PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1446: {
    1448:   DMWorkLink     link;
    1449:   PetscMPIInt    dsize;

    1454:   if (dm->workin) {
    1455:     link       = dm->workin;
    1456:     dm->workin = dm->workin->next;
    1457:   } else {
    1458:     PetscNewLog(dm,&link);
    1459:   }
    1460:   MPI_Type_size(dtype,&dsize);
    1461:   if (((size_t)dsize*count) > link->bytes) {
    1462:     PetscFree(link->mem);
    1463:     PetscMalloc(dsize*count,&link->mem);
    1464:     link->bytes = dsize*count;
    1465:   }
    1466:   link->next   = dm->workout;
    1467:   dm->workout  = link;
    1468: #if defined(PETSC_HAVE_VALGRIND)
    1469:   VALGRIND_MAKE_MEM_NOACCESS((char*)link->mem + (size_t)dsize*count, link->bytes - (size_t)dsize*count);
    1470:   VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize*count);
    1471: #endif
    1472:   *(void**)mem = link->mem;
    1473:   return(0);
    1474: }

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

    1479:   Not Collective

    1481:   Input Parameters:
    1482: + dm - the DM object
    1483: . count - The minium size
    1484: - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT

    1486:   Output Parameter:
    1487: . array - the work array

    1489:   Level: developer

    1491:   Developer Notes:
    1492:     count and dtype are ignored, they are only needed for DMGetWorkArray()
    1493: .seealso DMDestroy(), DMCreate()
    1494: @*/
    1495: PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,MPI_Datatype dtype,void *mem)
    1496: {
    1497:   DMWorkLink *p,link;

    1502:   for (p=&dm->workout; (link=*p); p=&link->next) {
    1503:     if (link->mem == *(void**)mem) {
    1504:       *p           = link->next;
    1505:       link->next   = dm->workin;
    1506:       dm->workin   = link;
    1507:       *(void**)mem = NULL;
    1508:       return(0);
    1509:     }
    1510:   }
    1511:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
    1512: }

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

    1517:   Logically collective on DM

    1519:   Input Parameters:
    1520: + dm     - The DM
    1521: . field  - The field number for the nullspace
    1522: - nullsp - A callback to create the nullspace

    1524:   Notes:
    1525:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1526: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1527: $ dm        - The present DM
    1528: $ origField - The field number given above, in the original DM
    1529: $ field     - The field number in dm
    1530: $ nullSpace - The nullspace for the given field

    1532:   This function is currently not available from Fortran.

    1534: .seealso: DMGetNullSpaceConstructor(), DMSetNearNullSpaceConstructor(), DMGetNearNullSpaceConstructor(), DMCreateSubDM(), DMCreateSuperDM()
    1535: */
    1536: PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
    1537: {
    1540:   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
    1541:   dm->nullspaceConstructors[field] = nullsp;
    1542:   return(0);
    1543: }

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

    1548:   Not collective

    1550:   Input Parameters:
    1551: + dm     - The DM
    1552: - field  - The field number for the nullspace

    1554:   Output Parameter:
    1555: . nullsp - A callback to create the nullspace

    1557:   Notes:
    1558:   The callback is intended to provide nullspaces when function spaces are joined or split, such as in DMCreateSubDM(). The calling sequence is
    1559: $ PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)
    1560: $ dm        - The present DM
    1561: $ origField - The field number given above, in the original DM
    1562: $ field     - The field number in dm
    1563: $ nullSpace - The nullspace for the given field

    1565:   This function is currently not available from Fortran.

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

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

    1582:   Logically collective on DM

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

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

    1597:   This function is currently not available from Fortran.

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

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

    1613:   Not collective

    1615:   Input Parameters:
    1616: + dm     - The DM
    1617: - field  - The field number for the nullspace

    1619:   Output Parameter:
    1620: . nullsp - A callback to create the near-nullspace

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

    1630:   This function is currently not available from Fortran.

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

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

    1647:   Not collective

    1649:   Input Parameter:
    1650: . dm - the DM object

    1652:   Output Parameters:
    1653: + numFields  - The number of fields (or NULL if not requested)
    1654: . fieldNames - The name for each field (or NULL if not requested)
    1655: - fields     - The global indices for each field (or NULL if not requested)

    1657:   Level: intermediate

    1659:   Notes:
    1660:   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
    1661:   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
    1662:   PetscFree().

    1664: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
    1665: @*/
    1666: PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
    1667: {
    1668:   PetscSection   section, sectionGlobal;

    1673:   if (numFields) {
    1675:     *numFields = 0;
    1676:   }
    1677:   if (fieldNames) {
    1679:     *fieldNames = NULL;
    1680:   }
    1681:   if (fields) {
    1683:     *fields = NULL;
    1684:   }
    1685:   DMGetLocalSection(dm, &section);
    1686:   if (section) {
    1687:     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
    1688:     PetscInt nF, f, pStart, pEnd, p;

    1690:     DMGetGlobalSection(dm, &sectionGlobal);
    1691:     PetscSectionGetNumFields(section, &nF);
    1692:     PetscMalloc3(nF,&fieldSizes,nF,&fieldNc,nF,&fieldIndices);
    1693:     PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);
    1694:     for (f = 0; f < nF; ++f) {
    1695:       fieldSizes[f] = 0;
    1696:       PetscSectionGetFieldComponents(section, f, &fieldNc[f]);
    1697:     }
    1698:     for (p = pStart; p < pEnd; ++p) {
    1699:       PetscInt gdof;

    1701:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1702:       if (gdof > 0) {
    1703:         for (f = 0; f < nF; ++f) {
    1704:           PetscInt fdof, fcdof, fpdof;

    1706:           PetscSectionGetFieldDof(section, p, f, &fdof);
    1707:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    1708:           fpdof = fdof-fcdof;
    1709:           if (fpdof && fpdof != fieldNc[f]) {
    1710:             /* Layout does not admit a pointwise block size */
    1711:             fieldNc[f] = 1;
    1712:           }
    1713:           fieldSizes[f] += fpdof;
    1714:         }
    1715:       }
    1716:     }
    1717:     for (f = 0; f < nF; ++f) {
    1718:       PetscMalloc1(fieldSizes[f], &fieldIndices[f]);
    1719:       fieldSizes[f] = 0;
    1720:     }
    1721:     for (p = pStart; p < pEnd; ++p) {
    1722:       PetscInt gdof, goff;

    1724:       PetscSectionGetDof(sectionGlobal, p, &gdof);
    1725:       if (gdof > 0) {
    1726:         PetscSectionGetOffset(sectionGlobal, p, &goff);
    1727:         for (f = 0; f < nF; ++f) {
    1728:           PetscInt fdof, fcdof, fc;

    1730:           PetscSectionGetFieldDof(section, p, f, &fdof);
    1731:           PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);
    1732:           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
    1733:             fieldIndices[f][fieldSizes[f]] = goff++;
    1734:           }
    1735:         }
    1736:       }
    1737:     }
    1738:     if (numFields) *numFields = nF;
    1739:     if (fieldNames) {
    1740:       PetscMalloc1(nF, fieldNames);
    1741:       for (f = 0; f < nF; ++f) {
    1742:         const char *fieldName;

    1744:         PetscSectionGetFieldName(section, f, &fieldName);
    1745:         PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);
    1746:       }
    1747:     }
    1748:     if (fields) {
    1749:       PetscMalloc1(nF, fields);
    1750:       for (f = 0; f < nF; ++f) {
    1751:         PetscInt bs, in[2], out[2];

    1753:         ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);
    1754:         in[0] = -fieldNc[f];
    1755:         in[1] = fieldNc[f];
    1756:         MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));
    1757:         bs    = (-out[0] == out[1]) ? out[1] : 1;
    1758:         ISSetBlockSize((*fields)[f], bs);
    1759:       }
    1760:     }
    1761:     PetscFree3(fieldSizes,fieldNc,fieldIndices);
    1762:   } else if (dm->ops->createfieldis) {
    1763:     (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);
    1764:   }
    1765:   return(0);
    1766: }

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

    1775:   Not collective

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

    1780:   Output Parameters:
    1781: + len       - The number of subproblems in the field decomposition (or NULL if not requested)
    1782: . namelist  - The name for each field (or NULL if not requested)
    1783: . islist    - The global indices for each field (or NULL if not requested)
    1784: - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

    1786:   Level: intermediate

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

    1793: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1794: @*/
    1795: PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
    1796: {

    1801:   if (len) {
    1803:     *len = 0;
    1804:   }
    1805:   if (namelist) {
    1807:     *namelist = NULL;
    1808:   }
    1809:   if (islist) {
    1811:     *islist = NULL;
    1812:   }
    1813:   if (dmlist) {
    1815:     *dmlist = NULL;
    1816:   }
    1817:   /*
    1818:    Is it a good idea to apply the following check across all impls?
    1819:    Perhaps some impls can have a well-defined decomposition before DMSetUp?
    1820:    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
    1821:    */
    1822:   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
    1823:   if (!dm->ops->createfielddecomposition) {
    1824:     PetscSection section;
    1825:     PetscInt     numFields, f;

    1827:     DMGetLocalSection(dm, &section);
    1828:     if (section) {PetscSectionGetNumFields(section, &numFields);}
    1829:     if (section && numFields && dm->ops->createsubdm) {
    1830:       if (len) *len = numFields;
    1831:       if (namelist) {PetscMalloc1(numFields,namelist);}
    1832:       if (islist)   {PetscMalloc1(numFields,islist);}
    1833:       if (dmlist)   {PetscMalloc1(numFields,dmlist);}
    1834:       for (f = 0; f < numFields; ++f) {
    1835:         const char *fieldName;

    1837:         DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);
    1838:         if (namelist) {
    1839:           PetscSectionGetFieldName(section, f, &fieldName);
    1840:           PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);
    1841:         }
    1842:       }
    1843:     } else {
    1844:       DMCreateFieldIS(dm, len, namelist, islist);
    1845:       /* By default there are no DMs associated with subproblems. */
    1846:       if (dmlist) *dmlist = NULL;
    1847:     }
    1848:   } else {
    1849:     (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);
    1850:   }
    1851:   return(0);
    1852: }

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

    1858:   Not collective

    1860:   Input Parameters:
    1861: + dm        - The DM object
    1862: . numFields - The number of fields in this subproblem
    1863: - fields    - The field numbers of the selected fields

    1865:   Output Parameters:
    1866: + is - The global indices for the subproblem
    1867: - subdm - The DM for the subproblem

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

    1871:   Level: intermediate

    1873: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1874: @*/
    1875: PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1876: {

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

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

    1892:   Not collective

    1894:   Input Parameter:
    1895: + dms - The DM objects
    1896: - len - The number of DMs

    1898:   Output Parameters:
    1899: + is - The global indices for the subproblem, or NULL
    1900: - superdm - The DM for the superproblem

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

    1904:   Level: intermediate

    1906: .seealso DMPlexSetMigrationSF(), DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    1907: @*/
    1908: PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt len, IS **is, DM *superdm)
    1909: {
    1910:   PetscInt       i;

    1918:   if (len < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %D", len);
    1919:   if (len) {
    1920:     DM dm = dms[0];
    1921:     if (!dm->ops->createsuperdm) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCreateSuperDM",((PetscObject)dm)->type_name);
    1922:     (*dm->ops->createsuperdm)(dms, len, is, superdm);
    1923:   }
    1924:   return(0);
    1925: }

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

    1935:   Not collective

    1937:   Input Parameter:
    1938: . dm - the DM object

    1940:   Output Parameters:
    1941: + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
    1942: . namelist    - The name for each subdomain (or NULL if not requested)
    1943: . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
    1944: . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
    1945: - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)

    1947:   Level: intermediate

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

    1954: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldDecomposition()
    1955: @*/
    1956: PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
    1957: {
    1958:   PetscErrorCode      ierr;
    1959:   DMSubDomainHookLink link;
    1960:   PetscInt            i,l;

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

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

    1995:   Not collective

    1997:   Input Parameters:
    1998: + dm - the DM object
    1999: . n  - the number of subdomain scatters
    2000: - subdms - the local subdomains

    2002:   Output Parameters:
    2003: + n     - the number of scatters returned
    2004: . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
    2005: . oscat - scatter from global vector to overlapping global vector entries on subdomain
    2006: - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)

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

    2014:   Level: developer

    2016: .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
    2017: @*/
    2018: PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
    2019: {

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

    2030: /*@
    2031:   DMRefine - Refines a DM object

    2033:   Collective on dm

    2035:   Input Parameter:
    2036: + dm   - the DM object
    2037: - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    2039:   Output Parameter:
    2040: . dmf - the refined DM, or NULL

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

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

    2047:   Level: developer

    2049: .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    2050: @*/
    2051: PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
    2052: {
    2053:   PetscErrorCode   ierr;
    2054:   DMRefineHookLink link;

    2058:   if (!dm->ops->refine) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMRefine",((PetscObject)dm)->type_name);
    2059:   PetscLogEventBegin(DM_Refine,dm,0,0,0);
    2060:   (*dm->ops->refine)(dm,comm,dmf);
    2061:   if (*dmf) {
    2062:     (*dmf)->ops->creatematrix = dm->ops->creatematrix;

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

    2066:     (*dmf)->ctx       = dm->ctx;
    2067:     (*dmf)->leveldown = dm->leveldown;
    2068:     (*dmf)->levelup   = dm->levelup + 1;

    2070:     DMSetMatType(*dmf,dm->mattype);
    2071:     for (link=dm->refinehook; link; link=link->next) {
    2072:       if (link->refinehook) {
    2073:         (*link->refinehook)(dm,*dmf,link->ctx);
    2074:       }
    2075:     }
    2076:   }
    2077:   PetscLogEventEnd(DM_Refine,dm,0,0,0);
    2078:   return(0);
    2079: }

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

    2084:    Logically Collective

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

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

    2095: +  coarse - coarse level DM
    2096: .  fine - fine level DM to interpolate problem to
    2097: -  ctx - optional user-defined function context

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

    2102: +  coarse - coarse level DM
    2103: .  interp - matrix interpolating a coarse-level solution to the finer grid
    2104: .  fine - fine level DM to update
    2105: -  ctx - optional user-defined function context

    2107:    Level: advanced

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

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

    2114:    This function is currently not available from Fortran.

    2116: .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2117: @*/
    2118: PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2119: {
    2120:   PetscErrorCode   ierr;
    2121:   DMRefineHookLink link,*p;

    2125:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    2126:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) return(0);
    2127:   }
    2128:   PetscNew(&link);
    2129:   link->refinehook = refinehook;
    2130:   link->interphook = interphook;
    2131:   link->ctx        = ctx;
    2132:   link->next       = NULL;
    2133:   *p               = link;
    2134:   return(0);
    2135: }

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

    2140:    Logically Collective

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

    2148:    Level: advanced

    2150:    Notes:
    2151:    This function does nothing if the hook is not in the list.

    2153:    This function is currently not available from Fortran.

    2155: .seealso: DMCoarsenHookRemove(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2156: @*/
    2157: PetscErrorCode DMRefineHookRemove(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
    2158: {
    2159:   PetscErrorCode   ierr;
    2160:   DMRefineHookLink link,*p;

    2164:   for (p=&coarse->refinehook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    2165:     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
    2166:       link = *p;
    2167:       *p = link->next;
    2168:       PetscFree(link);
    2169:       break;
    2170:     }
    2171:   }
    2172:   return(0);
    2173: }

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

    2178:    Collective if any hooks are

    2180:    Input Arguments:
    2181: +  coarse - coarser DM to use as a base
    2182: .  interp - interpolation matrix, apply using MatInterpolate()
    2183: -  fine - finer DM to update

    2185:    Level: developer

    2187: .seealso: DMRefineHookAdd(), MatInterpolate()
    2188: @*/
    2189: PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
    2190: {
    2191:   PetscErrorCode   ierr;
    2192:   DMRefineHookLink link;

    2195:   for (link=fine->refinehook; link; link=link->next) {
    2196:     if (link->interphook) {
    2197:       (*link->interphook)(coarse,interp,fine,link->ctx);
    2198:     }
    2199:   }
    2200:   return(0);
    2201: }

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

    2206:     Not Collective

    2208:     Input Parameter:
    2209: .   dm - the DM object

    2211:     Output Parameter:
    2212: .   level - number of refinements

    2214:     Level: developer

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

    2218: @*/
    2219: PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
    2220: {
    2223:   *level = dm->levelup;
    2224:   return(0);
    2225: }

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

    2230:     Not Collective

    2232:     Input Parameter:
    2233: +   dm - the DM object
    2234: -   level - number of refinements

    2236:     Level: advanced

    2238:     Notes:
    2239:     This value is used by PCMG to determine how many multigrid levels to use

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

    2243: @*/
    2244: PetscErrorCode  DMSetRefineLevel(DM dm,PetscInt level)
    2245: {
    2248:   dm->levelup = level;
    2249:   return(0);
    2250: }

    2252: PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
    2253: {
    2257:   *tdm = dm->transformDM;
    2258:   return(0);
    2259: }

    2261: PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
    2262: {
    2266:   *tv = dm->transform;
    2267:   return(0);
    2268: }

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

    2273:   Input Parameter:
    2274: . dm - The DM

    2276:   Output Parameter:
    2277: . flg - PETSC_TRUE if a basis transformation should be done

    2279:   Level: developer

    2281: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis(), DMPlexCreateBasisRotation()
    2282: @*/
    2283: PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
    2284: {
    2285:   Vec            tv;

    2291:   DMGetBasisTransformVec_Internal(dm, &tv);
    2292:   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
    2293:   return(0);
    2294: }

    2296: PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
    2297: {
    2298:   PetscSection   s, ts;
    2299:   PetscScalar   *ta;
    2300:   PetscInt       cdim, pStart, pEnd, p, Nf, f, Nc, dof;

    2304:   DMGetCoordinateDim(dm, &cdim);
    2305:   DMGetLocalSection(dm, &s);
    2306:   PetscSectionGetChart(s, &pStart, &pEnd);
    2307:   PetscSectionGetNumFields(s, &Nf);
    2308:   DMClone(dm, &dm->transformDM);
    2309:   DMGetLocalSection(dm->transformDM, &ts);
    2310:   PetscSectionSetNumFields(ts, Nf);
    2311:   PetscSectionSetChart(ts, pStart, pEnd);
    2312:   for (f = 0; f < Nf; ++f) {
    2313:     PetscSectionGetFieldComponents(s, f, &Nc);
    2314:     /* We could start to label fields by their transformation properties */
    2315:     if (Nc != cdim) continue;
    2316:     for (p = pStart; p < pEnd; ++p) {
    2317:       PetscSectionGetFieldDof(s, p, f, &dof);
    2318:       if (!dof) continue;
    2319:       PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim));
    2320:       PetscSectionAddDof(ts, p, PetscSqr(cdim));
    2321:     }
    2322:   }
    2323:   PetscSectionSetUp(ts);
    2324:   DMCreateLocalVector(dm->transformDM, &dm->transform);
    2325:   VecGetArray(dm->transform, &ta);
    2326:   for (p = pStart; p < pEnd; ++p) {
    2327:     for (f = 0; f < Nf; ++f) {
    2328:       PetscSectionGetFieldDof(ts, p, f, &dof);
    2329:       if (dof) {
    2330:         PetscReal          x[3] = {0.0, 0.0, 0.0};
    2331:         PetscScalar       *tva;
    2332:         const PetscScalar *A;

    2334:         /* TODO Get quadrature point for this dual basis vector for coordinate */
    2335:         (*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx);
    2336:         DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *) &tva);
    2337:         PetscArraycpy(tva, A, PetscSqr(cdim));
    2338:       }
    2339:     }
    2340:   }
    2341:   VecRestoreArray(dm->transform, &ta);
    2342:   return(0);
    2343: }

    2345: PetscErrorCode DMCopyTransform(DM dm, DM newdm)
    2346: {

    2352:   newdm->transformCtx       = dm->transformCtx;
    2353:   newdm->transformSetUp     = dm->transformSetUp;
    2354:   newdm->transformDestroy   = NULL;
    2355:   newdm->transformGetMatrix = dm->transformGetMatrix;
    2356:   if (newdm->transformSetUp) {DMConstructBasisTransform_Internal(newdm);}
    2357:   return(0);
    2358: }

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

    2363:    Logically Collective

    2365:    Input Arguments:
    2366: +  dm - the DM
    2367: .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
    2368: .  endhook - function to run after DMGlobalToLocalEnd() has completed
    2369: -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)

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

    2374: +  dm - global DM
    2375: .  g - global vector
    2376: .  mode - mode
    2377: .  l - local vector
    2378: -  ctx - optional user-defined function context

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

    2384: +  global - global DM
    2385: -  ctx - optional user-defined function context

    2387:    Level: advanced

    2389: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    2390: @*/
    2391: PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
    2392: {
    2393:   PetscErrorCode          ierr;
    2394:   DMGlobalToLocalHookLink link,*p;

    2398:   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
    2399:   PetscNew(&link);
    2400:   link->beginhook = beginhook;
    2401:   link->endhook   = endhook;
    2402:   link->ctx       = ctx;
    2403:   link->next      = NULL;
    2404:   *p              = link;
    2405:   return(0);
    2406: }

    2408: static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
    2409: {
    2410:   Mat cMat;
    2411:   Vec cVec;
    2412:   PetscSection section, cSec;
    2413:   PetscInt pStart, pEnd, p, dof;

    2418:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    2419:   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
    2420:     PetscInt nRows;

    2422:     MatGetSize(cMat,&nRows,NULL);
    2423:     if (nRows <= 0) return(0);
    2424:     DMGetLocalSection(dm,&section);
    2425:     MatCreateVecs(cMat,NULL,&cVec);
    2426:     MatMult(cMat,l,cVec);
    2427:     PetscSectionGetChart(cSec,&pStart,&pEnd);
    2428:     for (p = pStart; p < pEnd; p++) {
    2429:       PetscSectionGetDof(cSec,p,&dof);
    2430:       if (dof) {
    2431:         PetscScalar *vals;
    2432:         VecGetValuesSection(cVec,cSec,p,&vals);
    2433:         VecSetValuesSection(l,section,p,vals,INSERT_ALL_VALUES);
    2434:       }
    2435:     }
    2436:     VecDestroy(&cVec);
    2437:   }
    2438:   return(0);
    2439: }

    2441: /*@
    2442:     DMGlobalToLocal - update local vectors from global vector

    2444:     Neighbor-wise Collective on dm

    2446:     Input Parameters:
    2447: +   dm - the DM object
    2448: .   g - the global vector
    2449: .   mode - INSERT_VALUES or ADD_VALUES
    2450: -   l - the local vector

    2452:     Notes:
    2453:     The communication involved in this update can be overlapped with computation by using
    2454:     DMGlobalToLocalBegin() and DMGlobalToLocalEnd().

    2456:     Level: beginner

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

    2460: @*/
    2461: PetscErrorCode DMGlobalToLocal(DM dm,Vec g,InsertMode mode,Vec l)
    2462: {

    2466:   DMGlobalToLocalBegin(dm,g,mode,l);
    2467:   DMGlobalToLocalEnd(dm,g,mode,l);
    2468:   return(0);
    2469: }

    2471: /*@
    2472:     DMGlobalToLocalBegin - Begins updating local vectors from global vector

    2474:     Neighbor-wise Collective on dm

    2476:     Input Parameters:
    2477: +   dm - the DM object
    2478: .   g - the global vector
    2479: .   mode - INSERT_VALUES or ADD_VALUES
    2480: -   l - the local vector

    2482:     Level: intermediate

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

    2486: @*/
    2487: PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
    2488: {
    2489:   PetscSF                 sf;
    2490:   PetscErrorCode          ierr;
    2491:   DMGlobalToLocalHookLink link;

    2496:   for (link=dm->gtolhook; link; link=link->next) {
    2497:     if (link->beginhook) {
    2498:       (*link->beginhook)(dm,g,mode,l,link->ctx);
    2499:     }
    2500:   }
    2501:   DMGetSectionSF(dm, &sf);
    2502:   if (sf) {
    2503:     const PetscScalar *gArray;
    2504:     PetscScalar       *lArray;
    2505:     PetscMemType      lmtype,gmtype;

    2507:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2508:     VecGetArrayInPlace_Internal(l, &lArray, &lmtype);
    2509:     VecGetArrayReadInPlace_Internal(g, &gArray, &gmtype);
    2510:     PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray);
    2511:     VecRestoreArrayInPlace(l, &lArray);
    2512:     VecRestoreArrayReadInPlace(g, &gArray);
    2513:   } else {
    2514:     if (!dm->ops->globaltolocalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalBegin() for type %s",((PetscObject)dm)->type_name);
    2515:     (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2516:   }
    2517:   return(0);
    2518: }

    2520: /*@
    2521:     DMGlobalToLocalEnd - Ends updating local vectors from global vector

    2523:     Neighbor-wise Collective on dm

    2525:     Input Parameters:
    2526: +   dm - the DM object
    2527: .   g - the global vector
    2528: .   mode - INSERT_VALUES or ADD_VALUES
    2529: -   l - the local vector

    2531:     Level: intermediate

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

    2535: @*/
    2536: PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    2537: {
    2538:   PetscSF                 sf;
    2539:   PetscErrorCode          ierr;
    2540:   const PetscScalar      *gArray;
    2541:   PetscScalar            *lArray;
    2542:   PetscBool               transform;
    2543:   DMGlobalToLocalHookLink link;
    2544:   PetscMemType            lmtype,gmtype;

    2548:   DMGetSectionSF(dm, &sf);
    2549:   DMHasBasisTransform(dm, &transform);
    2550:   if (sf) {
    2551:     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);

    2553:     VecGetArrayInPlace_Internal(l, &lArray, &lmtype);
    2554:     VecGetArrayReadInPlace_Internal(g, &gArray, &gmtype);
    2555:     PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);
    2556:     VecRestoreArrayInPlace(l, &lArray);
    2557:     VecRestoreArrayReadInPlace(g, &gArray);
    2558:     if (transform) {DMPlexGlobalToLocalBasis(dm, l);}
    2559:   } else {
    2560:     if (!dm->ops->globaltolocalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMGlobalToLocalEnd() for type %s",((PetscObject)dm)->type_name);
    2561:     (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);
    2562:   }
    2563:   DMGlobalToLocalHook_Constraints(dm,g,mode,l,NULL);
    2564:   for (link=dm->gtolhook; link; link=link->next) {
    2565:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2566:   }
    2567:   return(0);
    2568: }

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

    2573:    Logically Collective

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

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

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

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

    2594: +  global - global DM
    2595: .  l - local vector
    2596: .  mode - mode
    2597: .  g - global vector
    2598: -  ctx - optional user-defined function context

    2600:    Level: advanced

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

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

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

    2631:   DMGetDefaultConstraints(dm,&cSec,&cMat);
    2632:   if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) {
    2633:     PetscInt nRows;

    2635:     MatGetSize(cMat,&nRows,NULL);
    2636:     if (nRows <= 0) return(0);
    2637:     DMGetLocalSection(dm,&section);
    2638:     MatCreateVecs(cMat,NULL,&cVec);
    2639:     PetscSectionGetChart(cSec,&pStart,&pEnd);
    2640:     for (p = pStart; p < pEnd; p++) {
    2641:       PetscSectionGetDof(cSec,p,&dof);
    2642:       if (dof) {
    2643:         PetscInt d;
    2644:         PetscScalar *vals;
    2645:         VecGetValuesSection(l,section,p,&vals);
    2646:         VecSetValuesSection(cVec,cSec,p,vals,mode);
    2647:         /* for this to be the true transpose, we have to zero the values that
    2648:          * we just extracted */
    2649:         for (d = 0; d < dof; d++) {
    2650:           vals[d] = 0.;
    2651:         }
    2652:       }
    2653:     }
    2654:     MatMultTransposeAdd(cMat,cVec,l,l);
    2655:     VecDestroy(&cVec);
    2656:   }
    2657:   return(0);
    2658: }
    2659: /*@
    2660:     DMLocalToGlobal - updates global vectors from local vectors

    2662:     Neighbor-wise Collective on dm

    2664:     Input Parameters:
    2665: +   dm - the DM object
    2666: .   l - the local vector
    2667: .   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.
    2668: -   g - the global vector

    2670:     Notes:
    2671:     The communication involved in this update can be overlapped with computation by using
    2672:     DMLocalToGlobalBegin() and DMLocalToGlobalEnd().

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

    2677:     Level: beginner

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

    2681: @*/
    2682: PetscErrorCode DMLocalToGlobal(DM dm,Vec l,InsertMode mode,Vec g)
    2683: {

    2687:   DMLocalToGlobalBegin(dm,l,mode,g);
    2688:   DMLocalToGlobalEnd(dm,l,mode,g);
    2689:   return(0);
    2690: }

    2692: /*@
    2693:     DMLocalToGlobalBegin - begins updating global vectors from local vectors

    2695:     Neighbor-wise Collective on dm

    2697:     Input Parameters:
    2698: +   dm - the DM object
    2699: .   l - the local vector
    2700: .   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.
    2701: -   g - the global vector

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

    2707:     Level: intermediate

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

    2711: @*/
    2712: PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
    2713: {
    2714:   PetscSF                 sf;
    2715:   PetscSection            s, gs;
    2716:   DMLocalToGlobalHookLink link;
    2717:   Vec                     tmpl;
    2718:   const PetscScalar      *lArray;
    2719:   PetscScalar            *gArray;
    2720:   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
    2721:   PetscErrorCode          ierr;
    2722:   PetscMemType            lmtype=PETSC_MEMTYPE_HOST,gmtype=PETSC_MEMTYPE_HOST;

    2726:   for (link=dm->ltoghook; link; link=link->next) {
    2727:     if (link->beginhook) {
    2728:       (*link->beginhook)(dm,l,mode,g,link->ctx);
    2729:     }
    2730:   }
    2731:   DMLocalToGlobalHook_Constraints(dm,l,mode,g,NULL);
    2732:   DMGetSectionSF(dm, &sf);
    2733:   DMGetLocalSection(dm, &s);
    2734:   switch (mode) {
    2735:   case INSERT_VALUES:
    2736:   case INSERT_ALL_VALUES:
    2737:   case INSERT_BC_VALUES:
    2738:     isInsert = PETSC_TRUE; break;
    2739:   case ADD_VALUES:
    2740:   case ADD_ALL_VALUES:
    2741:   case ADD_BC_VALUES:
    2742:     isInsert = PETSC_FALSE; break;
    2743:   default:
    2744:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2745:   }
    2746:   if ((sf && !isInsert) || (s && isInsert)) {
    2747:     DMHasBasisTransform(dm, &transform);
    2748:     if (transform) {
    2749:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2750:       VecCopy(l, tmpl);
    2751:       DMPlexLocalToGlobalBasis(dm, tmpl);
    2752:       VecGetArrayRead(tmpl, &lArray);
    2753:     } else if (isInsert) {
    2754:       VecGetArrayRead(l, &lArray);
    2755:     } else {
    2756:       VecGetArrayReadInPlace_Internal(l, &lArray, &lmtype);
    2757:       l_inplace = PETSC_TRUE;
    2758:     }
    2759:     if (s && isInsert) {
    2760:       VecGetArray(g, &gArray);
    2761:     } else {
    2762:       VecGetArrayInPlace_Internal(g, &gArray, &gmtype);
    2763:       g_inplace = PETSC_TRUE;
    2764:     }
    2765:     if (sf && !isInsert) {
    2766:       PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM);
    2767:     } else if (s && isInsert) {
    2768:       PetscInt gStart, pStart, pEnd, p;

    2770:       DMGetGlobalSection(dm, &gs);
    2771:       PetscSectionGetChart(s, &pStart, &pEnd);
    2772:       VecGetOwnershipRange(g, &gStart, NULL);
    2773:       for (p = pStart; p < pEnd; ++p) {
    2774:         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;

    2776:         PetscSectionGetDof(s, p, &dof);
    2777:         PetscSectionGetDof(gs, p, &gdof);
    2778:         PetscSectionGetConstraintDof(s, p, &cdof);
    2779:         PetscSectionGetConstraintDof(gs, p, &gcdof);
    2780:         PetscSectionGetOffset(s, p, &off);
    2781:         PetscSectionGetOffset(gs, p, &goff);
    2782:         /* Ignore off-process data and points with no global data */
    2783:         if (!gdof || goff < 0) continue;
    2784:         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);
    2785:         /* If no constraints are enforced in the global vector */
    2786:         if (!gcdof) {
    2787:           for (d = 0; d < dof; ++d) gArray[goff-gStart+d] = lArray[off+d];
    2788:           /* If constraints are enforced in the global vector */
    2789:         } else if (cdof == gcdof) {
    2790:           const PetscInt *cdofs;
    2791:           PetscInt        cind = 0;

    2793:           PetscSectionGetConstraintIndices(s, p, &cdofs);
    2794:           for (d = 0, e = 0; d < dof; ++d) {
    2795:             if ((cind < cdof) && (d == cdofs[cind])) {++cind; continue;}
    2796:             gArray[goff-gStart+e++] = lArray[off+d];
    2797:           }
    2798:         } 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);
    2799:       }
    2800:     }
    2801:     if (g_inplace) {
    2802:       VecRestoreArrayInPlace(g, &gArray);
    2803:     } else {
    2804:       VecRestoreArray(g, &gArray);
    2805:     }
    2806:     if (transform) {
    2807:       VecRestoreArrayRead(tmpl, &lArray);
    2808:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2809:     } else if (l_inplace) {
    2810:       VecRestoreArrayReadInPlace(l, &lArray);
    2811:     } else {
    2812:       VecRestoreArrayRead(l, &lArray);
    2813:     }
    2814:   } else {
    2815:     if (!dm->ops->localtoglobalbegin) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalBegin() for type %s",((PetscObject)dm)->type_name);
    2816:     (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2817:   }
    2818:   return(0);
    2819: }

    2821: /*@
    2822:     DMLocalToGlobalEnd - updates global vectors from local vectors

    2824:     Neighbor-wise Collective on dm

    2826:     Input Parameters:
    2827: +   dm - the DM object
    2828: .   l - the local vector
    2829: .   mode - INSERT_VALUES or ADD_VALUES
    2830: -   g - the global vector

    2832:     Level: intermediate

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

    2836: @*/
    2837: PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
    2838: {
    2839:   PetscSF                 sf;
    2840:   PetscSection            s;
    2841:   DMLocalToGlobalHookLink link;
    2842:   PetscBool               isInsert, transform;
    2843:   PetscErrorCode          ierr;

    2847:   DMGetSectionSF(dm, &sf);
    2848:   DMGetLocalSection(dm, &s);
    2849:   switch (mode) {
    2850:   case INSERT_VALUES:
    2851:   case INSERT_ALL_VALUES:
    2852:     isInsert = PETSC_TRUE; break;
    2853:   case ADD_VALUES:
    2854:   case ADD_ALL_VALUES:
    2855:     isInsert = PETSC_FALSE; break;
    2856:   default:
    2857:     SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
    2858:   }
    2859:   if (sf && !isInsert) {
    2860:     const PetscScalar *lArray;
    2861:     PetscScalar       *gArray;
    2862:     Vec                tmpl;

    2864:     DMHasBasisTransform(dm, &transform);
    2865:     if (transform) {
    2866:       DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2867:       VecGetArrayRead(tmpl, &lArray);
    2868:     } else {
    2869:       VecGetArrayReadInPlace_Internal(l, &lArray, NULL);
    2870:     }
    2871:     VecGetArrayInPlace_Internal(g, &gArray, NULL);
    2872:     PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM);
    2873:     if (transform) {
    2874:       VecRestoreArrayRead(tmpl, &lArray);
    2875:       DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl);
    2876:     } else {
    2877:       VecRestoreArrayReadInPlace(l, &lArray);
    2878:     }
    2879:     VecRestoreArrayInPlace(g, &gArray);
    2880:   } else if (s && isInsert) {
    2881:   } else {
    2882:     if (!dm->ops->localtoglobalend) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing DMLocalToGlobalEnd() for type %s",((PetscObject)dm)->type_name);
    2883:     (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);
    2884:   }
    2885:   for (link=dm->ltoghook; link; link=link->next) {
    2886:     if (link->endhook) {(*link->endhook)(dm,g,mode,l,link->ctx);}
    2887:   }
    2888:   return(0);
    2889: }

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

    2896:    Neighbor-wise Collective on dm

    2898:    Input Parameters:
    2899: +  dm - the DM object
    2900: .  g - the original local vector
    2901: -  mode - one of INSERT_VALUES or ADD_VALUES

    2903:    Output Parameter:
    2904: .  l  - the local vector with correct ghost values

    2906:    Level: intermediate

    2908:    Notes:
    2909:    The local vectors used here need not be the same as those
    2910:    obtained from DMCreateLocalVector(), BUT they
    2911:    must have the same parallel data layout; they could, for example, be
    2912:    obtained with VecDuplicate() from the DM originating vectors.

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

    2916: @*/
    2917: PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
    2918: {
    2919:   PetscErrorCode          ierr;

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

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

    2933:    Neighbor-wise Collective on dm

    2935:    Input Parameters:
    2936: +  da - the DM object
    2937: .  g - the original local vector
    2938: -  mode - one of INSERT_VALUES or ADD_VALUES

    2940:    Output Parameter:
    2941: .  l  - the local vector with correct ghost values

    2943:    Level: intermediate

    2945:    Notes:
    2946:    The local vectors used here need not be the same as those
    2947:    obtained from DMCreateLocalVector(), BUT they
    2948:    must have the same parallel data layout; they could, for example, be
    2949:    obtained with VecDuplicate() from the DM originating vectors.

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

    2953: @*/
    2954: PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
    2955: {
    2956:   PetscErrorCode          ierr;

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

    2966: /*@
    2967:     DMCoarsen - Coarsens a DM object

    2969:     Collective on dm

    2971:     Input Parameter:
    2972: +   dm - the DM object
    2973: -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)

    2975:     Output Parameter:
    2976: .   dmc - the coarsened DM

    2978:     Level: developer

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

    2982: @*/
    2983: PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
    2984: {
    2985:   PetscErrorCode    ierr;
    2986:   DMCoarsenHookLink link;

    2990:   if (!dm->ops->coarsen) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMCoarsen",((PetscObject)dm)->type_name);
    2991:   PetscLogEventBegin(DM_Coarsen,dm,0,0,0);
    2992:   (*dm->ops->coarsen)(dm, comm, dmc);
    2993:   if (*dmc) {
    2994:     DMSetCoarseDM(dm,*dmc);
    2995:     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
    2996:     PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);
    2997:     (*dmc)->ctx               = dm->ctx;
    2998:     (*dmc)->levelup           = dm->levelup;
    2999:     (*dmc)->leveldown         = dm->leveldown + 1;
    3000:     DMSetMatType(*dmc,dm->mattype);
    3001:     for (link=dm->coarsenhook; link; link=link->next) {
    3002:       if (link->coarsenhook) {(*link->coarsenhook)(dm,*dmc,link->ctx);}
    3003:     }
    3004:   }
    3005:   PetscLogEventEnd(DM_Coarsen,dm,0,0,0);
    3006:   if (!(*dmc)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
    3007:   return(0);
    3008: }

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

    3013:    Logically Collective

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

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

    3024: +  fine - fine level DM
    3025: .  coarse - coarse level DM to restrict problem to
    3026: -  ctx - optional user-defined function context

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

    3031: +  fine - fine level DM
    3032: .  mrestrict - matrix restricting a fine-level solution to the coarse grid
    3033: .  rscale - scaling vector for restriction
    3034: .  inject - matrix restricting by injection
    3035: .  coarse - coarse level DM to update
    3036: -  ctx - optional user-defined function context

    3038:    Level: advanced

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

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

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

    3048:    This function is currently not available from Fortran.

    3050: .seealso: DMCoarsenHookRemove(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3051: @*/
    3052: PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3053: {
    3054:   PetscErrorCode    ierr;
    3055:   DMCoarsenHookLink link,*p;

    3059:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3060:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3061:   }
    3062:   PetscNew(&link);
    3063:   link->coarsenhook  = coarsenhook;
    3064:   link->restricthook = restricthook;
    3065:   link->ctx          = ctx;
    3066:   link->next         = NULL;
    3067:   *p                 = link;
    3068:   return(0);
    3069: }

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

    3074:    Logically Collective

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

    3082:    Level: advanced

    3084:    Notes:
    3085:    This function does nothing if the hook is not in the list.

    3087:    This function is currently not available from Fortran.

    3089: .seealso: DMCoarsenHookAdd(), DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3090: @*/
    3091: PetscErrorCode DMCoarsenHookRemove(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
    3092: {
    3093:   PetscErrorCode    ierr;
    3094:   DMCoarsenHookLink link,*p;

    3098:   for (p=&fine->coarsenhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3099:     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3100:       link = *p;
    3101:       *p = link->next;
    3102:       PetscFree(link);
    3103:       break;
    3104:     }
    3105:   }
    3106:   return(0);
    3107: }

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

    3113:    Collective if any hooks are

    3115:    Input Arguments:
    3116: +  fine - finer DM to use as a base
    3117: .  restrct - restriction matrix, apply using MatRestrict()
    3118: .  rscale - scaling vector for restriction
    3119: .  inject - injection matrix, also use MatRestrict()
    3120: -  coarse - coarser DM to update

    3122:    Level: developer

    3124: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3125: @*/
    3126: PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
    3127: {
    3128:   PetscErrorCode    ierr;
    3129:   DMCoarsenHookLink link;

    3132:   for (link=fine->coarsenhook; link; link=link->next) {
    3133:     if (link->restricthook) {
    3134:       (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);
    3135:     }
    3136:   }
    3137:   return(0);
    3138: }

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

    3143:    Logically Collective on global

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

    3152:    Calling sequence for ddhook:
    3153: $    ddhook(DM global,DM block,void *ctx)

    3155: +  global - global DM
    3156: .  block  - block DM
    3157: -  ctx - optional user-defined function context

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

    3162: +  global - global DM
    3163: .  out    - scatter to the outer (with ghost and overlap points) block vector
    3164: .  in     - scatter to block vector values only owned locally
    3165: .  block  - block DM
    3166: -  ctx - optional user-defined function context

    3168:    Level: advanced

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

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

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

    3178:    This function is currently not available from Fortran.

    3180: .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3181: @*/
    3182: PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3183: {
    3184:   PetscErrorCode      ierr;
    3185:   DMSubDomainHookLink link,*p;

    3189:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Scan to the end of the current list of hooks */
    3190:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) return(0);
    3191:   }
    3192:   PetscNew(&link);
    3193:   link->restricthook = restricthook;
    3194:   link->ddhook       = ddhook;
    3195:   link->ctx          = ctx;
    3196:   link->next         = NULL;
    3197:   *p                 = link;
    3198:   return(0);
    3199: }

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

    3204:    Logically Collective

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

    3212:    Level: advanced

    3214:    Notes:

    3216:    This function is currently not available from Fortran.

    3218: .seealso: DMSubDomainHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
    3219: @*/
    3220: PetscErrorCode DMSubDomainHookRemove(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
    3221: {
    3222:   PetscErrorCode      ierr;
    3223:   DMSubDomainHookLink link,*p;

    3227:   for (p=&global->subdomainhook; *p; p=&(*p)->next) { /* Search the list of current hooks */
    3228:     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
    3229:       link = *p;
    3230:       *p = link->next;
    3231:       PetscFree(link);
    3232:       break;
    3233:     }
    3234:   }
    3235:   return(0);
    3236: }

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

    3241:    Collective if any hooks are

    3243:    Input Arguments:
    3244: +  fine - finer DM to use as a base
    3245: .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
    3246: .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
    3247: -  coarse - coarer DM to update

    3249:    Level: developer

    3251: .seealso: DMCoarsenHookAdd(), MatRestrict()
    3252: @*/
    3253: PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
    3254: {
    3255:   PetscErrorCode      ierr;
    3256:   DMSubDomainHookLink link;

    3259:   for (link=global->subdomainhook; link; link=link->next) {
    3260:     if (link->restricthook) {
    3261:       (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);
    3262:     }
    3263:   }
    3264:   return(0);
    3265: }

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

    3270:     Not Collective

    3272:     Input Parameter:
    3273: .   dm - the DM object

    3275:     Output Parameter:
    3276: .   level - number of coarsenings

    3278:     Level: developer

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

    3282: @*/
    3283: PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
    3284: {
    3288:   *level = dm->leveldown;
    3289:   return(0);
    3290: }

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

    3295:     Not Collective

    3297:     Input Parameters:
    3298: +   dm - the DM object
    3299: -   level - number of coarsenings

    3301:     Level: developer

    3303: .seealso DMCoarsen(), DMGetCoarsenLevel(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
    3304: @*/
    3305: PetscErrorCode DMSetCoarsenLevel(DM dm,PetscInt level)
    3306: {
    3309:   dm->leveldown = level;
    3310:   return(0);
    3311: }

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

    3318:     Collective on dm

    3320:     Input Parameter:
    3321: +   dm - the DM object
    3322: -   nlevels - the number of levels of refinement

    3324:     Output Parameter:
    3325: .   dmf - the refined DM hierarchy

    3327:     Level: developer

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

    3331: @*/
    3332: PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
    3333: {

    3338:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3339:   if (nlevels == 0) return(0);
    3341:   if (dm->ops->refinehierarchy) {
    3342:     (*dm->ops->refinehierarchy)(dm,nlevels,dmf);
    3343:   } else if (dm->ops->refine) {
    3344:     PetscInt i;

    3346:     DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);
    3347:     for (i=1; i<nlevels; i++) {
    3348:       DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);
    3349:     }
    3350:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
    3351:   return(0);
    3352: }

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

    3357:     Collective on dm

    3359:     Input Parameter:
    3360: +   dm - the DM object
    3361: -   nlevels - the number of levels of coarsening

    3363:     Output Parameter:
    3364: .   dmc - the coarsened DM hierarchy

    3366:     Level: developer

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

    3370: @*/
    3371: PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
    3372: {

    3377:   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
    3378:   if (nlevels == 0) return(0);
    3380:   if (dm->ops->coarsenhierarchy) {
    3381:     (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);
    3382:   } else if (dm->ops->coarsen) {
    3383:     PetscInt i;

    3385:     DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);
    3386:     for (i=1; i<nlevels; i++) {
    3387:       DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);
    3388:     }
    3389:   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
    3390:   return(0);
    3391: }

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

    3396:     Not Collective

    3398:     Input Parameters:
    3399: +   dm - the DM object
    3400: -   destroy - the destroy function

    3402:     Level: intermediate

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

    3406: @*/
    3407: PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
    3408: {
    3411:   dm->ctxdestroy = destroy;
    3412:   return(0);
    3413: }

    3415: /*@
    3416:     DMSetApplicationContext - Set a user context into a DM object

    3418:     Not Collective

    3420:     Input Parameters:
    3421: +   dm - the DM object
    3422: -   ctx - the user context

    3424:     Level: intermediate

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

    3428: @*/
    3429: PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
    3430: {
    3433:   dm->ctx = ctx;
    3434:   return(0);
    3435: }

    3437: /*@
    3438:     DMGetApplicationContext - Gets a user context from a DM object

    3440:     Not Collective

    3442:     Input Parameter:
    3443: .   dm - the DM object

    3445:     Output Parameter:
    3446: .   ctx - the user context

    3448:     Level: intermediate

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

    3452: @*/
    3453: PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
    3454: {
    3457:   *(void**)ctx = dm->ctx;
    3458:   return(0);
    3459: }

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

    3464:     Logically Collective on dm

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

    3470:     Level: intermediate

    3472: .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
    3473:          DMSetJacobian()

    3475: @*/
    3476: PetscErrorCode DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
    3477: {
    3480:   dm->ops->computevariablebounds = f;
    3481:   return(0);
    3482: }

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

    3487:     Not Collective

    3489:     Input Parameter:
    3490: .   dm - the DM object to destroy

    3492:     Output Parameter:
    3493: .   flg - PETSC_TRUE if the variable bounds function exists

    3495:     Level: developer

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

    3499: @*/
    3500: PetscErrorCode DMHasVariableBounds(DM dm,PetscBool *flg)
    3501: {
    3505:   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
    3506:   return(0);
    3507: }

    3509: /*@C
    3510:     DMComputeVariableBounds - compute variable bounds used by SNESVI.

    3512:     Logically Collective on dm

    3514:     Input Parameters:
    3515: .   dm - the DM object

    3517:     Output parameters:
    3518: +   xl - lower bound
    3519: -   xu - upper bound

    3521:     Level: advanced

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

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

    3528: @*/
    3529: PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
    3530: {

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

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

    3545:     Not Collective

    3547:     Input Parameter:
    3548: .   dm - the DM object

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

    3553:     Level: developer

    3555: .seealso DMCreateColoring()

    3557: @*/
    3558: PetscErrorCode DMHasColoring(DM dm,PetscBool *flg)
    3559: {
    3563:   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
    3564:   return(0);
    3565: }

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

    3570:     Not Collective

    3572:     Input Parameter:
    3573: .   dm - the DM object

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

    3578:     Level: developer

    3580: .seealso DMCreateRestriction()

    3582: @*/
    3583: PetscErrorCode DMHasCreateRestriction(DM dm,PetscBool *flg)
    3584: {
    3588:   *flg =  (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
    3589:   return(0);
    3590: }

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

    3596:     Not Collective

    3598:     Input Parameter:
    3599: .   dm - the DM object

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

    3604:     Level: developer

    3606: .seealso DMCreateInjection()

    3608: @*/
    3609: PetscErrorCode DMHasCreateInjection(DM dm,PetscBool *flg)
    3610: {

    3616:   if (dm->ops->hascreateinjection) {
    3617:     (*dm->ops->hascreateinjection)(dm,flg);
    3618:   } else {
    3619:     *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
    3620:   }
    3621:   return(0);
    3622: }

    3624: PetscFunctionList DMList              = NULL;
    3625: PetscBool         DMRegisterAllCalled = PETSC_FALSE;

    3627: /*@C
    3628:   DMSetType - Builds a DM, for a particular DM implementation.

    3630:   Collective on dm

    3632:   Input Parameters:
    3633: + dm     - The DM object
    3634: - method - The name of the DM type

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

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

    3642:   Level: intermediate

    3644: .seealso: DMGetType(), DMCreate()
    3645: @*/
    3646: PetscErrorCode  DMSetType(DM dm, DMType method)
    3647: {
    3648:   PetscErrorCode (*r)(DM);
    3649:   PetscBool      match;

    3654:   PetscObjectTypeCompare((PetscObject) dm, method, &match);
    3655:   if (match) return(0);

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

    3661:   if (dm->ops->destroy) {
    3662:     (*dm->ops->destroy)(dm);
    3663:   }
    3664:   PetscMemzero(dm->ops,sizeof(*dm->ops));
    3665:   PetscObjectChangeTypeName((PetscObject)dm,method);
    3666:   (*r)(dm);
    3667:   return(0);
    3668: }

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

    3673:   Not Collective

    3675:   Input Parameter:
    3676: . dm  - The DM

    3678:   Output Parameter:
    3679: . type - The DM type name

    3681:   Level: intermediate

    3683: .seealso: DMSetType(), DMCreate()
    3684: @*/
    3685: PetscErrorCode  DMGetType(DM dm, DMType *type)
    3686: {

    3692:   DMRegisterAll();
    3693:   *type = ((PetscObject)dm)->type_name;
    3694:   return(0);
    3695: }

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

    3700:   Collective on dm

    3702:   Input Parameters:
    3703: + dm - the DM
    3704: - newtype - new DM type (use "same" for the same type)

    3706:   Output Parameter:
    3707: . M - pointer to new DM

    3709:   Notes:
    3710:   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
    3711:   the MPI communicator of the generated DM is always the same as the communicator
    3712:   of the input DM.

    3714:   Level: intermediate

    3716: .seealso: DMCreate()
    3717: @*/
    3718: PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
    3719: {
    3720:   DM             B;
    3721:   char           convname[256];
    3722:   PetscBool      sametype/*, issame */;

    3729:   PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);
    3730:   /* PetscStrcmp(newtype, "same", &issame); */
    3731:   if (sametype) {
    3732:     *M   = dm;
    3733:     PetscObjectReference((PetscObject) dm);
    3734:     return(0);
    3735:   } else {
    3736:     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;

    3738:     /*
    3739:        Order of precedence:
    3740:        1) See if a specialized converter is known to the current DM.
    3741:        2) See if a specialized converter is known to the desired DM class.
    3742:        3) See if a good general converter is registered for the desired class
    3743:        4) See if a good general converter is known for the current matrix.
    3744:        5) Use a really basic converter.
    3745:     */

    3747:     /* 1) See if a specialized converter is known to the current DM and the desired class */
    3748:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3749:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3750:     PetscStrlcat(convname,"_",sizeof(convname));
    3751:     PetscStrlcat(convname,newtype,sizeof(convname));
    3752:     PetscStrlcat(convname,"_C",sizeof(convname));
    3753:     PetscObjectQueryFunction((PetscObject)dm,convname,&conv);
    3754:     if (conv) goto foundconv;

    3756:     /* 2)  See if a specialized converter is known to the desired DM class. */
    3757:     DMCreate(PetscObjectComm((PetscObject)dm), &B);
    3758:     DMSetType(B, newtype);
    3759:     PetscStrncpy(convname,"DMConvert_",sizeof(convname));
    3760:     PetscStrlcat(convname,((PetscObject) dm)->type_name,sizeof(convname));
    3761:     PetscStrlcat(convname,"_",sizeof(convname));
    3762:     PetscStrlcat(convname,newtype,sizeof(convname));
    3763:     PetscStrlcat(convname,"_C",sizeof(convname));
    3764:     PetscObjectQueryFunction((PetscObject)B,convname,&conv);
    3765:     if (conv) {
    3766:       DMDestroy(&B);
    3767:       goto foundconv;
    3768:     }

    3770: #if 0
    3771:     /* 3) See if a good general converter is registered for the desired class */
    3772:     conv = B->ops->convertfrom;
    3773:     DMDestroy(&B);
    3774:     if (conv) goto foundconv;

    3776:     /* 4) See if a good general converter is known for the current matrix */
    3777:     if (dm->ops->convert) {
    3778:       conv = dm->ops->convert;
    3779:     }
    3780:     if (conv) goto foundconv;
    3781: #endif

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

    3786: foundconv:
    3787:     PetscLogEventBegin(DM_Convert,dm,0,0,0);
    3788:     (*conv)(dm,newtype,M);
    3789:     /* Things that are independent of DM type: We should consult DMClone() here */
    3790:     {
    3791:       PetscBool             isper;
    3792:       const PetscReal      *maxCell, *L;
    3793:       const DMBoundaryType *bd;
    3794:       DMGetPeriodicity(dm, &isper, &maxCell, &L, &bd);
    3795:       DMSetPeriodicity(*M, isper, maxCell,  L,  bd);
    3796:     }
    3797:     PetscLogEventEnd(DM_Convert,dm,0,0,0);
    3798:   }
    3799:   PetscObjectStateIncrease((PetscObject) *M);
    3800:   return(0);
    3801: }

    3803: /*--------------------------------------------------------------------------------------------------------------------*/

    3805: /*@C
    3806:   DMRegister -  Adds a new DM component implementation

    3808:   Not Collective

    3810:   Input Parameters:
    3811: + name        - The name of a new user-defined creation routine
    3812: - create_func - The creation routine itself

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

    3818:   Sample usage:
    3819: .vb
    3820:     DMRegister("my_da", MyDMCreate);
    3821: .ve

    3823:   Then, your DM type can be chosen with the procedural interface via
    3824: .vb
    3825:     DMCreate(MPI_Comm, DM *);
    3826:     DMSetType(DM,"my_da");
    3827: .ve
    3828:    or at runtime via the option
    3829: .vb
    3830:     -da_type my_da
    3831: .ve

    3833:   Level: advanced

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

    3837: @*/
    3838: PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
    3839: {

    3843:   DMInitializePackage();
    3844:   PetscFunctionListAdd(&DMList,sname,function);
    3845:   return(0);
    3846: }

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

    3851:   Collective on viewer

    3853:   Input Parameters:
    3854: + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
    3855:            some related function before a call to DMLoad().
    3856: - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
    3857:            HDF5 file viewer, obtained from PetscViewerHDF5Open()

    3859:    Level: intermediate

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

    3864:   Notes for advanced users:
    3865:   Most users should not need to know the details of the binary storage
    3866:   format, since DMLoad() and DMView() completely hide these details.
    3867:   But for anyone who's interested, the standard binary matrix storage
    3868:   format is
    3869: .vb
    3870:      has not yet been determined
    3871: .ve

    3873: .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
    3874: @*/
    3875: PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
    3876: {
    3877:   PetscBool      isbinary, ishdf5;

    3883:   PetscViewerCheckReadable(viewer);
    3884:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);
    3885:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);
    3886:   PetscLogEventBegin(DM_Load,viewer,0,0,0);
    3887:   if (isbinary) {
    3888:     PetscInt classid;
    3889:     char     type[256];

    3891:     PetscViewerBinaryRead(viewer,&classid,1,NULL,PETSC_INT);
    3892:     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
    3893:     PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);
    3894:     DMSetType(newdm, type);
    3895:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    3896:   } else if (ishdf5) {
    3897:     if (newdm->ops->load) {(*newdm->ops->load)(newdm,viewer);}
    3898:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
    3899:   PetscLogEventEnd(DM_Load,viewer,0,0,0);
    3900:   return(0);
    3901: }

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

    3906:   Not collective

    3908:   Input Parameter:
    3909: . dm - the DM

    3911:   Output Parameters:
    3912: + lmin - local minimum coordinates (length coord dim, optional)
    3913: - lmax - local maximim coordinates (length coord dim, optional)

    3915:   Level: beginner

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

    3920: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetBoundingBox()
    3921: @*/
    3922: PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[])
    3923: {
    3924:   Vec                coords = NULL;
    3925:   PetscReal          min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
    3926:   PetscReal          max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
    3927:   const PetscScalar *local_coords;
    3928:   PetscInt           N, Ni;
    3929:   PetscInt           cdim, i, j;
    3930:   PetscErrorCode     ierr;

    3934:   DMGetCoordinateDim(dm, &cdim);
    3935:   DMGetCoordinates(dm, &coords);
    3936:   if (coords) {
    3937:     VecGetArrayRead(coords, &local_coords);
    3938:     VecGetLocalSize(coords, &N);
    3939:     Ni   = N/cdim;
    3940:     for (i = 0; i < Ni; ++i) {
    3941:       for (j = 0; j < 3; ++j) {
    3942:         min[j] = j < cdim ? PetscMin(min[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    3943:         max[j] = j < cdim ? PetscMax(max[j], PetscRealPart(local_coords[i*cdim+j])) : 0;
    3944:       }
    3945:     }
    3946:     VecRestoreArrayRead(coords, &local_coords);
    3947:   } else {
    3948:     PetscBool isda;

    3950:     PetscObjectTypeCompare((PetscObject) dm, DMDA, &isda);
    3951:     if (isda) {DMGetLocalBoundingIndices_DMDA(dm, min, max);}
    3952:   }
    3953:   if (lmin) {PetscArraycpy(lmin, min, cdim);}
    3954:   if (lmax) {PetscArraycpy(lmax, max, cdim);}
    3955:   return(0);
    3956: }

    3958: /*@
    3959:   DMGetBoundingBox - Returns the global bounding box for the DM.

    3961:   Collective

    3963:   Input Parameter:
    3964: . dm - the DM

    3966:   Output Parameters:
    3967: + gmin - global minimum coordinates (length coord dim, optional)
    3968: - gmax - global maximim coordinates (length coord dim, optional)

    3970:   Level: beginner

    3972: .seealso: DMGetLocalBoundingBox(), DMGetCoordinates(), DMGetCoordinatesLocal()
    3973: @*/
    3974: PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[])
    3975: {
    3976:   PetscReal      lmin[3], lmax[3];
    3977:   PetscInt       cdim;
    3978:   PetscMPIInt    count;

    3983:   DMGetCoordinateDim(dm, &cdim);
    3984:   PetscMPIIntCast(cdim, &count);
    3985:   DMGetLocalBoundingBox(dm, lmin, lmax);
    3986:   if (gmin) {MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm));}
    3987:   if (gmax) {MPIU_Allreduce(lmax, gmax, count, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject) dm));}
    3988:   return(0);
    3989: }

    3991: /******************************** FEM Support **********************************/

    3993: PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
    3994: {
    3995:   PetscInt       f;

    3999:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
    4000:   for (f = 0; f < len; ++f) {
    4001:     PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));
    4002:   }
    4003:   return(0);
    4004: }

    4006: PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
    4007: {
    4008:   PetscInt       f, g;

    4012:   PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);
    4013:   for (f = 0; f < rows; ++f) {
    4014:     PetscPrintf(PETSC_COMM_SELF, "  |");
    4015:     for (g = 0; g < cols; ++g) {
    4016:       PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));
    4017:     }
    4018:     PetscPrintf(PETSC_COMM_SELF, " |\n");
    4019:   }
    4020:   return(0);
    4021: }

    4023: PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
    4024: {
    4025:   PetscInt          localSize, bs;
    4026:   PetscMPIInt       size;
    4027:   Vec               x, xglob;
    4028:   const PetscScalar *xarray;
    4029:   PetscErrorCode    ierr;

    4032:   MPI_Comm_size(PetscObjectComm((PetscObject) dm),&size);
    4033:   VecDuplicate(X, &x);
    4034:   VecCopy(X, x);
    4035:   VecChop(x, tol);
    4036:   PetscPrintf(PetscObjectComm((PetscObject) dm),"%s:\n",name);
    4037:   if (size > 1) {
    4038:     VecGetLocalSize(x,&localSize);
    4039:     VecGetArrayRead(x,&xarray);
    4040:     VecGetBlockSize(x,&bs);
    4041:     VecCreateMPIWithArray(PetscObjectComm((PetscObject) dm),bs,localSize,PETSC_DETERMINE,xarray,&xglob);
    4042:   } else {
    4043:     xglob = x;
    4044:   }
    4045:   VecView(xglob,PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject) dm)));
    4046:   if (size > 1) {
    4047:     VecDestroy(&xglob);
    4048:     VecRestoreArrayRead(x,&xarray);
    4049:   }
    4050:   VecDestroy(&x);
    4051:   return(0);
    4052: }

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

    4057:   Input Parameter:
    4058: . dm - The DM

    4060:   Output Parameter:
    4061: . section - The PetscSection

    4063:   Options Database Keys:
    4064: . -dm_petscsection_view - View the Section created by the DM

    4066:   Level: advanced

    4068:   Notes:
    4069:   Use DMGetLocalSection() in new code.

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

    4073: .seealso: DMGetLocalSection(), DMSetLocalSection(), DMGetGlobalSection()
    4074: @*/
    4075: PetscErrorCode DMGetSection(DM dm, PetscSection *section)
    4076: {

    4080:   DMGetLocalSection(dm,section);
    4081:   return(0);
    4082: }

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

    4087:   Input Parameter:
    4088: . dm - The DM

    4090:   Output Parameter:
    4091: . section - The PetscSection

    4093:   Options Database Keys:
    4094: . -dm_petscsection_view - View the Section created by the DM

    4096:   Level: intermediate

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

    4100: .seealso: DMSetLocalSection(), DMGetGlobalSection()
    4101: @*/
    4102: PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
    4103: {

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

    4112:     if (dm->setfromoptionscalled) for (d = 0; d < dm->Nds; ++d) {PetscDSSetFromOptions(dm->probs[d].ds);}
    4113:     (*dm->ops->createlocalsection)(dm);
    4114:     if (dm->localSection) {PetscObjectViewFromOptions((PetscObject) dm->localSection, NULL, "-dm_petscsection_view");}
    4115:   }
    4116:   *section = dm->localSection;
    4117:   return(0);
    4118: }

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

    4123:   Input Parameters:
    4124: + dm - The DM
    4125: - section - The PetscSection

    4127:   Level: advanced

    4129:   Notes:
    4130:   Use DMSetLocalSection() in new code.

    4132:   Any existing Section will be destroyed

    4134: .seealso: DMSetLocalSection(), DMGetLocalSection(), DMSetGlobalSection()
    4135: @*/
    4136: PetscErrorCode DMSetSection(DM dm, PetscSection section)
    4137: {

    4141:   DMSetLocalSection(dm,section);
    4142:   return(0);
    4143: }

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

    4148:   Input Parameters:
    4149: + dm - The DM
    4150: - section - The PetscSection

    4152:   Level: intermediate

    4154:   Note: Any existing Section will be destroyed

    4156: .seealso: DMGetLocalSection(), DMSetGlobalSection()
    4157: @*/
    4158: PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
    4159: {
    4160:   PetscInt       numFields = 0;
    4161:   PetscInt       f;

    4167:   PetscObjectReference((PetscObject)section);
    4168:   PetscSectionDestroy(&dm->localSection);
    4169:   dm->localSection = section;
    4170:   if (section) {PetscSectionGetNumFields(dm->localSection, &numFields);}
    4171:   if (numFields) {
    4172:     DMSetNumFields(dm, numFields);
    4173:     for (f = 0; f < numFields; ++f) {
    4174:       PetscObject disc;
    4175:       const char *name;

    4177:       PetscSectionGetFieldName(dm->localSection, f, &name);
    4178:       DMGetField(dm, f, NULL, &disc);
    4179:       PetscObjectSetName(disc, name);
    4180:     }
    4181:   }
    4182:   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
    4183:   PetscSectionDestroy(&dm->globalSection);
    4184:   return(0);
    4185: }

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

    4190:   not collective

    4192:   Input Parameter:
    4193: . dm - The DM

    4195:   Output Parameter:
    4196: + 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.
    4197: - 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.

    4199:   Level: advanced

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

    4203: .seealso: DMSetDefaultConstraints()
    4204: @*/
    4205: PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat)
    4206: {

    4211:   if (!dm->defaultConstraintSection && !dm->defaultConstraintMat && dm->ops->createdefaultconstraints) {(*dm->ops->createdefaultconstraints)(dm);}
    4212:   if (section) {*section = dm->defaultConstraintSection;}
    4213:   if (mat) {*mat = dm->defaultConstraintMat;}
    4214:   return(0);
    4215: }

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

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

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

    4224:   collective on dm

    4226:   Input Parameters:
    4227: + dm - The DM
    4228: + 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).
    4229: - 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).

    4231:   Level: advanced

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

    4235: .seealso: DMGetDefaultConstraints()
    4236: @*/
    4237: PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat)
    4238: {
    4239:   PetscMPIInt result;

    4244:   if (section) {
    4246:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)section),&result);
    4247:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint section must have local communicator");
    4248:   }
    4249:   if (mat) {
    4251:     MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)mat),&result);
    4252:     if (result != MPI_CONGRUENT && result != MPI_IDENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"constraint matrix must have local communicator");
    4253:   }
    4254:   PetscObjectReference((PetscObject)section);
    4255:   PetscSectionDestroy(&dm->defaultConstraintSection);
    4256:   dm->defaultConstraintSection = section;
    4257:   PetscObjectReference((PetscObject)mat);
    4258:   MatDestroy(&dm->defaultConstraintMat);
    4259:   dm->defaultConstraintMat = mat;
    4260:   return(0);
    4261: }

    4263: #if defined(PETSC_USE_DEBUG)
    4264: /*
    4265:   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections.

    4267:   Input Parameters:
    4268: + dm - The DM
    4269: . localSection - PetscSection describing the local data layout
    4270: - globalSection - PetscSection describing the global data layout

    4272:   Level: intermediate

    4274: .seealso: DMGetSectionSF(), DMSetSectionSF()
    4275: */
    4276: static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
    4277: {
    4278:   MPI_Comm        comm;
    4279:   PetscLayout     layout;
    4280:   const PetscInt *ranges;
    4281:   PetscInt        pStart, pEnd, p, nroots;
    4282:   PetscMPIInt     size, rank;
    4283:   PetscBool       valid = PETSC_TRUE, gvalid;
    4284:   PetscErrorCode  ierr;

    4287:   PetscObjectGetComm((PetscObject)dm,&comm);
    4289:   MPI_Comm_size(comm, &size);
    4290:   MPI_Comm_rank(comm, &rank);
    4291:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
    4292:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
    4293:   PetscLayoutCreate(comm, &layout);
    4294:   PetscLayoutSetBlockSize(layout, 1);
    4295:   PetscLayoutSetLocalSize(layout, nroots);
    4296:   PetscLayoutSetUp(layout);
    4297:   PetscLayoutGetRanges(layout, &ranges);
    4298:   for (p = pStart; p < pEnd; ++p) {
    4299:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d;

    4301:     PetscSectionGetDof(localSection, p, &dof);
    4302:     PetscSectionGetOffset(localSection, p, &off);
    4303:     PetscSectionGetConstraintDof(localSection, p, &cdof);
    4304:     PetscSectionGetDof(globalSection, p, &gdof);
    4305:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
    4306:     PetscSectionGetOffset(globalSection, p, &goff);
    4307:     if (!gdof) continue; /* Censored point */
    4308:     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;}
    4309:     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;}
    4310:     if (gdof < 0) {
    4311:       gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
    4312:       for (d = 0; d < gsize; ++d) {
    4313:         PetscInt offset = -(goff+1) + d, r;

    4315:         PetscFindInt(offset,size+1,ranges,&r);
    4316:         if (r < 0) r = -(r+2);
    4317:         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;}
    4318:       }
    4319:     }
    4320:   }
    4321:   PetscLayoutDestroy(&layout);
    4322:   PetscSynchronizedFlush(comm, NULL);
    4323:   MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm);
    4324:   if (!gvalid) {
    4325:     DMView(dm, NULL);
    4326:     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
    4327:   }
    4328:   return(0);
    4329: }
    4330: #endif

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

    4335:   Collective on dm

    4337:   Input Parameter:
    4338: . dm - The DM

    4340:   Output Parameter:
    4341: . section - The PetscSection

    4343:   Level: intermediate

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

    4347: .seealso: DMSetLocalSection(), DMGetLocalSection()
    4348: @*/
    4349: PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
    4350: {

    4356:   if (!dm->globalSection) {
    4357:     PetscSection s;

    4359:     DMGetLocalSection(dm, &s);
    4360:     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
    4361:     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
    4362:     PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection);
    4363:     PetscLayoutDestroy(&dm->map);
    4364:     PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map);
    4365:     PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view");
    4366:   }
    4367:   *section = dm->globalSection;
    4368:   return(0);
    4369: }

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

    4374:   Input Parameters:
    4375: + dm - The DM
    4376: - section - The PetscSection, or NULL

    4378:   Level: intermediate

    4380:   Note: Any existing Section will be destroyed

    4382: .seealso: DMGetGlobalSection(), DMSetLocalSection()
    4383: @*/
    4384: PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
    4385: {

    4391:   PetscObjectReference((PetscObject)section);
    4392:   PetscSectionDestroy(&dm->globalSection);
    4393:   dm->globalSection = section;
    4394: #if defined(PETSC_USE_DEBUG)
    4395:   if (section) {DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section);}
    4396: #endif
    4397:   return(0);
    4398: }

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

    4404:   Input Parameter:
    4405: . dm - The DM

    4407:   Output Parameter:
    4408: . sf - The PetscSF

    4410:   Level: intermediate

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

    4414: .seealso: DMSetSectionSF(), DMCreateSectionSF()
    4415: @*/
    4416: PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
    4417: {
    4418:   PetscInt       nroots;

    4424:   if (!dm->sectionSF) {
    4425:     PetscSFCreate(PetscObjectComm((PetscObject)dm),&dm->sectionSF);
    4426:   }
    4427:   PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL);
    4428:   if (nroots < 0) {
    4429:     PetscSection section, gSection;

    4431:     DMGetLocalSection(dm, &section);
    4432:     if (section) {
    4433:       DMGetGlobalSection(dm, &gSection);
    4434:       DMCreateSectionSF(dm, section, gSection);
    4435:     } else {
    4436:       *sf = NULL;
    4437:       return(0);
    4438:     }
    4439:   }
    4440:   *sf = dm->sectionSF;
    4441:   return(0);
    4442: }

    4444: /*@
    4445:   DMSetSectionSF - Set the PetscSF encoding the parallel dof overlap for the DM

    4447:   Input Parameters:
    4448: + dm - The DM
    4449: - sf - The PetscSF

    4451:   Level: intermediate

    4453:   Note: Any previous SF is destroyed

    4455: .seealso: DMGetSectionSF(), DMCreateSectionSF()
    4456: @*/
    4457: PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
    4458: {

    4464:   PetscObjectReference((PetscObject) sf);
    4465:   PetscSFDestroy(&dm->sectionSF);
    4466:   dm->sectionSF = sf;
    4467:   return(0);
    4468: }

    4470: /*@C
    4471:   DMCreateSectionSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
    4472:   describing the data layout.

    4474:   Input Parameters:
    4475: + dm - The DM
    4476: . localSection - PetscSection describing the local data layout
    4477: - globalSection - PetscSection describing the global data layout

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

    4481:   Level: developer

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

    4487: .seealso: DMGetSectionSF(), DMSetSectionSF(), DMGetLocalSection(), DMGetGlobalSection()
    4488: @*/
    4489: PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
    4490: {
    4491:   MPI_Comm       comm;
    4492:   PetscLayout    layout;
    4493:   const PetscInt *ranges;
    4494:   PetscInt       *local;
    4495:   PetscSFNode    *remote;
    4496:   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
    4497:   PetscMPIInt    size, rank;

    4502:   PetscObjectGetComm((PetscObject)dm,&comm);
    4503:   MPI_Comm_size(comm, &size);
    4504:   MPI_Comm_rank(comm, &rank);
    4505:   PetscSectionGetChart(globalSection, &pStart, &pEnd);
    4506:   PetscSectionGetConstrainedStorageSize(globalSection, &nroots);
    4507:   PetscLayoutCreate(comm, &layout);
    4508:   PetscLayoutSetBlockSize(layout, 1);
    4509:   PetscLayoutSetLocalSize(layout, nroots);
    4510:   PetscLayoutSetUp(layout);
    4511:   PetscLayoutGetRanges(layout, &ranges);
    4512:   for (p = pStart; p < pEnd; ++p) {
    4513:     PetscInt gdof, gcdof;

    4515:     PetscSectionGetDof(globalSection, p, &gdof);
    4516:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
    4517:     if (gcdof > (gdof < 0 ? -(gdof+1) : gdof)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d has %d constraints > %d dof", p, gcdof, (gdof < 0 ? -(gdof+1) : gdof));
    4518:     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
    4519:   }
    4520:   PetscMalloc1(nleaves, &local);
    4521:   PetscMalloc1(nleaves, &remote);
    4522:   for (p = pStart, l = 0; p < pEnd; ++p) {
    4523:     const PetscInt *cind;
    4524:     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;

    4526:     PetscSectionGetDof(localSection, p, &dof);
    4527:     PetscSectionGetOffset(localSection, p, &off);
    4528:     PetscSectionGetConstraintDof(localSection, p, &cdof);
    4529:     PetscSectionGetConstraintIndices(localSection, p, &cind);
    4530:     PetscSectionGetDof(globalSection, p, &gdof);
    4531:     PetscSectionGetConstraintDof(globalSection, p, &gcdof);
    4532:     PetscSectionGetOffset(globalSection, p, &goff);
    4533:     if (!gdof) continue; /* Censored point */
    4534:     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
    4535:     if (gsize != dof-cdof) {
    4536:       if (gsize != dof) SETERRQ4(comm, PETSC_ERR_ARG_WRONG, "Global dof %d for point %d is neither the constrained size %d, nor the unconstrained %d", gsize, p, dof-cdof, dof);
    4537:       cdof = 0; /* Ignore constraints */
    4538:     }
    4539:     for (d = 0, c = 0; d < dof; ++d) {
    4540:       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
    4541:       local[l+d-c] = off+d;
    4542:     }
    4543:     if (gdof < 0) {
    4544:       for (d = 0; d < gsize; ++d, ++l) {
    4545:         PetscInt offset = -(goff+1) + d, r;

    4547:         PetscFindInt(offset,size+1,ranges,&r);
    4548:         if (r < 0) r = -(r+2);
    4549:         if ((r < 0) || (r >= size)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d mapped to invalid process %d (%d, %d)", p, r, gdof, goff);
    4550:         remote[l].rank  = r;
    4551:         remote[l].index = offset - ranges[r];
    4552:       }
    4553:     } else {
    4554:       for (d = 0; d < gsize; ++d, ++l) {
    4555:         remote[l].rank  = rank;
    4556:         remote[l].index = goff+d - ranges[rank];
    4557:       }
    4558:     }
    4559:   }
    4560:   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
    4561:   PetscLayoutDestroy(&layout);
    4562:   PetscSFSetGraph(dm->sectionSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);
    4563:   return(0);
    4564: }

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

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

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

    4575:   Level: intermediate

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

    4579: .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4580: @*/
    4581: PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
    4582: {
    4586:   *sf = dm->sf;
    4587:   return(0);
    4588: }

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

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

    4597:   Level: intermediate

    4599: .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
    4600: @*/
    4601: PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
    4602: {

    4608:   PetscObjectReference((PetscObject) sf);
    4609:   PetscSFDestroy(&dm->sf);
    4610:   dm->sf = sf;
    4611:   return(0);
    4612: }

    4614: static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
    4615: {
    4616:   PetscClassId   id;

    4620:   PetscObjectGetClassId(disc, &id);
    4621:   if (id == PETSCFE_CLASSID) {
    4622:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
    4623:   } else if (id == PETSCFV_CLASSID) {
    4624:     DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);
    4625:   } else {
    4626:     DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);
    4627:   }
    4628:   return(0);
    4629: }

    4631: static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
    4632: {
    4633:   RegionField   *tmpr;
    4634:   PetscInt       Nf = dm->Nf, f;

    4638:   if (Nf >= NfNew) return(0);
    4639:   PetscMalloc1(NfNew, &tmpr);
    4640:   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
    4641:   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL;}
    4642:   PetscFree(dm->fields);
    4643:   dm->Nf     = NfNew;
    4644:   dm->fields = tmpr;
    4645:   return(0);
    4646: }

    4648: /*@
    4649:   DMClearFields - Remove all fields from the DM

    4651:   Logically collective on dm

    4653:   Input Parameter:
    4654: . dm - The DM

    4656:   Level: intermediate

    4658: .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
    4659: @*/
    4660: PetscErrorCode DMClearFields(DM dm)
    4661: {
    4662:   PetscInt       f;

    4667:   for (f = 0; f < dm->Nf; ++f) {
    4668:     PetscObjectDestroy(&dm->fields[f].disc);
    4669:     DMLabelDestroy(&dm->fields[f].label);
    4670:   }
    4671:   PetscFree(dm->fields);
    4672:   dm->fields = NULL;
    4673:   dm->Nf     = 0;
    4674:   return(0);
    4675: }

    4677: /*@
    4678:   DMGetNumFields - Get the number of fields in the DM

    4680:   Not collective

    4682:   Input Parameter:
    4683: . dm - The DM

    4685:   Output Parameter:
    4686: . Nf - The number of fields

    4688:   Level: intermediate

    4690: .seealso: DMSetNumFields(), DMSetField()
    4691: @*/
    4692: PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
    4693: {
    4697:   *numFields = dm->Nf;
    4698:   return(0);
    4699: }

    4701: /*@
    4702:   DMSetNumFields - Set the number of fields in the DM

    4704:   Logically collective on dm

    4706:   Input Parameters:
    4707: + dm - The DM
    4708: - Nf - The number of fields

    4710:   Level: intermediate

    4712: .seealso: DMGetNumFields(), DMSetField()
    4713: @*/
    4714: PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
    4715: {
    4716:   PetscInt       Nf, f;

    4721:   DMGetNumFields(dm, &Nf);
    4722:   for (f = Nf; f < numFields; ++f) {
    4723:     PetscContainer obj;

    4725:     PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);
    4726:     DMAddField(dm, NULL, (PetscObject) obj);
    4727:     PetscContainerDestroy(&obj);
    4728:   }
    4729:   return(0);
    4730: }

    4732: /*@
    4733:   DMGetField - Return the discretization object for a given DM field

    4735:   Not collective

    4737:   Input Parameters:
    4738: + dm - The DM
    4739: - f  - The field number

    4741:   Output Parameters:
    4742: + label - The label indicating the support of the field, or NULL for the entire mesh
    4743: - field - The discretization object

    4745:   Level: intermediate

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

    4760: /* Does not clear the DS */
    4761: PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4762: {

    4766:   DMFieldEnlarge_Static(dm, f+1);
    4767:   DMLabelDestroy(&dm->fields[f].label);
    4768:   PetscObjectDestroy(&dm->fields[f].disc);
    4769:   dm->fields[f].label = label;
    4770:   dm->fields[f].disc  = field;
    4771:   PetscObjectReference((PetscObject) label);
    4772:   PetscObjectReference((PetscObject) field);
    4773:   return(0);
    4774: }

    4776: /*@
    4777:   DMSetField - Set the discretization object for a given DM field

    4779:   Logically collective on dm

    4781:   Input Parameters:
    4782: + dm    - The DM
    4783: . f     - The field number
    4784: . label - The label indicating the support of the field, or NULL for the entire mesh
    4785: - field - The discretization object

    4787:   Level: intermediate

    4789: .seealso: DMAddField(), DMGetField()
    4790: @*/
    4791: PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
    4792: {

    4799:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    4800:   DMSetField_Internal(dm, f, label, field);
    4801:   DMSetDefaultAdjacency_Private(dm, f, field);
    4802:   DMClearDS(dm);
    4803:   return(0);
    4804: }

    4806: /*@
    4807:   DMAddField - Add the discretization object for the given DM field

    4809:   Logically collective on dm

    4811:   Input Parameters:
    4812: + dm    - The DM
    4813: . label - The label indicating the support of the field, or NULL for the entire mesh
    4814: - field - The discretization object

    4816:   Level: intermediate

    4818: .seealso: DMSetField(), DMGetField()
    4819: @*/
    4820: PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
    4821: {
    4822:   PetscInt       Nf = dm->Nf;

    4829:   DMFieldEnlarge_Static(dm, Nf+1);
    4830:   dm->fields[Nf].label = label;
    4831:   dm->fields[Nf].disc  = field;
    4832:   PetscObjectReference((PetscObject) label);
    4833:   PetscObjectReference((PetscObject) field);
    4834:   DMSetDefaultAdjacency_Private(dm, Nf, field);
    4835:   DMClearDS(dm);
    4836:   return(0);
    4837: }

    4839: /*@
    4840:   DMCopyFields - Copy the discretizations for the DM into another DM

    4842:   Collective on dm

    4844:   Input Parameter:
    4845: . dm - The DM

    4847:   Output Parameter:
    4848: . newdm - The DM

    4850:   Level: advanced

    4852: .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
    4853: @*/
    4854: PetscErrorCode DMCopyFields(DM dm, DM newdm)
    4855: {
    4856:   PetscInt       Nf, f;

    4860:   if (dm == newdm) return(0);
    4861:   DMGetNumFields(dm, &Nf);
    4862:   DMClearFields(newdm);
    4863:   for (f = 0; f < Nf; ++f) {
    4864:     DMLabel     label;
    4865:     PetscObject field;
    4866:     PetscBool   useCone, useClosure;

    4868:     DMGetField(dm, f, &label, &field);
    4869:     DMSetField(newdm, f, label, field);
    4870:     DMGetAdjacency(dm, f, &useCone, &useClosure);
    4871:     DMSetAdjacency(newdm, f, useCone, useClosure);
    4872:   }
    4873:   return(0);
    4874: }

    4876: /*@
    4877:   DMGetAdjacency - Returns the flags for determining variable influence

    4879:   Not collective

    4881:   Input Parameters:
    4882: + dm - The DM object
    4883: - f  - The field number, or PETSC_DEFAULT for the default adjacency

    4885:   Output Parameter:
    4886: + useCone    - Flag for variable influence starting with the cone operation
    4887: - useClosure - Flag for variable influence using transitive closure

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

    4895:   Level: developer

    4897: .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
    4898: @*/
    4899: PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
    4900: {
    4905:   if (f < 0) {
    4906:     if (useCone)    *useCone    = dm->adjacency[0];
    4907:     if (useClosure) *useClosure = dm->adjacency[1];
    4908:   } else {
    4909:     PetscInt       Nf;

    4912:     DMGetNumFields(dm, &Nf);
    4913:     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
    4914:     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
    4915:     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
    4916:   }
    4917:   return(0);
    4918: }

    4920: /*@
    4921:   DMSetAdjacency - Set the flags for determining variable influence

    4923:   Not collective

    4925:   Input Parameters:
    4926: + dm         - The DM object
    4927: . f          - The field number
    4928: . useCone    - Flag for variable influence starting with the cone operation
    4929: - useClosure - Flag for variable influence using transitive closure

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

    4937:   Level: developer

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

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

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

    4963:   Not collective

    4965:   Input Parameters:
    4966: . dm - The DM object

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

    4972:   Notes:
    4973: $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
    4974: $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
    4975: $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE

    4977:   Level: developer

    4979: .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
    4980: @*/
    4981: PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
    4982: {
    4983:   PetscInt       Nf;

    4990:   DMGetNumFields(dm, &Nf);
    4991:   if (!Nf) {
    4992:     DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    4993:   } else {
    4994:     DMGetAdjacency(dm, 0, useCone, useClosure);
    4995:   }
    4996:   return(0);
    4997: }

    4999: /*@
    5000:   DMSetBasicAdjacency - Set 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
    5006: . useCone    - Flag for variable influence starting with the cone operation
    5007: - useClosure - Flag for variable influence using transitive closure

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

    5014:   Level: developer

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

    5025:   DMGetNumFields(dm, &Nf);
    5026:   if (!Nf) {
    5027:     DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);
    5028:   } else {
    5029:     DMSetAdjacency(dm, 0, useCone, useClosure);
    5030:   }
    5031:   return(0);
    5032: }

    5034: /* Complete labels that are being used for FEM BC */
    5035: static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
    5036: {
    5037:   DMLabel        label;
    5038:   PetscObject    obj;
    5039:   PetscClassId   id;
    5040:   PetscInt       Nbd, bd;
    5041:   PetscBool      isFE      = PETSC_FALSE;
    5042:   PetscBool      duplicate = PETSC_FALSE;

    5046:   DMGetField(dm, field, NULL, &obj);
    5047:   PetscObjectGetClassId(obj, &id);
    5048:   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
    5049:   DMGetLabel(dm, labelname, &label);
    5050:   if (isFE && label) {
    5051:     /* Only want to modify label once */
    5052:     PetscDSGetNumBoundary(ds, &Nbd);
    5053:     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
    5054:       const char *lname;

    5056:       PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5057:       PetscStrcmp(lname, labelname, &duplicate);
    5058:       if (duplicate) break;
    5059:     }
    5060:     if (!duplicate) {
    5061:       DM plex;

    5063:       DMConvert(dm, DMPLEX, &plex);
    5064:       if (plex) {DMPlexLabelComplete(plex, label);}
    5065:       DMDestroy(&plex);
    5066:     }
    5067:   }
    5068:   return(0);
    5069: }

    5071: static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
    5072: {
    5073:   DMSpace       *tmpd;
    5074:   PetscInt       Nds = dm->Nds, s;

    5078:   if (Nds >= NdsNew) return(0);
    5079:   PetscMalloc1(NdsNew, &tmpd);
    5080:   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
    5081:   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
    5082:   PetscFree(dm->probs);
    5083:   dm->Nds   = NdsNew;
    5084:   dm->probs = tmpd;
    5085:   return(0);
    5086: }

    5088: /*@
    5089:   DMGetNumDS - Get the number of discrete systems in the DM

    5091:   Not collective

    5093:   Input Parameter:
    5094: . dm - The DM

    5096:   Output Parameter:
    5097: . Nds - The number of PetscDS objects

    5099:   Level: intermediate

    5101: .seealso: DMGetDS(), DMGetCellDS()
    5102: @*/
    5103: PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
    5104: {
    5108:   *Nds = dm->Nds;
    5109:   return(0);
    5110: }

    5112: /*@
    5113:   DMClearDS - Remove all discrete systems from the DM

    5115:   Logically collective on dm

    5117:   Input Parameter:
    5118: . dm - The DM

    5120:   Level: intermediate

    5122: .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
    5123: @*/
    5124: PetscErrorCode DMClearDS(DM dm)
    5125: {
    5126:   PetscInt       s;

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

    5142: /*@
    5143:   DMGetDS - Get the default PetscDS

    5145:   Not collective

    5147:   Input Parameter:
    5148: . dm    - The DM

    5150:   Output Parameter:
    5151: . prob - The default PetscDS

    5153:   Level: intermediate

    5155: .seealso: DMGetCellDS(), DMGetRegionDS()
    5156: @*/
    5157: PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
    5158: {

    5164:   if (dm->Nds <= 0) {
    5165:     PetscDS ds;

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

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

    5178:   Not collective

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

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

    5187:   Level: developer

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

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

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

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

    5218:   Not collective

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

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

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

    5230:   Level: advanced

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

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

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

    5256:   Collective on dm

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

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

    5267:   Level: advanced

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

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

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

    5305:   Not collective

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

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

    5316:   Level: advanced

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

    5327:   DMGetNumDS(dm, &Nds);
    5328:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5329:   if (label) {
    5331:     *label = dm->probs[num].label;
    5332:   }
    5333:   if (fields) {
    5335:     *fields = dm->probs[num].fields;
    5336:   }
    5337:   if (ds) {
    5339:     *ds = dm->probs[num].ds;
    5340:   }
    5341:   return(0);
    5342: }

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

    5347:   Not collective

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

    5356:   Level: advanced

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

    5368:   DMGetNumDS(dm, &Nds);
    5369:   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
    5370:   PetscObjectReference((PetscObject) label);
    5371:   DMLabelDestroy(&dm->probs[num].label);
    5372:   dm->probs[num].label = label;
    5373:   if (fields) {
    5375:     PetscObjectReference((PetscObject) fields);
    5376:     ISDestroy(&dm->probs[num].fields);
    5377:     dm->probs[num].fields = fields;
    5378:   }
    5379:   if (ds) {
    5381:     PetscObjectReference((PetscObject) ds);
    5382:     PetscDSDestroy(&dm->probs[num].ds);
    5383:     dm->probs[num].ds = ds;
    5384:   }
    5385:   return(0);
    5386: }

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

    5391:   Not collective

    5393:   Input Parameters:
    5394: + dm  - The DM
    5395: - ds  - The PetscDS defined on the given region

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

    5400:   Level: advanced

    5402: .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
    5403: @*/
    5404: PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
    5405: {
    5406:   PetscInt       Nds, n;

    5413:   DMGetNumDS(dm, &Nds);
    5414:   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
    5415:   if (n >= Nds) *num = -1;
    5416:   else          *num = n;
    5417:   return(0);
    5418: }

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

    5423:   Collective on dm

    5425:   Input Parameter:
    5426: . dm - The DM

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

    5430:   Level: intermediate

    5432: .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5433: @*/
    5434: PetscErrorCode DMCreateDS(DM dm)
    5435: {
    5436:   MPI_Comm       comm;
    5437:   PetscDS        dsDef;
    5438:   DMLabel       *labelSet;
    5439:   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
    5440:   PetscBool      doSetup = PETSC_TRUE;

    5445:   if (!dm->fields) return(0);
    5446:   PetscObjectGetComm((PetscObject) dm, &comm);
    5447:   DMGetCoordinateDim(dm, &dE);
    5448:   /* Determine how many regions we have */
    5449:   PetscMalloc1(Nf, &labelSet);
    5450:   Nl   = 0;
    5451:   Ndef = 0;
    5452:   for (f = 0; f < Nf; ++f) {
    5453:     DMLabel  label = dm->fields[f].label;
    5454:     PetscInt l;

    5456:     if (!label) {++Ndef; continue;}
    5457:     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
    5458:     if (l < Nl) continue;
    5459:     labelSet[Nl++] = label;
    5460:   }
    5461:   /* Create default DS if there are no labels to intersect with */
    5462:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5463:   if (!dsDef && Ndef && !Nl) {
    5464:     IS        fields;
    5465:     PetscInt *fld, nf;

    5467:     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
    5468:     if (nf) {
    5469:       PetscMalloc1(nf, &fld);
    5470:       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
    5471:       ISCreate(PETSC_COMM_SELF, &fields);
    5472:       PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
    5473:       ISSetType(fields, ISGENERAL);
    5474:       ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);

    5476:       PetscDSCreate(comm, &dsDef);
    5477:       DMSetRegionDS(dm, NULL, fields, dsDef);
    5478:       PetscDSDestroy(&dsDef);
    5479:       ISDestroy(&fields);
    5480:     }
    5481:   }
    5482:   DMGetRegionDS(dm, NULL, NULL, &dsDef);
    5483:   if (dsDef) {PetscDSSetCoordinateDimension(dsDef, dE);}
    5484:   /* Intersect labels with default fields */
    5485:   if (Ndef && Nl) {
    5486:     DM              plex;
    5487:     DMLabel         cellLabel;
    5488:     IS              fieldIS, allcellIS, defcellIS = NULL;
    5489:     PetscInt       *fields;
    5490:     const PetscInt *cells;
    5491:     PetscInt        depth, nf = 0, n, c;

    5493:     DMConvert(dm, DMPLEX, &plex);
    5494:     DMPlexGetDepth(plex, &depth);
    5495:     DMGetStratumIS(plex, "dim", depth, &allcellIS);
    5496:     if (!allcellIS) {DMGetStratumIS(plex, "depth", depth, &allcellIS);}
    5497:     for (l = 0; l < Nl; ++l) {
    5498:       DMLabel label = labelSet[l];
    5499:       IS      pointIS;

    5501:       ISDestroy(&defcellIS);
    5502:       DMLabelGetStratumIS(label, 1, &pointIS);
    5503:       ISDifference(allcellIS, pointIS, &defcellIS);
    5504:       ISDestroy(&pointIS);
    5505:     }
    5506:     ISDestroy(&allcellIS);

    5508:     DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);
    5509:     ISGetLocalSize(defcellIS, &n);
    5510:     ISGetIndices(defcellIS, &cells);
    5511:     for (c = 0; c < n; ++c) {DMLabelSetValue(cellLabel, cells[c], 1);}
    5512:     ISRestoreIndices(defcellIS, &cells);
    5513:     ISDestroy(&defcellIS);
    5514:     DMPlexLabelComplete(plex, cellLabel);

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

    5523:     PetscDSCreate(comm, &dsDef);
    5524:     DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);
    5525:     DMLabelDestroy(&cellLabel);
    5526:     PetscDSSetCoordinateDimension(dsDef, dE);
    5527:     PetscDSDestroy(&dsDef);
    5528:     ISDestroy(&fieldIS);
    5529:     DMDestroy(&plex);
    5530:   }
    5531:   /* Create label DSes
    5532:      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
    5533:   */
    5534:   /* TODO Should check that labels are disjoint */
    5535:   for (l = 0; l < Nl; ++l) {
    5536:     DMLabel   label = labelSet[l];
    5537:     PetscDS   ds;
    5538:     IS        fields;
    5539:     PetscInt *fld, nf;

    5541:     PetscDSCreate(comm, &ds);
    5542:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
    5543:     PetscMalloc1(nf, &fld);
    5544:     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
    5545:     ISCreate(PETSC_COMM_SELF, &fields);
    5546:     PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");
    5547:     ISSetType(fields, ISGENERAL);
    5548:     ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);
    5549:     DMSetRegionDS(dm, label, fields, ds);
    5550:     ISDestroy(&fields);
    5551:     PetscDSSetCoordinateDimension(ds, dE);
    5552:     {
    5553:       DMPolytopeType ct;
    5554:       PetscInt       lStart, lEnd;
    5555:       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;

    5557:       DMLabelGetBounds(label, &lStart, &lEnd);
    5558:       if (lStart >= 0) {
    5559:         DMPlexGetCellType(dm, lStart, &ct);
    5560:         switch (ct) {
    5561:           case DM_POLYTOPE_POINT_PRISM_TENSOR:
    5562:           case DM_POLYTOPE_SEG_PRISM_TENSOR:
    5563:           case DM_POLYTOPE_TRI_PRISM_TENSOR:
    5564:           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
    5565:             isHybridLocal = PETSC_TRUE;break;
    5566:           default: break;
    5567:         }
    5568:       }
    5569:       MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);
    5570:       PetscDSSetHybrid(ds, isHybrid);
    5571:     }
    5572:     PetscDSDestroy(&ds);
    5573:   }
    5574:   PetscFree(labelSet);
    5575:   /* Set fields in DSes */
    5576:   for (s = 0; s < dm->Nds; ++s) {
    5577:     PetscDS         ds     = dm->probs[s].ds;
    5578:     IS              fields = dm->probs[s].fields;
    5579:     const PetscInt *fld;
    5580:     PetscInt        nf;

    5582:     ISGetLocalSize(fields, &nf);
    5583:     ISGetIndices(fields, &fld);
    5584:     for (f = 0; f < nf; ++f) {
    5585:       PetscObject  disc  = dm->fields[fld[f]].disc;
    5586:       PetscBool    isHybrid;
    5587:       PetscClassId id;

    5589:       PetscDSGetHybrid(ds, &isHybrid);
    5590:       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
    5591:       if (isHybrid && f < nf-1) {PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);}
    5592:       PetscDSSetDiscretization(ds, f, disc);
    5593:       /* We allow people to have placeholder fields and construct the Section by hand */
    5594:       PetscObjectGetClassId(disc, &id);
    5595:       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
    5596:     }
    5597:     ISRestoreIndices(fields, &fld);
    5598:   }
    5599:   /* Setup DSes */
    5600:   if (doSetup) {
    5601:     for (s = 0; s < dm->Nds; ++s) {PetscDSSetUp(dm->probs[s].ds);}
    5602:   }
    5603:   return(0);
    5604: }

    5606: /*@
    5607:   DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.

    5609:   Collective on DM

    5611:   Input Parameters:
    5612: + dm   - The DM
    5613: - time - The time

    5615:   Output Parameters:
    5616: + u    - The vector will be filled with exact solution values, or NULL
    5617: - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL

    5619:   Note: The user must call PetscDSSetExactSolution() beforehand

    5621:   Level: developer

    5623: .seealso: PetscDSSetExactSolution()
    5624: @*/
    5625: PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
    5626: {
    5627:   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
    5628:   void            **ectxs;
    5629:   PetscInt          Nf, Nds, s;
    5630:   PetscErrorCode    ierr;

    5636:   DMGetNumFields(dm, &Nf);
    5637:   PetscMalloc2(Nf, &exacts, Nf, &ectxs);
    5638:   DMGetNumDS(dm, &Nds);
    5639:   for (s = 0; s < Nds; ++s) {
    5640:     PetscDS         ds;
    5641:     DMLabel         label;
    5642:     IS              fieldIS;
    5643:     const PetscInt *fields, id = 1;
    5644:     PetscInt        dsNf, f;

    5646:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
    5647:     PetscDSGetNumFields(ds, &dsNf);
    5648:     ISGetIndices(fieldIS, &fields);
    5649:     PetscArrayzero(exacts, Nf);
    5650:     PetscArrayzero(ectxs, Nf);
    5651:     if (u) {
    5652:       for (f = 0; f < dsNf; ++f) {
    5653:         const PetscInt field = fields[f];
    5654:         PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);
    5655:       }
    5656:       ISRestoreIndices(fieldIS, &fields);
    5657:       if (label) {
    5658:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);
    5659:       } else {
    5660:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);
    5661:       }
    5662:     }
    5663:     if (u_t) {
    5664:       PetscArrayzero(exacts, Nf);
    5665:       PetscArrayzero(ectxs, Nf);
    5666:       for (f = 0; f < dsNf; ++f) {
    5667:         const PetscInt field = fields[f];
    5668:         PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);
    5669:       }
    5670:       ISRestoreIndices(fieldIS, &fields);
    5671:       if (label) {
    5672:         DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5673:       } else {
    5674:         DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);
    5675:       }
    5676:     }
    5677:   }
    5678:   if (u) {
    5679:     PetscObjectSetName((PetscObject) u, "Exact Solution");
    5680:     PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");
    5681:   }
    5682:   if (u_t) {
    5683:     PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");
    5684:     PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");
    5685:   }
    5686:   PetscFree2(exacts, ectxs);
    5687:   return(0);
    5688: }

    5690: /*@
    5691:   DMCopyDS - Copy the discrete systems for the DM into another DM

    5693:   Collective on dm

    5695:   Input Parameter:
    5696: . dm - The DM

    5698:   Output Parameter:
    5699: . newdm - The DM

    5701:   Level: advanced

    5703: .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
    5704: @*/
    5705: PetscErrorCode DMCopyDS(DM dm, DM newdm)
    5706: {
    5707:   PetscInt       Nds, s;

    5711:   if (dm == newdm) return(0);
    5712:   DMGetNumDS(dm, &Nds);
    5713:   DMClearDS(newdm);
    5714:   for (s = 0; s < Nds; ++s) {
    5715:     DMLabel  label;
    5716:     IS       fields;
    5717:     PetscDS  ds;
    5718:     PetscInt Nbd, bd;

    5720:     DMGetRegionNumDS(dm, s, &label, &fields, &ds);
    5721:     DMSetRegionDS(newdm, label, fields, ds);
    5722:     PetscDSGetNumBoundary(ds, &Nbd);
    5723:     for (bd = 0; bd < Nbd; ++bd) {
    5724:       const char *labelname, *name;
    5725:       PetscInt    field;

    5727:       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    5728:       PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    5729:       DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);
    5730:     }
    5731:   }
    5732:   return(0);
    5733: }

    5735: /*@
    5736:   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM

    5738:   Collective on dm

    5740:   Input Parameter:
    5741: . dm - The DM

    5743:   Output Parameter:
    5744: . newdm - The DM

    5746:   Level: advanced

    5748: .seealso: DMCopyFields(), DMCopyDS()
    5749: @*/
    5750: PetscErrorCode DMCopyDisc(DM dm, DM newdm)
    5751: {

    5755:   DMCopyFields(dm, newdm);
    5756:   DMCopyDS(dm, newdm);
    5757:   return(0);
    5758: }

    5760: PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
    5761: {
    5762:   DM dm_coord,dmc_coord;
    5764:   Vec coords,ccoords;
    5765:   Mat inject;
    5767:   DMGetCoordinateDM(dm,&dm_coord);
    5768:   DMGetCoordinateDM(dmc,&dmc_coord);
    5769:   DMGetCoordinates(dm,&coords);
    5770:   DMGetCoordinates(dmc,&ccoords);
    5771:   if (coords && !ccoords) {
    5772:     DMCreateGlobalVector(dmc_coord,&ccoords);
    5773:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5774:     DMCreateInjection(dmc_coord,dm_coord,&inject);
    5775:     MatRestrict(inject,coords,ccoords);
    5776:     MatDestroy(&inject);
    5777:     DMSetCoordinates(dmc,ccoords);
    5778:     VecDestroy(&ccoords);
    5779:   }
    5780:   return(0);
    5781: }

    5783: static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
    5784: {
    5785:   DM dm_coord,subdm_coord;
    5787:   Vec coords,ccoords,clcoords;
    5788:   VecScatter *scat_i,*scat_g;
    5790:   DMGetCoordinateDM(dm,&dm_coord);
    5791:   DMGetCoordinateDM(subdm,&subdm_coord);
    5792:   DMGetCoordinates(dm,&coords);
    5793:   DMGetCoordinates(subdm,&ccoords);
    5794:   if (coords && !ccoords) {
    5795:     DMCreateGlobalVector(subdm_coord,&ccoords);
    5796:     PetscObjectSetName((PetscObject)ccoords,"coordinates");
    5797:     DMCreateLocalVector(subdm_coord,&clcoords);
    5798:     PetscObjectSetName((PetscObject)clcoords,"coordinates");
    5799:     DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);
    5800:     VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5801:     VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);
    5802:     VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5803:     VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);
    5804:     DMSetCoordinates(subdm,ccoords);
    5805:     DMSetCoordinatesLocal(subdm,clcoords);
    5806:     VecScatterDestroy(&scat_i[0]);
    5807:     VecScatterDestroy(&scat_g[0]);
    5808:     VecDestroy(&ccoords);
    5809:     VecDestroy(&clcoords);
    5810:     PetscFree(scat_i);
    5811:     PetscFree(scat_g);
    5812:   }
    5813:   return(0);
    5814: }

    5816: /*@
    5817:   DMGetDimension - Return the topological dimension of the DM

    5819:   Not collective

    5821:   Input Parameter:
    5822: . dm - The DM

    5824:   Output Parameter:
    5825: . dim - The topological dimension

    5827:   Level: beginner

    5829: .seealso: DMSetDimension(), DMCreate()
    5830: @*/
    5831: PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
    5832: {
    5836:   *dim = dm->dim;
    5837:   return(0);
    5838: }

    5840: /*@
    5841:   DMSetDimension - Set the topological dimension of the DM

    5843:   Collective on dm

    5845:   Input Parameters:
    5846: + dm - The DM
    5847: - dim - The topological dimension

    5849:   Level: beginner

    5851: .seealso: DMGetDimension(), DMCreate()
    5852: @*/
    5853: PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
    5854: {
    5855:   PetscDS        ds;

    5861:   dm->dim = dim;
    5862:   DMGetDS(dm, &ds);
    5863:   if (ds->dimEmbed < 0) {PetscDSSetCoordinateDimension(ds, dm->dim);}
    5864:   return(0);
    5865: }

    5867: /*@
    5868:   DMGetDimPoints - Get the half-open interval for all points of a given dimension

    5870:   Collective on dm

    5872:   Input Parameters:
    5873: + dm - the DM
    5874: - dim - the dimension

    5876:   Output Parameters:
    5877: + pStart - The first point of the given dimension
    5878: - pEnd - The first point following points of the given dimension

    5880:   Note:
    5881:   The points are vertices in the Hasse diagram encoding the topology. This is explained in
    5882:   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
    5883:   then the interval is empty.

    5885:   Level: intermediate

    5887: .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
    5888: @*/
    5889: PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
    5890: {
    5891:   PetscInt       d;

    5896:   DMGetDimension(dm, &d);
    5897:   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
    5898:   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
    5899:   (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);
    5900:   return(0);
    5901: }

    5903: /*@
    5904:   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates

    5906:   Collective on dm

    5908:   Input Parameters:
    5909: + dm - the DM
    5910: - c - coordinate vector

    5912:   Notes:
    5913:   The coordinates do include those for ghost points, which are in the local vector.

    5915:   The vector c should be destroyed by the caller.

    5917:   Level: intermediate

    5919: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
    5920: @*/
    5921: PetscErrorCode DMSetCoordinates(DM dm, Vec c)
    5922: {

    5928:   PetscObjectReference((PetscObject) c);
    5929:   VecDestroy(&dm->coordinates);
    5930:   dm->coordinates = c;
    5931:   VecDestroy(&dm->coordinatesLocal);
    5932:   DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);
    5933:   DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);
    5934:   return(0);
    5935: }

    5937: /*@
    5938:   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates

    5940:   Not collective

    5942:    Input Parameters:
    5943: +  dm - the DM
    5944: -  c - coordinate vector

    5946:   Notes:
    5947:   The coordinates of ghost points can be set using DMSetCoordinates()
    5948:   followed by DMGetCoordinatesLocal(). This is intended to enable the
    5949:   setting of ghost coordinates outside of the domain.

    5951:   The vector c should be destroyed by the caller.

    5953:   Level: intermediate

    5955: .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
    5956: @*/
    5957: PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
    5958: {

    5964:   PetscObjectReference((PetscObject) c);
    5965:   VecDestroy(&dm->coordinatesLocal);

    5967:   dm->coordinatesLocal = c;

    5969:   VecDestroy(&dm->coordinates);
    5970:   return(0);
    5971: }

    5973: /*@
    5974:   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.

    5976:   Collective on dm

    5978:   Input Parameter:
    5979: . dm - the DM

    5981:   Output Parameter:
    5982: . c - global coordinate vector

    5984:   Note:
    5985:   This is a borrowed reference, so the user should NOT destroy this vector

    5987:   Each process has only the local coordinates (does NOT have the ghost coordinates).

    5989:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    5990:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    5992:   Level: intermediate

    5994: .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
    5995: @*/
    5996: PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
    5997: {

    6003:   if (!dm->coordinates && dm->coordinatesLocal) {
    6004:     DM        cdm = NULL;
    6005:     PetscBool localized;

    6007:     DMGetCoordinateDM(dm, &cdm);
    6008:     DMCreateGlobalVector(cdm, &dm->coordinates);
    6009:     DMGetCoordinatesLocalized(dm, &localized);
    6010:     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
    6011:     if (localized) {
    6012:       PetscInt cdim;

    6014:       DMGetCoordinateDim(dm, &cdim);
    6015:       VecSetBlockSize(dm->coordinates, cdim);
    6016:     }
    6017:     PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");
    6018:     DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6019:     DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);
    6020:   }
    6021:   *c = dm->coordinates;
    6022:   return(0);
    6023: }

    6025: /*@
    6026:   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.

    6028:   Collective on dm

    6030:   Input Parameter:
    6031: . dm - the DM

    6033:   Level: advanced

    6035: .seealso: DMGetCoordinatesLocalNoncollective()
    6036: @*/
    6037: PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
    6038: {

    6043:   if (!dm->coordinatesLocal && dm->coordinates) {
    6044:     DM        cdm = NULL;
    6045:     PetscBool localized;

    6047:     DMGetCoordinateDM(dm, &cdm);
    6048:     DMCreateLocalVector(cdm, &dm->coordinatesLocal);
    6049:     DMGetCoordinatesLocalized(dm, &localized);
    6050:     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
    6051:     if (localized) {
    6052:       PetscInt cdim;

    6054:       DMGetCoordinateDim(dm, &cdim);
    6055:       VecSetBlockSize(dm->coordinates, cdim);
    6056:     }
    6057:     PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");
    6058:     DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6059:     DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);
    6060:   }
    6061:   return(0);
    6062: }

    6064: /*@
    6065:   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.

    6067:   Collective on dm

    6069:   Input Parameter:
    6070: . dm - the DM

    6072:   Output Parameter:
    6073: . c - coordinate vector

    6075:   Note:
    6076:   This is a borrowed reference, so the user should NOT destroy this vector

    6078:   Each process has the local and ghost coordinates

    6080:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6081:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6083:   Level: intermediate

    6085: .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
    6086: @*/
    6087: PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
    6088: {

    6094:   DMGetCoordinatesLocalSetUp(dm);
    6095:   *c = dm->coordinatesLocal;
    6096:   return(0);
    6097: }

    6099: /*@
    6100:   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.

    6102:   Not collective

    6104:   Input Parameter:
    6105: . dm - the DM

    6107:   Output Parameter:
    6108: . c - coordinate vector

    6110:   Level: advanced

    6112: .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6113: @*/
    6114: PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
    6115: {
    6119:   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
    6120:   *c = dm->coordinatesLocal;
    6121:   return(0);
    6122: }

    6124: /*@
    6125:   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.

    6127:   Not collective

    6129:   Input Parameter:
    6130: + dm - the DM
    6131: - p - the IS of points whose coordinates will be returned

    6133:   Output Parameter:
    6134: + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
    6135: - pCoord - the Vec with coordinates of points in p

    6137:   Note:
    6138:   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.

    6140:   This creates a new vector, so the user SHOULD destroy this vector

    6142:   Each process has the local and ghost coordinates

    6144:   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
    6145:   and (x_0,y_0,z_0,x_1,y_1,z_1...)

    6147:   Level: advanced

    6149: .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
    6150: @*/
    6151: PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
    6152: {
    6153:   PetscSection        cs, newcs;
    6154:   Vec                 coords;
    6155:   const PetscScalar   *arr;
    6156:   PetscScalar         *newarr=NULL;
    6157:   PetscInt            n;
    6158:   PetscErrorCode      ierr;

    6165:   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
    6166:   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
    6167:   cs = dm->coordinateDM->localSection;
    6168:   coords = dm->coordinatesLocal;
    6169:   VecGetArrayRead(coords, &arr);
    6170:   PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);
    6171:   VecRestoreArrayRead(coords, &arr);
    6172:   if (pCoord) {
    6173:     PetscSectionGetStorageSize(newcs, &n);
    6174:     /* set array in two steps to mimic PETSC_OWN_POINTER */
    6175:     VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);
    6176:     VecReplaceArray(*pCoord, newarr);
    6177:   } else {
    6178:     PetscFree(newarr);
    6179:   }
    6180:   if (pCoordSection) {*pCoordSection = newcs;}
    6181:   else               {PetscSectionDestroy(&newcs);}
    6182:   return(0);
    6183: }

    6185: PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
    6186: {

    6192:   if (!dm->coordinateField) {
    6193:     if (dm->ops->createcoordinatefield) {
    6194:       (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);
    6195:     }
    6196:   }
    6197:   *field = dm->coordinateField;
    6198:   return(0);
    6199: }

    6201: PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
    6202: {

    6208:   PetscObjectReference((PetscObject)field);
    6209:   DMFieldDestroy(&dm->coordinateField);
    6210:   dm->coordinateField = field;
    6211:   return(0);
    6212: }

    6214: /*@
    6215:   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6217:   Collective on dm

    6219:   Input Parameter:
    6220: . dm - the DM

    6222:   Output Parameter:
    6223: . cdm - coordinate DM

    6225:   Level: intermediate

    6227: .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6228: @*/
    6229: PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
    6230: {

    6236:   if (!dm->coordinateDM) {
    6237:     DM cdm;

    6239:     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
    6240:     (*dm->ops->createcoordinatedm)(dm, &cdm);
    6241:     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
    6242:      * until the call to CreateCoordinateDM) */
    6243:     DMDestroy(&dm->coordinateDM);
    6244:     dm->coordinateDM = cdm;
    6245:   }
    6246:   *cdm = dm->coordinateDM;
    6247:   return(0);
    6248: }

    6250: /*@
    6251:   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates

    6253:   Logically Collective on dm

    6255:   Input Parameters:
    6256: + dm - the DM
    6257: - cdm - coordinate DM

    6259:   Level: intermediate

    6261: .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
    6262: @*/
    6263: PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
    6264: {

    6270:   PetscObjectReference((PetscObject)cdm);
    6271:   DMDestroy(&dm->coordinateDM);
    6272:   dm->coordinateDM = cdm;
    6273:   return(0);
    6274: }

    6276: /*@
    6277:   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.

    6279:   Not Collective

    6281:   Input Parameter:
    6282: . dm - The DM object

    6284:   Output Parameter:
    6285: . dim - The embedding dimension

    6287:   Level: intermediate

    6289: .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6290: @*/
    6291: PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
    6292: {
    6296:   if (dm->dimEmbed == PETSC_DEFAULT) {
    6297:     dm->dimEmbed = dm->dim;
    6298:   }
    6299:   *dim = dm->dimEmbed;
    6300:   return(0);
    6301: }

    6303: /*@
    6304:   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.

    6306:   Not Collective

    6308:   Input Parameters:
    6309: + dm  - The DM object
    6310: - dim - The embedding dimension

    6312:   Level: intermediate

    6314: .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6315: @*/
    6316: PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
    6317: {
    6318:   PetscDS        ds;

    6323:   dm->dimEmbed = dim;
    6324:   DMGetDS(dm, &ds);
    6325:   PetscDSSetCoordinateDimension(ds, dim);
    6326:   return(0);
    6327: }

    6329: /*@
    6330:   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.

    6332:   Collective on dm

    6334:   Input Parameter:
    6335: . dm - The DM object

    6337:   Output Parameter:
    6338: . section - The PetscSection object

    6340:   Level: intermediate

    6342: .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
    6343: @*/
    6344: PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
    6345: {
    6346:   DM             cdm;

    6352:   DMGetCoordinateDM(dm, &cdm);
    6353:   DMGetLocalSection(cdm, section);
    6354:   return(0);
    6355: }

    6357: /*@
    6358:   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.

    6360:   Not Collective

    6362:   Input Parameters:
    6363: + dm      - The DM object
    6364: . dim     - The embedding dimension, or PETSC_DETERMINE
    6365: - section - The PetscSection object

    6367:   Level: intermediate

    6369: .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
    6370: @*/
    6371: PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
    6372: {
    6373:   DM             cdm;

    6379:   DMGetCoordinateDM(dm, &cdm);
    6380:   DMSetLocalSection(cdm, section);
    6381:   if (dim == PETSC_DETERMINE) {
    6382:     PetscInt d = PETSC_DEFAULT;
    6383:     PetscInt pStart, pEnd, vStart, vEnd, v, dd;

    6385:     PetscSectionGetChart(section, &pStart, &pEnd);
    6386:     DMGetDimPoints(dm, 0, &vStart, &vEnd);
    6387:     pStart = PetscMax(vStart, pStart);
    6388:     pEnd   = PetscMin(vEnd, pEnd);
    6389:     for (v = pStart; v < pEnd; ++v) {
    6390:       PetscSectionGetDof(section, v, &dd);
    6391:       if (dd) {d = dd; break;}
    6392:     }
    6393:     if (d >= 0) {DMSetCoordinateDim(dm, d);}
    6394:   }
    6395:   return(0);
    6396: }

    6398: /*@
    6399:   DMProjectCoordinates - Project coordinates to a different space

    6401:   Input Parameters:
    6402: + dm      - The DM object
    6403: - disc    - The new coordinate discretization

    6405:   Level: intermediate

    6407: .seealso: DMGetCoordinateField()
    6408: @*/
    6409: PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
    6410: {
    6411:   PetscObject    discOld;
    6412:   PetscClassId   classid;
    6413:   DM             cdmOld,cdmNew;
    6414:   Vec            coordsOld,coordsNew;
    6415:   Mat            matInterp;

    6422:   DMGetCoordinateDM(dm, &cdmOld);
    6423:   /* Check current discretization is compatible */
    6424:   DMGetField(cdmOld, 0, NULL, &discOld);
    6425:   PetscObjectGetClassId(discOld, &classid);
    6426:   if (classid != PETSCFE_CLASSID) SETERRQ(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type not supported");
    6427:   /* Make a fresh clone of the coordinate DM */
    6428:   DMClone(cdmOld, &cdmNew);
    6429:   DMSetField(cdmNew, 0, NULL, (PetscObject) disc);
    6430:   DMCreateDS(cdmNew);
    6431:   /* Project the coordinate vector from old to new space  */
    6432:   DMGetCoordinates(dm, &coordsOld);
    6433:   DMCreateGlobalVector(cdmNew, &coordsNew);
    6434:   DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);
    6435:   MatInterpolate(matInterp, coordsOld, coordsNew);
    6436:   MatDestroy(&matInterp);
    6437:   /* Set new coordinate structures */
    6438:   DMSetCoordinateField(dm, NULL);
    6439:   DMSetCoordinateDM(dm, cdmNew);
    6440:   DMSetCoordinates(dm, coordsNew);
    6441:   VecDestroy(&coordsNew);
    6442:   DMDestroy(&cdmNew);
    6443:   return(0);
    6444: }

    6446: /*@C
    6447:   DMGetPeriodicity - Get the description of mesh periodicity

    6449:   Input Parameters:
    6450: . dm      - The DM object

    6452:   Output Parameters:
    6453: + per     - Whether the DM is periodic or not
    6454: . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
    6455: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6456: - bd      - This describes the type of periodicity in each topological dimension

    6458:   Level: developer

    6460: .seealso: DMGetPeriodicity()
    6461: @*/
    6462: PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
    6463: {
    6466:   if (per)     *per     = dm->periodic;
    6467:   if (L)       *L       = dm->L;
    6468:   if (maxCell) *maxCell = dm->maxCell;
    6469:   if (bd)      *bd      = dm->bdtype;
    6470:   return(0);
    6471: }

    6473: /*@C
    6474:   DMSetPeriodicity - Set the description of mesh periodicity

    6476:   Input Parameters:
    6477: + dm      - The DM object
    6478: . per     - Whether the DM is periodic or not.
    6479: . 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.
    6480: . L       - If we assume the mesh is a torus, this is the length of each coordinate
    6481: - bd      - This describes the type of periodicity in each topological dimension

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

    6485:   Level: developer

    6487: .seealso: DMGetPeriodicity()
    6488: @*/
    6489: PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
    6490: {
    6491:   PetscInt       dim, d;

    6500:   DMGetDimension(dm, &dim);
    6501:   if (maxCell) {
    6502:     if (!dm->maxCell) {PetscMalloc1(dim, &dm->maxCell);}
    6503:     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
    6504:   } else { /* remove maxCell information to disable automatic computation of localized vertices */
    6505:     PetscFree(dm->maxCell);
    6506:   }

    6508:   if (L) {
    6509:     if (!dm->L) {PetscMalloc1(dim, &dm->L);}
    6510:     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
    6511:   }
    6512:   if (bd) {
    6513:     if (!dm->bdtype) {PetscMalloc1(dim, &dm->bdtype);}
    6514:     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
    6515:   }
    6516:   dm->periodic = per;
    6517:   return(0);
    6518: }

    6520: /*@
    6521:   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.

    6523:   Input Parameters:
    6524: + dm     - The DM
    6525: . in     - The input coordinate point (dim numbers)
    6526: - endpoint - Include the endpoint L_i

    6528:   Output Parameter:
    6529: . out - The localized coordinate point

    6531:   Level: developer

    6533: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6534: @*/
    6535: PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
    6536: {
    6537:   PetscInt       dim, d;

    6541:   DMGetCoordinateDim(dm, &dim);
    6542:   if (!dm->maxCell) {
    6543:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6544:   } else {
    6545:     if (endpoint) {
    6546:       for (d = 0; d < dim; ++d) {
    6547:         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)) {
    6548:           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
    6549:         } else {
    6550:           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6551:         }
    6552:       }
    6553:     } else {
    6554:       for (d = 0; d < dim; ++d) {
    6555:         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
    6556:       }
    6557:     }
    6558:   }
    6559:   return(0);
    6560: }

    6562: /*
    6563:   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.

    6565:   Input Parameters:
    6566: + dm     - The DM
    6567: . dim    - The spatial dimension
    6568: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6569: - in     - The input coordinate point (dim numbers)

    6571:   Output Parameter:
    6572: . out - The localized coordinate point

    6574:   Level: developer

    6576:   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

    6578: .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
    6579: */
    6580: PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6581: {
    6582:   PetscInt d;

    6585:   if (!dm->maxCell) {
    6586:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6587:   } else {
    6588:     for (d = 0; d < dim; ++d) {
    6589:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
    6590:         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6591:       } else {
    6592:         out[d] = in[d];
    6593:       }
    6594:     }
    6595:   }
    6596:   return(0);
    6597: }

    6599: PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
    6600: {
    6601:   PetscInt d;

    6604:   if (!dm->maxCell) {
    6605:     for (d = 0; d < dim; ++d) out[d] = in[d];
    6606:   } else {
    6607:     for (d = 0; d < dim; ++d) {
    6608:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
    6609:         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
    6610:       } else {
    6611:         out[d] = in[d];
    6612:       }
    6613:     }
    6614:   }
    6615:   return(0);
    6616: }

    6618: /*
    6619:   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.

    6621:   Input Parameters:
    6622: + dm     - The DM
    6623: . dim    - The spatial dimension
    6624: . anchor - The anchor point, the input point can be no more than maxCell away from it
    6625: . in     - The input coordinate delta (dim numbers)
    6626: - out    - The input coordinate point (dim numbers)

    6628:   Output Parameter:
    6629: . out    - The localized coordinate in + out

    6631:   Level: developer

    6633:   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

    6635: .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
    6636: */
    6637: PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
    6638: {
    6639:   PetscInt d;

    6642:   if (!dm->maxCell) {
    6643:     for (d = 0; d < dim; ++d) out[d] += in[d];
    6644:   } else {
    6645:     for (d = 0; d < dim; ++d) {
    6646:       const PetscReal maxC = dm->maxCell[d];

    6648:       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
    6649:         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];

    6651:         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
    6652:           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]));
    6653:         out[d] += newCoord;
    6654:       } else {
    6655:         out[d] += in[d];
    6656:       }
    6657:     }
    6658:   }
    6659:   return(0);
    6660: }

    6662: /*@
    6663:   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process

    6665:   Not collective

    6667:   Input Parameter:
    6668: . dm - The DM

    6670:   Output Parameter:
    6671:   areLocalized - True if localized

    6673:   Level: developer

    6675: .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
    6676: @*/
    6677: PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
    6678: {
    6679:   DM             cdm;
    6680:   PetscSection   coordSection;
    6681:   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
    6682:   PetscBool      isPlex, alreadyLocalized;

    6688:   *areLocalized = PETSC_FALSE;

    6690:   /* We need some generic way of refering to cells/vertices */
    6691:   DMGetCoordinateDM(dm, &cdm);
    6692:   PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);
    6693:   if (!isPlex) return(0);

    6695:   DMGetCoordinateSection(dm, &coordSection);
    6696:   DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);
    6697:   PetscSectionGetChart(coordSection, &sStart, &sEnd);
    6698:   alreadyLocalized = PETSC_FALSE;
    6699:   for (c = cStart; c < cEnd; ++c) {
    6700:     if (c < sStart || c >= sEnd) continue;
    6701:     PetscSectionGetDof(coordSection, c, &dof);
    6702:     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
    6703:   }
    6704:   *areLocalized = alreadyLocalized;
    6705:   return(0);
    6706: }

    6708: /*@
    6709:   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells

    6711:   Collective on dm

    6713:   Input Parameter:
    6714: . dm - The DM

    6716:   Output Parameter:
    6717:   areLocalized - True if localized

    6719:   Level: developer

    6721: .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
    6722: @*/
    6723: PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
    6724: {
    6725:   PetscBool      localized;

    6731:   DMGetCoordinatesLocalizedLocal(dm,&localized);
    6732:   MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));
    6733:   return(0);
    6734: }

    6736: /*@
    6737:   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces

    6739:   Collective on dm

    6741:   Input Parameter:
    6742: . dm - The DM

    6744:   Level: developer

    6746: .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
    6747: @*/
    6748: PetscErrorCode DMLocalizeCoordinates(DM dm)
    6749: {
    6750:   DM             cdm;
    6751:   PetscSection   coordSection, cSection;
    6752:   Vec            coordinates,  cVec;
    6753:   PetscScalar   *coords, *coords2, *anchor, *localized;
    6754:   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
    6755:   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
    6756:   PetscInt       maxHeight = 0, h;
    6757:   PetscInt       *pStart = NULL, *pEnd = NULL;

    6762:   if (!dm->periodic) return(0);
    6763:   DMGetCoordinatesLocalized(dm, &alreadyLocalized);
    6764:   if (alreadyLocalized) return(0);

    6766:   /* We need some generic way of refering to cells/vertices */
    6767:   DMGetCoordinateDM(dm, &cdm);
    6768:   {
    6769:     PetscBool isplex;

    6771:     PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);
    6772:     if (isplex) {
    6773:       DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);
    6774:       DMPlexGetMaxProjectionHeight(cdm,&maxHeight);
    6775:       DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6776:       pEnd = &pStart[maxHeight + 1];
    6777:       newStart = vStart;
    6778:       newEnd   = vEnd;
    6779:       for (h = 0; h <= maxHeight; h++) {
    6780:         DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);
    6781:         newStart = PetscMin(newStart,pStart[h]);
    6782:         newEnd   = PetscMax(newEnd,pEnd[h]);
    6783:       }
    6784:     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
    6785:   }
    6786:   DMGetCoordinatesLocal(dm, &coordinates);
    6787:   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
    6788:   DMGetCoordinateSection(dm, &coordSection);
    6789:   VecGetBlockSize(coordinates, &bs);
    6790:   PetscSectionGetChart(coordSection,&sStart,&sEnd);

    6792:   PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);
    6793:   PetscSectionSetNumFields(cSection, 1);
    6794:   PetscSectionGetFieldComponents(coordSection, 0, &Nc);
    6795:   PetscSectionSetFieldComponents(cSection, 0, Nc);
    6796:   PetscSectionSetChart(cSection, newStart, newEnd);

    6798:   DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6799:   localized = &anchor[bs];
    6800:   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
    6801:   for (h = 0; h <= maxHeight; h++) {
    6802:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6804:     for (c = cStart; c < cEnd; ++c) {
    6805:       PetscScalar *cellCoords = NULL;
    6806:       PetscInt     b;

    6808:       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
    6809:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6810:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6811:       for (d = 0; d < dof/bs; ++d) {
    6812:         DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);
    6813:         for (b = 0; b < bs; b++) {
    6814:           if (cellCoords[d*bs + b] != localized[b]) break;
    6815:         }
    6816:         if (b < bs) break;
    6817:       }
    6818:       if (d < dof/bs) {
    6819:         if (c >= sStart && c < sEnd) {
    6820:           PetscInt cdof;

    6822:           PetscSectionGetDof(coordSection, c, &cdof);
    6823:           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
    6824:         }
    6825:         PetscSectionSetDof(cSection, c, dof);
    6826:         PetscSectionSetFieldDof(cSection, c, 0, dof);
    6827:       }
    6828:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6829:     }
    6830:   }
    6831:   MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));
    6832:   if (alreadyLocalizedGlobal) {
    6833:     DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6834:     PetscSectionDestroy(&cSection);
    6835:     DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6836:     return(0);
    6837:   }
    6838:   for (v = vStart; v < vEnd; ++v) {
    6839:     PetscSectionGetDof(coordSection, v, &dof);
    6840:     PetscSectionSetDof(cSection, v, dof);
    6841:     PetscSectionSetFieldDof(cSection, v, 0, dof);
    6842:   }
    6843:   PetscSectionSetUp(cSection);
    6844:   PetscSectionGetStorageSize(cSection, &coordSize);
    6845:   VecCreate(PETSC_COMM_SELF, &cVec);
    6846:   PetscObjectSetName((PetscObject)cVec,"coordinates");
    6847:   VecSetBlockSize(cVec, bs);
    6848:   VecSetSizes(cVec, coordSize, PETSC_DETERMINE);
    6849:   VecSetType(cVec, VECSTANDARD);
    6850:   VecGetArrayRead(coordinates, (const PetscScalar**)&coords);
    6851:   VecGetArray(cVec, &coords2);
    6852:   for (v = vStart; v < vEnd; ++v) {
    6853:     PetscSectionGetDof(coordSection, v, &dof);
    6854:     PetscSectionGetOffset(coordSection, v, &off);
    6855:     PetscSectionGetOffset(cSection,     v, &off2);
    6856:     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
    6857:   }
    6858:   for (h = 0; h <= maxHeight; h++) {
    6859:     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;

    6861:     for (c = cStart; c < cEnd; ++c) {
    6862:       PetscScalar *cellCoords = NULL;
    6863:       PetscInt     b, cdof;

    6865:       PetscSectionGetDof(cSection,c,&cdof);
    6866:       if (!cdof) continue;
    6867:       DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6868:       PetscSectionGetOffset(cSection, c, &off2);
    6869:       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
    6870:       for (d = 0; d < dof/bs; ++d) {DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);}
    6871:       DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);
    6872:     }
    6873:   }
    6874:   DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);
    6875:   DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);
    6876:   VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);
    6877:   VecRestoreArray(cVec, &coords2);
    6878:   DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);
    6879:   DMSetCoordinatesLocal(dm, cVec);
    6880:   VecDestroy(&cVec);
    6881:   PetscSectionDestroy(&cSection);
    6882:   return(0);
    6883: }

    6885: /*@
    6886:   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells

    6888:   Collective on v (see explanation below)

    6890:   Input Parameters:
    6891: + dm - The DM
    6892: . v - The Vec of points
    6893: . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
    6894: - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.

    6896:   Output Parameter:
    6897: + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
    6898: - cells - The PetscSF containing the ranks and local indices of the containing points.

    6901:   Level: developer

    6903:   Notes:
    6904:   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
    6905:   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.

    6907:   If *cellSF is NULL on input, a PetscSF will be created.
    6908:   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.

    6910:   An array that maps each point to its containing cell can be obtained with

    6912: $    const PetscSFNode *cells;
    6913: $    PetscInt           nFound;
    6914: $    const PetscInt    *found;
    6915: $
    6916: $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);

    6918:   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
    6919:   the index of the cell in its rank's local numbering.

    6921: .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
    6922: @*/
    6923: PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
    6924: {

    6931:   if (*cellSF) {
    6932:     PetscMPIInt result;

    6935:     MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);
    6936:     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
    6937:   } else {
    6938:     PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);
    6939:   }
    6940:   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
    6941:   PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);
    6942:   (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);
    6943:   PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);
    6944:   return(0);
    6945: }

    6947: /*@
    6948:   DMGetOutputDM - Retrieve the DM associated with the layout for output

    6950:   Collective on dm

    6952:   Input Parameter:
    6953: . dm - The original DM

    6955:   Output Parameter:
    6956: . odm - The DM which provides the layout for output

    6958:   Level: intermediate

    6960: .seealso: VecView(), DMGetGlobalSection()
    6961: @*/
    6962: PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
    6963: {
    6964:   PetscSection   section;
    6965:   PetscBool      hasConstraints, ghasConstraints;

    6971:   DMGetLocalSection(dm, &section);
    6972:   PetscSectionHasConstraints(section, &hasConstraints);
    6973:   MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));
    6974:   if (!ghasConstraints) {
    6975:     *odm = dm;
    6976:     return(0);
    6977:   }
    6978:   if (!dm->dmBC) {
    6979:     PetscSection newSection, gsection;
    6980:     PetscSF      sf;

    6982:     DMClone(dm, &dm->dmBC);
    6983:     DMCopyDisc(dm, dm->dmBC);
    6984:     PetscSectionClone(section, &newSection);
    6985:     DMSetLocalSection(dm->dmBC, newSection);
    6986:     PetscSectionDestroy(&newSection);
    6987:     DMGetPointSF(dm->dmBC, &sf);
    6988:     PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);
    6989:     DMSetGlobalSection(dm->dmBC, gsection);
    6990:     PetscSectionDestroy(&gsection);
    6991:   }
    6992:   *odm = dm->dmBC;
    6993:   return(0);
    6994: }

    6996: /*@
    6997:   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output

    6999:   Input Parameter:
    7000: . dm - The original DM

    7002:   Output Parameters:
    7003: + num - The output sequence number
    7004: - val - The output sequence value

    7006:   Level: intermediate

    7008:   Note: This is intended for output that should appear in sequence, for instance
    7009:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7011: .seealso: VecView()
    7012: @*/
    7013: PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
    7014: {
    7019:   return(0);
    7020: }

    7022: /*@
    7023:   DMSetOutputSequenceNumber - Set the sequence number/value for output

    7025:   Input Parameters:
    7026: + dm - The original DM
    7027: . num - The output sequence number
    7028: - val - The output sequence value

    7030:   Level: intermediate

    7032:   Note: This is intended for output that should appear in sequence, for instance
    7033:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7035: .seealso: VecView()
    7036: @*/
    7037: PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
    7038: {
    7041:   dm->outputSequenceNum = num;
    7042:   dm->outputSequenceVal = val;
    7043:   return(0);
    7044: }

    7046: /*@C
    7047:   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer

    7049:   Input Parameters:
    7050: + dm   - The original DM
    7051: . name - The sequence name
    7052: - num  - The output sequence number

    7054:   Output Parameter:
    7055: . val  - The output sequence value

    7057:   Level: intermediate

    7059:   Note: This is intended for output that should appear in sequence, for instance
    7060:   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.

    7062: .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
    7063: @*/
    7064: PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
    7065: {
    7066:   PetscBool      ishdf5;

    7073:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);
    7074:   if (ishdf5) {
    7075: #if defined(PETSC_HAVE_HDF5)
    7076:     PetscScalar value;

    7078:     DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);
    7079:     *val = PetscRealPart(value);
    7080: #endif
    7081:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
    7082:   return(0);
    7083: }

    7085: /*@
    7086:   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution

    7088:   Not collective

    7090:   Input Parameter:
    7091: . dm - The DM

    7093:   Output Parameter:
    7094: . useNatural - The flag to build the mapping to a natural order during distribution

    7096:   Level: beginner

    7098: .seealso: DMSetUseNatural(), DMCreate()
    7099: @*/
    7100: PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
    7101: {
    7105:   *useNatural = dm->useNatural;
    7106:   return(0);
    7107: }

    7109: /*@
    7110:   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution

    7112:   Collective on dm

    7114:   Input Parameters:
    7115: + dm - The DM
    7116: - useNatural - The flag to build the mapping to a natural order during distribution

    7118:   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()

    7120:   Level: beginner

    7122: .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
    7123: @*/
    7124: PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
    7125: {
    7129:   dm->useNatural = useNatural;
    7130:   return(0);
    7131: }

    7134: /*@C
    7135:   DMCreateLabel - Create a label of the given name if it does not already exist

    7137:   Not Collective

    7139:   Input Parameters:
    7140: + dm   - The DM object
    7141: - name - The label name

    7143:   Level: intermediate

    7145: .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7146: @*/
    7147: PetscErrorCode DMCreateLabel(DM dm, const char name[])
    7148: {
    7149:   PetscBool      flg;
    7150:   DMLabel        label;

    7156:   DMHasLabel(dm, name, &flg);
    7157:   if (!flg) {
    7158:     DMLabelCreate(PETSC_COMM_SELF, name, &label);
    7159:     DMAddLabel(dm, label);
    7160:     DMLabelDestroy(&label);
    7161:   }
    7162:   return(0);
    7163: }

    7165: /*@C
    7166:   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default

    7168:   Not Collective

    7170:   Input Parameters:
    7171: + dm   - The DM object
    7172: . name - The label name
    7173: - point - The mesh point

    7175:   Output Parameter:
    7176: . value - The label value for this point, or -1 if the point is not in the label

    7178:   Level: beginner

    7180: .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
    7181: @*/
    7182: PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
    7183: {
    7184:   DMLabel        label;

    7190:   DMGetLabel(dm, name, &label);
    7191:   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
    7192:   DMLabelGetValue(label, point, value);
    7193:   return(0);
    7194: }

    7196: /*@C
    7197:   DMSetLabelValue - Add a point to a Sieve Label with given value

    7199:   Not Collective

    7201:   Input Parameters:
    7202: + dm   - The DM object
    7203: . name - The label name
    7204: . point - The mesh point
    7205: - value - The label value for this point

    7207:   Output Parameter:

    7209:   Level: beginner

    7211: .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
    7212: @*/
    7213: PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7214: {
    7215:   DMLabel        label;

    7221:   DMGetLabel(dm, name, &label);
    7222:   if (!label) {
    7223:     DMCreateLabel(dm, name);
    7224:     DMGetLabel(dm, name, &label);
    7225:   }
    7226:   DMLabelSetValue(label, point, value);
    7227:   return(0);
    7228: }

    7230: /*@C
    7231:   DMClearLabelValue - Remove a point from a Sieve Label with given value

    7233:   Not Collective

    7235:   Input Parameters:
    7236: + dm   - The DM object
    7237: . name - The label name
    7238: . point - The mesh point
    7239: - value - The label value for this point

    7241:   Output Parameter:

    7243:   Level: beginner

    7245: .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
    7246: @*/
    7247: PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
    7248: {
    7249:   DMLabel        label;

    7255:   DMGetLabel(dm, name, &label);
    7256:   if (!label) return(0);
    7257:   DMLabelClearValue(label, point, value);
    7258:   return(0);
    7259: }

    7261: /*@C
    7262:   DMGetLabelSize - Get the number of different integer ids in a Label

    7264:   Not Collective

    7266:   Input Parameters:
    7267: + dm   - The DM object
    7268: - name - The label name

    7270:   Output Parameter:
    7271: . size - The number of different integer ids, or 0 if the label does not exist

    7273:   Level: beginner

    7275: .seealso: DMLabelGetNumValues(), DMSetLabelValue()
    7276: @*/
    7277: PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
    7278: {
    7279:   DMLabel        label;

    7286:   DMGetLabel(dm, name, &label);
    7287:   *size = 0;
    7288:   if (!label) return(0);
    7289:   DMLabelGetNumValues(label, size);
    7290:   return(0);
    7291: }

    7293: /*@C
    7294:   DMGetLabelIdIS - Get the integer ids in a label

    7296:   Not Collective

    7298:   Input Parameters:
    7299: + mesh - The DM object
    7300: - name - The label name

    7302:   Output Parameter:
    7303: . ids - The integer ids, or NULL if the label does not exist

    7305:   Level: beginner

    7307: .seealso: DMLabelGetValueIS(), DMGetLabelSize()
    7308: @*/
    7309: PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
    7310: {
    7311:   DMLabel        label;

    7318:   DMGetLabel(dm, name, &label);
    7319:   *ids = NULL;
    7320:  if (label) {
    7321:     DMLabelGetValueIS(label, ids);
    7322:   } else {
    7323:     /* returning an empty IS */
    7324:     ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);
    7325:   }
    7326:   return(0);
    7327: }

    7329: /*@C
    7330:   DMGetStratumSize - Get the number of points in a label stratum

    7332:   Not Collective

    7334:   Input Parameters:
    7335: + dm - The DM object
    7336: . name - The label name
    7337: - value - The stratum value

    7339:   Output Parameter:
    7340: . size - The stratum size

    7342:   Level: beginner

    7344: .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
    7345: @*/
    7346: PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
    7347: {
    7348:   DMLabel        label;

    7355:   DMGetLabel(dm, name, &label);
    7356:   *size = 0;
    7357:   if (!label) return(0);
    7358:   DMLabelGetStratumSize(label, value, size);
    7359:   return(0);
    7360: }

    7362: /*@C
    7363:   DMGetStratumIS - Get the points in a label stratum

    7365:   Not Collective

    7367:   Input Parameters:
    7368: + dm - The DM object
    7369: . name - The label name
    7370: - value - The stratum value

    7372:   Output Parameter:
    7373: . points - The stratum points, or NULL if the label does not exist or does not have that value

    7375:   Level: beginner

    7377: .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
    7378: @*/
    7379: PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
    7380: {
    7381:   DMLabel        label;

    7388:   DMGetLabel(dm, name, &label);
    7389:   *points = NULL;
    7390:   if (!label) return(0);
    7391:   DMLabelGetStratumIS(label, value, points);
    7392:   return(0);
    7393: }

    7395: /*@C
    7396:   DMSetStratumIS - Set the points in a label stratum

    7398:   Not Collective

    7400:   Input Parameters:
    7401: + dm - The DM object
    7402: . name - The label name
    7403: . value - The stratum value
    7404: - points - The stratum points

    7406:   Level: beginner

    7408: .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
    7409: @*/
    7410: PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
    7411: {
    7412:   DMLabel        label;

    7419:   DMGetLabel(dm, name, &label);
    7420:   if (!label) return(0);
    7421:   DMLabelSetStratumIS(label, value, points);
    7422:   return(0);
    7423: }

    7425: /*@C
    7426:   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label

    7428:   Not Collective

    7430:   Input Parameters:
    7431: + dm   - The DM object
    7432: . name - The label name
    7433: - value - The label value for this point

    7435:   Output Parameter:

    7437:   Level: beginner

    7439: .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
    7440: @*/
    7441: PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
    7442: {
    7443:   DMLabel        label;

    7449:   DMGetLabel(dm, name, &label);
    7450:   if (!label) return(0);
    7451:   DMLabelClearStratum(label, value);
    7452:   return(0);
    7453: }

    7455: /*@
    7456:   DMGetNumLabels - Return the number of labels defined by the mesh

    7458:   Not Collective

    7460:   Input Parameter:
    7461: . dm   - The DM object

    7463:   Output Parameter:
    7464: . numLabels - the number of Labels

    7466:   Level: intermediate

    7468: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7469: @*/
    7470: PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
    7471: {
    7472:   DMLabelLink next = dm->labels;
    7473:   PetscInt  n    = 0;

    7478:   while (next) {++n; next = next->next;}
    7479:   *numLabels = n;
    7480:   return(0);
    7481: }

    7483: /*@C
    7484:   DMGetLabelName - Return the name of nth label

    7486:   Not Collective

    7488:   Input Parameters:
    7489: + dm - The DM object
    7490: - n  - the label number

    7492:   Output Parameter:
    7493: . name - the label name

    7495:   Level: intermediate

    7497: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7498: @*/
    7499: PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
    7500: {
    7501:   DMLabelLink    next = dm->labels;
    7502:   PetscInt       l    = 0;

    7508:   while (next) {
    7509:     if (l == n) {
    7510:       PetscObjectGetName((PetscObject) next->label, name);
    7511:       return(0);
    7512:     }
    7513:     ++l;
    7514:     next = next->next;
    7515:   }
    7516:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7517: }

    7519: /*@C
    7520:   DMHasLabel - Determine whether the mesh has a label of a given name

    7522:   Not Collective

    7524:   Input Parameters:
    7525: + dm   - The DM object
    7526: - name - The label name

    7528:   Output Parameter:
    7529: . hasLabel - PETSC_TRUE if the label is present

    7531:   Level: intermediate

    7533: .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7534: @*/
    7535: PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
    7536: {
    7537:   DMLabelLink    next = dm->labels;
    7538:   const char    *lname;

    7545:   *hasLabel = PETSC_FALSE;
    7546:   while (next) {
    7547:     PetscObjectGetName((PetscObject) next->label, &lname);
    7548:     PetscStrcmp(name, lname, hasLabel);
    7549:     if (*hasLabel) break;
    7550:     next = next->next;
    7551:   }
    7552:   return(0);
    7553: }

    7555: /*@C
    7556:   DMGetLabel - Return the label of a given name, or NULL

    7558:   Not Collective

    7560:   Input Parameters:
    7561: + dm   - The DM object
    7562: - name - The label name

    7564:   Output Parameter:
    7565: . label - The DMLabel, or NULL if the label is absent

    7567:   Level: intermediate

    7569: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7570: @*/
    7571: PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
    7572: {
    7573:   DMLabelLink    next = dm->labels;
    7574:   PetscBool      hasLabel;
    7575:   const char    *lname;

    7582:   *label = NULL;
    7583:   while (next) {
    7584:     PetscObjectGetName((PetscObject) next->label, &lname);
    7585:     PetscStrcmp(name, lname, &hasLabel);
    7586:     if (hasLabel) {
    7587:       *label = next->label;
    7588:       break;
    7589:     }
    7590:     next = next->next;
    7591:   }
    7592:   return(0);
    7593: }

    7595: /*@C
    7596:   DMGetLabelByNum - Return the nth label

    7598:   Not Collective

    7600:   Input Parameters:
    7601: + dm - The DM object
    7602: - n  - the label number

    7604:   Output Parameter:
    7605: . label - the label

    7607:   Level: intermediate

    7609: .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7610: @*/
    7611: PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
    7612: {
    7613:   DMLabelLink next = dm->labels;
    7614:   PetscInt    l    = 0;

    7619:   while (next) {
    7620:     if (l == n) {
    7621:       *label = next->label;
    7622:       return(0);
    7623:     }
    7624:     ++l;
    7625:     next = next->next;
    7626:   }
    7627:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
    7628: }

    7630: /*@C
    7631:   DMAddLabel - Add the label to this mesh

    7633:   Not Collective

    7635:   Input Parameters:
    7636: + dm   - The DM object
    7637: - label - The DMLabel

    7639:   Level: developer

    7641: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7642: @*/
    7643: PetscErrorCode DMAddLabel(DM dm, DMLabel label)
    7644: {
    7645:   DMLabelLink    l, *p, tmpLabel;
    7646:   PetscBool      hasLabel;
    7647:   const char    *lname;
    7648:   PetscBool      flg;

    7653:   PetscObjectGetName((PetscObject) label, &lname);
    7654:   DMHasLabel(dm, lname, &hasLabel);
    7655:   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
    7656:   PetscCalloc1(1, &tmpLabel);
    7657:   tmpLabel->label  = label;
    7658:   tmpLabel->output = PETSC_TRUE;
    7659:   for (p=&dm->labels; (l=*p); p=&l->next) {}
    7660:   *p = tmpLabel;
    7661:   PetscObjectReference((PetscObject)label);
    7662:   PetscStrcmp(lname, "depth", &flg);
    7663:   if (flg) dm->depthLabel = label;
    7664:   PetscStrcmp(lname, "celltype", &flg);
    7665:   if (flg) dm->celltypeLabel = label;
    7666:   return(0);
    7667: }

    7669: /*@C
    7670:   DMRemoveLabel - Remove the label given by name from this mesh

    7672:   Not Collective

    7674:   Input Parameters:
    7675: + dm   - The DM object
    7676: - name - The label name

    7678:   Output Parameter:
    7679: . label - The DMLabel, or NULL if the label is absent

    7681:   Level: developer

    7683:   Notes:
    7684:   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
    7685:   DMLabelDestroy() on the label.

    7687:   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
    7688:   call DMLabelDestroy(). Instead, the label is returned and the user is
    7689:   responsible of calling DMLabelDestroy() at some point.

    7691: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
    7692: @*/
    7693: PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
    7694: {
    7695:   DMLabelLink    link, *pnext;
    7696:   PetscBool      hasLabel;
    7697:   const char    *lname;

    7703:   if (label) {
    7705:     *label = NULL;
    7706:   }
    7707:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7708:     PetscObjectGetName((PetscObject) link->label, &lname);
    7709:     PetscStrcmp(name, lname, &hasLabel);
    7710:     if (hasLabel) {
    7711:       *pnext = link->next; /* Remove from list */
    7712:       PetscStrcmp(name, "depth", &hasLabel);
    7713:       if (hasLabel) dm->depthLabel = NULL;
    7714:       PetscStrcmp(name, "celltype", &hasLabel);
    7715:       if (hasLabel) dm->celltypeLabel = NULL;
    7716:       if (label) *label = link->label;
    7717:       else       {DMLabelDestroy(&link->label);}
    7718:       PetscFree(link);
    7719:       break;
    7720:     }
    7721:   }
    7722:   return(0);
    7723: }

    7725: /*@
    7726:   DMRemoveLabelBySelf - Remove the label from this mesh

    7728:   Not Collective

    7730:   Input Parameters:
    7731: + dm   - The DM object
    7732: . label - (Optional) The DMLabel to be removed from the DM
    7733: - failNotFound - Should it fail if the label is not found in the DM?

    7735:   Level: developer

    7737:   Notes:
    7738:   Only exactly the same instance is removed if found, name match is ignored.
    7739:   If the DM has an exclusive reference to the label, it gets destroyed and
    7740:   *label nullified.

    7742: .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
    7743: @*/
    7744: PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
    7745: {
    7746:   DMLabelLink    link, *pnext;
    7747:   PetscBool      hasLabel = PETSC_FALSE;

    7753:   if (!*label && !failNotFound) return(0);
    7756:   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
    7757:     if (*label == link->label) {
    7758:       hasLabel = PETSC_TRUE;
    7759:       *pnext = link->next; /* Remove from list */
    7760:       if (*label == dm->depthLabel) dm->depthLabel = NULL;
    7761:       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
    7762:       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
    7763:       DMLabelDestroy(&link->label);
    7764:       PetscFree(link);
    7765:       break;
    7766:     }
    7767:   }
    7768:   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
    7769:   return(0);
    7770: }

    7772: /*@C
    7773:   DMGetLabelOutput - Get the output flag for a given label

    7775:   Not Collective

    7777:   Input Parameters:
    7778: + dm   - The DM object
    7779: - name - The label name

    7781:   Output Parameter:
    7782: . output - The flag for output

    7784:   Level: developer

    7786: .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7787: @*/
    7788: PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
    7789: {
    7790:   DMLabelLink    next = dm->labels;
    7791:   const char    *lname;

    7798:   while (next) {
    7799:     PetscBool flg;

    7801:     PetscObjectGetName((PetscObject) next->label, &lname);
    7802:     PetscStrcmp(name, lname, &flg);
    7803:     if (flg) {*output = next->output; return(0);}
    7804:     next = next->next;
    7805:   }
    7806:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7807: }

    7809: /*@C
    7810:   DMSetLabelOutput - Set the output flag for a given label

    7812:   Not Collective

    7814:   Input Parameters:
    7815: + dm     - The DM object
    7816: . name   - The label name
    7817: - output - The flag for output

    7819:   Level: developer

    7821: .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
    7822: @*/
    7823: PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
    7824: {
    7825:   DMLabelLink    next = dm->labels;
    7826:   const char    *lname;

    7832:   while (next) {
    7833:     PetscBool flg;

    7835:     PetscObjectGetName((PetscObject) next->label, &lname);
    7836:     PetscStrcmp(name, lname, &flg);
    7837:     if (flg) {next->output = output; return(0);}
    7838:     next = next->next;
    7839:   }
    7840:   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
    7841: }

    7843: /*@
    7844:   DMCopyLabels - Copy labels from one mesh to another with a superset of the points

    7846:   Collective on dmA

    7848:   Input Parameter:
    7849: + dmA - The DM object with initial labels
    7850: . dmB - The DM object with copied labels
    7851: . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
    7852: - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)

    7854:   Level: intermediate

    7856:   Note: This is typically used when interpolating or otherwise adding to a mesh

    7858: .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
    7859: @*/
    7860: PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
    7861: {
    7862:   DMLabel        label, labelNew;
    7863:   const char    *name;
    7864:   PetscBool      flg;
    7865:   DMLabelLink    link;

    7873:   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
    7874:   if (dmA == dmB) return(0);
    7875:   for (link=dmA->labels; link; link=link->next) {
    7876:     label=link->label;
    7877:     PetscObjectGetName((PetscObject)label, &name);
    7878:     if (!all) {
    7879:       PetscStrcmp(name, "depth", &flg);
    7880:       if (flg) continue;
    7881:       PetscStrcmp(name, "dim", &flg);
    7882:       if (flg) continue;
    7883:       PetscStrcmp(name, "celltype", &flg);
    7884:       if (flg) continue;
    7885:     }
    7886:     if (mode==PETSC_COPY_VALUES) {
    7887:       DMLabelDuplicate(label, &labelNew);
    7888:     } else {
    7889:       labelNew = label;
    7890:     }
    7891:     DMAddLabel(dmB, labelNew);
    7892:     if (mode==PETSC_COPY_VALUES) {DMLabelDestroy(&labelNew);}
    7893:   }
    7894:   return(0);
    7895: }

    7897: /*@
    7898:   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement

    7900:   Input Parameter:
    7901: . dm - The DM object

    7903:   Output Parameter:
    7904: . cdm - The coarse DM

    7906:   Level: intermediate

    7908: .seealso: DMSetCoarseDM()
    7909: @*/
    7910: PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
    7911: {
    7915:   *cdm = dm->coarseMesh;
    7916:   return(0);
    7917: }

    7919: /*@
    7920:   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement

    7922:   Input Parameters:
    7923: + dm - The DM object
    7924: - cdm - The coarse DM

    7926:   Level: intermediate

    7928: .seealso: DMGetCoarseDM()
    7929: @*/
    7930: PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
    7931: {

    7937:   PetscObjectReference((PetscObject)cdm);
    7938:   DMDestroy(&dm->coarseMesh);
    7939:   dm->coarseMesh = cdm;
    7940:   return(0);
    7941: }

    7943: /*@
    7944:   DMGetFineDM - Get the fine mesh from which this was obtained by refinement

    7946:   Input Parameter:
    7947: . dm - The DM object

    7949:   Output Parameter:
    7950: . fdm - The fine DM

    7952:   Level: intermediate

    7954: .seealso: DMSetFineDM()
    7955: @*/
    7956: PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
    7957: {
    7961:   *fdm = dm->fineMesh;
    7962:   return(0);
    7963: }

    7965: /*@
    7966:   DMSetFineDM - Set the fine mesh from which this was obtained by refinement

    7968:   Input Parameters:
    7969: + dm - The DM object
    7970: - fdm - The fine DM

    7972:   Level: intermediate

    7974: .seealso: DMGetFineDM()
    7975: @*/
    7976: PetscErrorCode DMSetFineDM(DM dm, DM fdm)
    7977: {

    7983:   PetscObjectReference((PetscObject)fdm);
    7984:   DMDestroy(&dm->fineMesh);
    7985:   dm->fineMesh = fdm;
    7986:   return(0);
    7987: }

    7989: /*=== DMBoundary code ===*/

    7991: PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
    7992: {
    7993:   PetscInt       d;

    7997:   for (d = 0; d < dm->Nds; ++d) {
    7998:     PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);
    7999:   }
    8000:   return(0);
    8001: }

    8003: /*@C
    8004:   DMAddBoundary - Add a boundary condition to the model

    8006:   Collective on dm

    8008:   Input Parameters:
    8009: + dm          - The DM, with a PetscDS that matches the problem being constrained
    8010: . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8011: . name        - The BC name
    8012: . labelname   - The label defining constrained points
    8013: . field       - The field to constrain
    8014: . numcomps    - The number of constrained field components (0 will constrain all fields)
    8015: . comps       - An array of constrained component numbers
    8016: . bcFunc      - A pointwise function giving boundary values
    8017: . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
    8018: . numids      - The number of DMLabel ids for constrained points
    8019: . ids         - An array of ids for constrained points
    8020: - ctx         - An optional user context for bcFunc

    8022:   Options Database Keys:
    8023: + -bc_<boundary name> <num> - Overrides the boundary ids
    8024: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8026:   Note:
    8027:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

    8029: $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

    8031:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    8033: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8034: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8035: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8036: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    8038: + dim - the spatial dimension
    8039: . Nf - the number of fields
    8040: . uOff - the offset into u[] and u_t[] for each field
    8041: . uOff_x - the offset into u_x[] for each field
    8042: . u - each field evaluated at the current point
    8043: . u_t - the time derivative of each field evaluated at the current point
    8044: . u_x - the gradient of each field evaluated at the current point
    8045: . aOff - the offset into a[] and a_t[] for each auxiliary field
    8046: . aOff_x - the offset into a_x[] for each auxiliary field
    8047: . a - each auxiliary field evaluated at the current point
    8048: . a_t - the time derivative of each auxiliary field evaluated at the current point
    8049: . a_x - the gradient of auxiliary each field evaluated at the current point
    8050: . t - current time
    8051: . x - coordinates of the current point
    8052: . numConstants - number of constant parameters
    8053: . constants - constant parameters
    8054: - bcval - output values at the current point

    8056:   Level: developer

    8058: .seealso: DMGetBoundary(), PetscDSAddBoundary()
    8059: @*/
    8060: 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)
    8061: {
    8062:   PetscDS        ds;

    8071:   DMGetDS(dm, &ds);
    8072:   DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);
    8073:   PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);
    8074:   return(0);
    8075: }

    8077: /*@
    8078:   DMGetNumBoundary - Get the number of registered BC

    8080:   Input Parameters:
    8081: . dm - The mesh object

    8083:   Output Parameters:
    8084: . numBd - The number of BC

    8086:   Level: intermediate

    8088: .seealso: DMAddBoundary(), DMGetBoundary()
    8089: @*/
    8090: PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
    8091: {
    8092:   PetscDS        ds;

    8097:   DMGetDS(dm, &ds);
    8098:   PetscDSGetNumBoundary(ds, numBd);
    8099:   return(0);
    8100: }

    8102: /*@C
    8103:   DMGetBoundary - Get a model boundary condition

    8105:   Input Parameters:
    8106: + dm          - The mesh object
    8107: - bd          - The BC number

    8109:   Output Parameters:
    8110: + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    8111: . name        - The BC name
    8112: . labelname   - The label defining constrained points
    8113: . field       - The field to constrain
    8114: . numcomps    - The number of constrained field components
    8115: . comps       - An array of constrained component numbers
    8116: . bcFunc      - A pointwise function giving boundary values
    8117: . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
    8118: . numids      - The number of DMLabel ids for constrained points
    8119: . ids         - An array of ids for constrained points
    8120: - ctx         - An optional user context for bcFunc

    8122:   Options Database Keys:
    8123: + -bc_<boundary name> <num> - Overrides the boundary ids
    8124: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    8126:   Level: developer

    8128: .seealso: DMAddBoundary()
    8129: @*/
    8130: 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)
    8131: {
    8132:   PetscDS        ds;

    8137:   DMGetDS(dm, &ds);
    8138:   PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);
    8139:   return(0);
    8140: }

    8142: static PetscErrorCode DMPopulateBoundary(DM dm)
    8143: {
    8144:   PetscDS        ds;
    8145:   DMBoundary    *lastnext;
    8146:   DSBoundary     dsbound;

    8150:   DMGetDS(dm, &ds);
    8151:   dsbound = ds->boundary;
    8152:   if (dm->boundary) {
    8153:     DMBoundary next = dm->boundary;

    8155:     /* quick check to see if the PetscDS has changed */
    8156:     if (next->dsboundary == dsbound) return(0);
    8157:     /* the PetscDS has changed: tear down and rebuild */
    8158:     while (next) {
    8159:       DMBoundary b = next;

    8161:       next = b->next;
    8162:       PetscFree(b);
    8163:     }
    8164:     dm->boundary = NULL;
    8165:   }

    8167:   lastnext = &(dm->boundary);
    8168:   while (dsbound) {
    8169:     DMBoundary dmbound;

    8171:     PetscNew(&dmbound);
    8172:     dmbound->dsboundary = dsbound;
    8173:     DMGetLabel(dm, dsbound->labelname, &(dmbound->label));
    8174:     if (!dmbound->label) {PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);}
    8175:     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
    8176:     *lastnext = dmbound;
    8177:     lastnext = &(dmbound->next);
    8178:     dsbound = dsbound->next;
    8179:   }
    8180:   return(0);
    8181: }

    8183: PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
    8184: {
    8185:   DMBoundary     b;

    8191:   *isBd = PETSC_FALSE;
    8192:   DMPopulateBoundary(dm);
    8193:   b = dm->boundary;
    8194:   while (b && !(*isBd)) {
    8195:     DMLabel    label = b->label;
    8196:     DSBoundary dsb = b->dsboundary;

    8198:     if (label) {
    8199:       PetscInt i;

    8201:       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
    8202:         DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);
    8203:       }
    8204:     }
    8205:     b = b->next;
    8206:   }
    8207:   return(0);
    8208: }

    8210: /*@C
    8211:   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.

    8213:   Collective on DM

    8215:   Input Parameters:
    8216: + dm      - The DM
    8217: . time    - The time
    8218: . funcs   - The coordinate functions to evaluate, one per field
    8219: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8220: - mode    - The insertion mode for values

    8222:   Output Parameter:
    8223: . X - vector

    8225:    Calling sequence of func:
    8226: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8228: +  dim - The spatial dimension
    8229: .  time - The time at which to sample
    8230: .  x   - The coordinates
    8231: .  Nf  - The number of fields
    8232: .  u   - The output field values
    8233: -  ctx - optional user-defined function context

    8235:   Level: developer

    8237: .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8238: @*/
    8239: PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
    8240: {
    8241:   Vec            localX;

    8246:   DMGetLocalVector(dm, &localX);
    8247:   DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);
    8248:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8249:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8250:   DMRestoreLocalVector(dm, &localX);
    8251:   return(0);
    8252: }

    8254: /*@C
    8255:   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.

    8257:   Not collective

    8259:   Input Parameters:
    8260: + dm      - The DM
    8261: . time    - The time
    8262: . funcs   - The coordinate functions to evaluate, one per field
    8263: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8264: - mode    - The insertion mode for values

    8266:   Output Parameter:
    8267: . localX - vector

    8269:    Calling sequence of func:
    8270: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8272: +  dim - The spatial dimension
    8273: .  x   - The coordinates
    8274: .  Nf  - The number of fields
    8275: .  u   - The output field values
    8276: -  ctx - optional user-defined function context

    8278:   Level: developer

    8280: .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8281: @*/
    8282: PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
    8283: {

    8289:   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
    8290:   (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);
    8291:   return(0);
    8292: }

    8294: /*@C
    8295:   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.

    8297:   Collective on DM

    8299:   Input Parameters:
    8300: + dm      - The DM
    8301: . time    - The time
    8302: . label   - The DMLabel selecting the portion of the mesh for projection
    8303: . funcs   - The coordinate functions to evaluate, one per field
    8304: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8305: - mode    - The insertion mode for values

    8307:   Output Parameter:
    8308: . X - vector

    8310:    Calling sequence of func:
    8311: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8313: +  dim - The spatial dimension
    8314: .  x   - The coordinates
    8315: .  Nf  - The number of fields
    8316: .  u   - The output field values
    8317: -  ctx - optional user-defined function context

    8319:   Level: developer

    8321: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
    8322: @*/
    8323: 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)
    8324: {
    8325:   Vec            localX;

    8330:   DMGetLocalVector(dm, &localX);
    8331:   DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8332:   DMLocalToGlobalBegin(dm, localX, mode, X);
    8333:   DMLocalToGlobalEnd(dm, localX, mode, X);
    8334:   DMRestoreLocalVector(dm, &localX);
    8335:   return(0);
    8336: }

    8338: /*@C
    8339:   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.

    8341:   Not collective

    8343:   Input Parameters:
    8344: + dm      - The DM
    8345: . time    - The time
    8346: . label   - The DMLabel selecting the portion of the mesh for projection
    8347: . funcs   - The coordinate functions to evaluate, one per field
    8348: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
    8349: - mode    - The insertion mode for values

    8351:   Output Parameter:
    8352: . localX - vector

    8354:    Calling sequence of func:
    8355: $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);

    8357: +  dim - The spatial dimension
    8358: .  x   - The coordinates
    8359: .  Nf  - The number of fields
    8360: .  u   - The output field values
    8361: -  ctx - optional user-defined function context

    8363:   Level: developer

    8365: .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
    8366: @*/
    8367: 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)
    8368: {

    8374:   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
    8375:   (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
    8376:   return(0);
    8377: }

    8379: /*@C
    8380:   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.

    8382:   Not collective

    8384:   Input Parameters:
    8385: + dm      - The DM
    8386: . time    - The time
    8387: . localU  - The input field vector
    8388: . funcs   - The functions to evaluate, one per field
    8389: - mode    - The insertion mode for values

    8391:   Output Parameter:
    8392: . localX  - The output vector

    8394:    Calling sequence of func:
    8395: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8396: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8397: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8398: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8400: +  dim          - The spatial dimension
    8401: .  Nf           - The number of input fields
    8402: .  NfAux        - The number of input auxiliary fields
    8403: .  uOff         - The offset of each field in u[]
    8404: .  uOff_x       - The offset of each field in u_x[]
    8405: .  u            - The field values at this point in space
    8406: .  u_t          - The field time derivative at this point in space (or NULL)
    8407: .  u_x          - The field derivatives at this point in space
    8408: .  aOff         - The offset of each auxiliary field in u[]
    8409: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8410: .  a            - The auxiliary field values at this point in space
    8411: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8412: .  a_x          - The auxiliary field derivatives at this point in space
    8413: .  t            - The current time
    8414: .  x            - The coordinates of this point
    8415: .  numConstants - The number of constants
    8416: .  constants    - The value of each constant
    8417: -  f            - The value of the function at this point in space

    8419:   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.
    8420:   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
    8421:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8422:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8424:   Level: intermediate

    8426: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8427: @*/
    8428: PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
    8429:                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
    8430:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8431:                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8432:                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8433:                                    InsertMode mode, Vec localX)
    8434: {

    8441:   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
    8442:   (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);
    8443:   return(0);
    8444: }

    8446: /*@C
    8447:   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.

    8449:   Not collective

    8451:   Input Parameters:
    8452: + dm      - The DM
    8453: . time    - The time
    8454: . label   - The DMLabel marking the portion of the domain to output
    8455: . numIds  - The number of label ids to use
    8456: . ids     - The label ids to use for marking
    8457: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8458: . comps   - The components to set in the output, or NULL for all components
    8459: . localU  - The input field vector
    8460: . funcs   - The functions to evaluate, one per field
    8461: - mode    - The insertion mode for values

    8463:   Output Parameter:
    8464: . localX  - The output vector

    8466:    Calling sequence of func:
    8467: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8468: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8469: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8470: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8472: +  dim          - The spatial dimension
    8473: .  Nf           - The number of input fields
    8474: .  NfAux        - The number of input auxiliary fields
    8475: .  uOff         - The offset of each field in u[]
    8476: .  uOff_x       - The offset of each field in u_x[]
    8477: .  u            - The field values at this point in space
    8478: .  u_t          - The field time derivative at this point in space (or NULL)
    8479: .  u_x          - The field derivatives at this point in space
    8480: .  aOff         - The offset of each auxiliary field in u[]
    8481: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8482: .  a            - The auxiliary field values at this point in space
    8483: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8484: .  a_x          - The auxiliary field derivatives at this point in space
    8485: .  t            - The current time
    8486: .  x            - The coordinates of this point
    8487: .  numConstants - The number of constants
    8488: .  constants    - The value of each constant
    8489: -  f            - The value of the function at this point in space

    8491:   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.
    8492:   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
    8493:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8494:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8496:   Level: intermediate

    8498: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8499: @*/
    8500: PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8501:                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
    8502:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8503:                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8504:                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8505:                                         InsertMode mode, Vec localX)
    8506: {

    8513:   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
    8514:   (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8515:   return(0);
    8516: }

    8518: /*@C
    8519:   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.

    8521:   Not collective

    8523:   Input Parameters:
    8524: + dm      - The DM
    8525: . time    - The time
    8526: . label   - The DMLabel marking the portion of the domain boundary to output
    8527: . numIds  - The number of label ids to use
    8528: . ids     - The label ids to use for marking
    8529: . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
    8530: . comps   - The components to set in the output, or NULL for all components
    8531: . localU  - The input field vector
    8532: . funcs   - The functions to evaluate, one per field
    8533: - mode    - The insertion mode for values

    8535:   Output Parameter:
    8536: . localX  - The output vector

    8538:    Calling sequence of func:
    8539: $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    8540: $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    8541: $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    8542: $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);

    8544: +  dim          - The spatial dimension
    8545: .  Nf           - The number of input fields
    8546: .  NfAux        - The number of input auxiliary fields
    8547: .  uOff         - The offset of each field in u[]
    8548: .  uOff_x       - The offset of each field in u_x[]
    8549: .  u            - The field values at this point in space
    8550: .  u_t          - The field time derivative at this point in space (or NULL)
    8551: .  u_x          - The field derivatives at this point in space
    8552: .  aOff         - The offset of each auxiliary field in u[]
    8553: .  aOff_x       - The offset of each auxiliary field in u_x[]
    8554: .  a            - The auxiliary field values at this point in space
    8555: .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
    8556: .  a_x          - The auxiliary field derivatives at this point in space
    8557: .  t            - The current time
    8558: .  x            - The coordinates of this point
    8559: .  n            - The face normal
    8560: .  numConstants - The number of constants
    8561: .  constants    - The value of each constant
    8562: -  f            - The value of the function at this point in space

    8564:   Note:
    8565:   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
    8566:   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
    8567:   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
    8568:   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.

    8570:   Level: intermediate

    8572: .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
    8573: @*/
    8574: PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
    8575:                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
    8576:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8577:                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    8578:                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    8579:                                           InsertMode mode, Vec localX)
    8580: {

    8587:   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
    8588:   (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
    8589:   return(0);
    8590: }

    8592: /*@C
    8593:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

    8595:   Input Parameters:
    8596: + dm    - The DM
    8597: . time  - The time
    8598: . funcs - The functions to evaluate for each field component
    8599: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8600: - X     - The coefficient vector u_h, a global vector

    8602:   Output Parameter:
    8603: . diff - The diff ||u - u_h||_2

    8605:   Level: developer

    8607: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8608: @*/
    8609: PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
    8610: {

    8616:   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
    8617:   (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);
    8618:   return(0);
    8619: }

    8621: /*@C
    8622:   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

    8624:   Collective on dm

    8626:   Input Parameters:
    8627: + dm    - The DM
    8628: , time  - The time
    8629: . funcs - The gradient functions to evaluate for each field component
    8630: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8631: . X     - The coefficient vector u_h, a global vector
    8632: - n     - The vector to project along

    8634:   Output Parameter:
    8635: . diff - The diff ||(grad u - grad u_h) . n||_2

    8637:   Level: developer

    8639: .seealso: DMProjectFunction(), DMComputeL2Diff()
    8640: @*/
    8641: 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)
    8642: {

    8648:   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
    8649:   (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);
    8650:   return(0);
    8651: }

    8653: /*@C
    8654:   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.

    8656:   Collective on dm

    8658:   Input Parameters:
    8659: + dm    - The DM
    8660: . time  - The time
    8661: . funcs - The functions to evaluate for each field component
    8662: . ctxs  - Optional array of contexts to pass to each function, or NULL.
    8663: - X     - The coefficient vector u_h, a global vector

    8665:   Output Parameter:
    8666: . diff - The array of differences, ||u^f - u^f_h||_2

    8668:   Level: developer

    8670: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
    8671: @*/
    8672: PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
    8673: {

    8679:   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
    8680:   (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);
    8681:   return(0);
    8682: }

    8684: /*@C
    8685:   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
    8686:                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.

    8688:   Collective on dm

    8690:   Input parameters:
    8691: + dm - the pre-adaptation DM object
    8692: - label - label with the flags

    8694:   Output parameters:
    8695: . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.

    8697:   Level: intermediate

    8699: .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
    8700: @*/
    8701: PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
    8702: {

    8709:   *dmAdapt = NULL;
    8710:   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
    8711:   (dm->ops->adaptlabel)(dm, label, dmAdapt);
    8712:   return(0);
    8713: }

    8715: /*@C
    8716:   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.

    8718:   Input Parameters:
    8719: + dm - The DM object
    8720: . metric - The metric to which the mesh is adapted, defined vertex-wise.
    8721: - 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_".

    8723:   Output Parameter:
    8724: . dmAdapt  - Pointer to the DM object containing the adapted mesh

    8726:   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object

    8728:   Level: advanced

    8730: .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
    8731: @*/
    8732: PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
    8733: {

    8741:   *dmAdapt = NULL;
    8742:   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
    8743:   (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);
    8744:   return(0);
    8745: }

    8747: /*@C
    8748:  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors

    8750:  Not Collective

    8752:  Input Parameter:
    8753: .  dm    - The DM

    8755:  Output Parameters:
    8756: +  nranks - the number of neighbours
    8757: -  ranks - the neighbors ranks

    8759:  Notes:
    8760:  Do not free the array, it is freed when the DM is destroyed.

    8762:  Level: beginner

    8764:  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
    8765: @*/
    8766: PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
    8767: {

    8772:   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
    8773:   (dm->ops->getneighbors)(dm,nranks,ranks);
    8774:   return(0);
    8775: }

    8777: #include <petsc/private/matimpl.h>

    8779: /*
    8780:     Converts the input vector to a ghosted vector and then calls the standard coloring code.
    8781:     This has be a different function because it requires DM which is not defined in the Mat library
    8782: */
    8783: PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
    8784: {

    8788:   if (coloring->ctype == IS_COLORING_LOCAL) {
    8789:     Vec x1local;
    8790:     DM  dm;
    8791:     MatGetDM(J,&dm);
    8792:     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
    8793:     DMGetLocalVector(dm,&x1local);
    8794:     DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);
    8795:     DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);
    8796:     x1   = x1local;
    8797:   }
    8798:   MatFDColoringApply_AIJ(J,coloring,x1,sctx);
    8799:   if (coloring->ctype == IS_COLORING_LOCAL) {
    8800:     DM  dm;
    8801:     MatGetDM(J,&dm);
    8802:     DMRestoreLocalVector(dm,&x1);
    8803:   }
    8804:   return(0);
    8805: }

    8807: /*@
    8808:     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring

    8810:     Input Parameter:
    8811: .    coloring - the MatFDColoring object

    8813:     Developer Notes:
    8814:     this routine exists because the PETSc Mat library does not know about the DM objects

    8816:     Level: advanced

    8818: .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
    8819: @*/
    8820: PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
    8821: {
    8823:   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
    8824:   return(0);
    8825: }

    8827: /*@
    8828:     DMGetCompatibility - determine if two DMs are compatible

    8830:     Collective

    8832:     Input Parameters:
    8833: +    dm1 - the first DM
    8834: -    dm2 - the second DM

    8836:     Output Parameters:
    8837: +    compatible - whether or not the two DMs are compatible
    8838: -    set - whether or not the compatible value was set

    8840:     Notes:
    8841:     Two DMs are deemed compatible if they represent the same parallel decomposition
    8842:     of the same topology. This implies that the section (field data) on one
    8843:     "makes sense" with respect to the topology and parallel decomposition of the other.
    8844:     Loosely speaking, compatible DMs represent the same domain and parallel
    8845:     decomposition, but hold different data.

    8847:     Typically, one would confirm compatibility if intending to simultaneously iterate
    8848:     over a pair of vectors obtained from different DMs.

    8850:     For example, two DMDA objects are compatible if they have the same local
    8851:     and global sizes and the same stencil width. They can have different numbers
    8852:     of degrees of freedom per node. Thus, one could use the node numbering from
    8853:     either DM in bounds for a loop over vectors derived from either DM.

    8855:     Consider the operation of summing data living on a 2-dof DMDA to data living
    8856:     on a 1-dof DMDA, which should be compatible, as in the following snippet.
    8857: .vb
    8858:   ...
    8859:   DMGetCompatibility(da1,da2,&compatible,&set);
    8860:   if (set && compatible)  {
    8861:     DMDAVecGetArrayDOF(da1,vec1,&arr1);
    8862:     DMDAVecGetArrayDOF(da2,vec2,&arr2);
    8863:     DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);
    8864:     for (j=y; j<y+n; ++j) {
    8865:       for (i=x; i<x+m, ++i) {
    8866:         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
    8867:       }
    8868:     }
    8869:     DMDAVecRestoreArrayDOF(da1,vec1,&arr1);
    8870:     DMDAVecRestoreArrayDOF(da2,vec2,&arr2);
    8871:   } else {
    8872:     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
    8873:   }
    8874:   ...
    8875: .ve

    8877:     Checking compatibility might be expensive for a given implementation of DM,
    8878:     or might be impossible to unambiguously confirm or deny. For this reason,
    8879:     this function may decline to determine compatibility, and hence users should
    8880:     always check the "set" output parameter.

    8882:     A DM is always compatible with itself.

    8884:     In the current implementation, DMs which live on "unequal" communicators
    8885:     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
    8886:     incompatible.

    8888:     This function is labeled "Collective," as information about all subdomains
    8889:     is required on each rank. However, in DM implementations which store all this
    8890:     information locally, this function may be merely "Logically Collective".

    8892:     Developer Notes:
    8893:     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
    8894:     iff B is compatible with A. Thus, this function checks the implementations
    8895:     of both dm and dmc (if they are of different types), attempting to determine
    8896:     compatibility. It is left to DM implementers to ensure that symmetry is
    8897:     preserved. The simplest way to do this is, when implementing type-specific
    8898:     logic for this function, is to check for existing logic in the implementation
    8899:     of other DM types and let *set = PETSC_FALSE if found.

    8901:     Level: advanced

    8903: .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
    8904: @*/

    8906: PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
    8907: {
    8909:   PetscMPIInt    compareResult;
    8910:   DMType         type,type2;
    8911:   PetscBool      sameType;

    8917:   /* Declare a DM compatible with itself */
    8918:   if (dm1 == dm2) {
    8919:     *set = PETSC_TRUE;
    8920:     *compatible = PETSC_TRUE;
    8921:     return(0);
    8922:   }

    8924:   /* Declare a DM incompatible with a DM that lives on an "unequal"
    8925:      communicator. Note that this does not preclude compatibility with
    8926:      DMs living on "congruent" or "similar" communicators, but this must be
    8927:      determined by the implementation-specific logic */
    8928:   MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);
    8929:   if (compareResult == MPI_UNEQUAL) {
    8930:     *set = PETSC_TRUE;
    8931:     *compatible = PETSC_FALSE;
    8932:     return(0);
    8933:   }

    8935:   /* Pass to the implementation-specific routine, if one exists. */
    8936:   if (dm1->ops->getcompatibility) {
    8937:     (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);
    8938:     if (*set) return(0);
    8939:   }

    8941:   /* If dm1 and dm2 are of different types, then attempt to check compatibility
    8942:      with an implementation of this function from dm2 */
    8943:   DMGetType(dm1,&type);
    8944:   DMGetType(dm2,&type2);
    8945:   PetscStrcmp(type,type2,&sameType);
    8946:   if (!sameType && dm2->ops->getcompatibility) {
    8947:     (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set); /* Note argument order */
    8948:   } else {
    8949:     *set = PETSC_FALSE;
    8950:   }
    8951:   return(0);
    8952: }

    8954: /*@C
    8955:   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.

    8957:   Logically Collective on DM

    8959:   Input Parameters:
    8960: + DM - the DM
    8961: . f - the monitor function
    8962: . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
    8963: - monitordestroy - [optional] routine that frees monitor context (may be NULL)

    8965:   Options Database Keys:
    8966: - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
    8967:                             does not cancel those set via the options database.

    8969:   Notes:
    8970:   Several different monitoring routines may be set by calling
    8971:   DMMonitorSet() multiple times; all will be called in the
    8972:   order in which they were set.

    8974:   Fortran Notes:
    8975:   Only a single monitor function can be set for each DM object

    8977:   Level: intermediate

    8979: .seealso: DMMonitorCancel()
    8980: @*/
    8981: PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
    8982: {
    8983:   PetscInt       m;

    8988:   for (m = 0; m < dm->numbermonitors; ++m) {
    8989:     PetscBool identical;

    8991:     PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);
    8992:     if (identical) return(0);
    8993:   }
    8994:   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
    8995:   dm->monitor[dm->numbermonitors]          = f;
    8996:   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
    8997:   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
    8998:   return(0);
    8999: }

    9001: /*@
    9002:   DMMonitorCancel - Clears all the monitor functions for a DM object.

    9004:   Logically Collective on DM

    9006:   Input Parameter:
    9007: . dm - the DM

    9009:   Options Database Key:
    9010: . -dm_monitor_cancel - cancels all monitors that have been hardwired
    9011:   into a code by calls to DMonitorSet(), but does not cancel those
    9012:   set via the options database

    9014:   Notes:
    9015:   There is no way to clear one specific monitor from a DM object.

    9017:   Level: intermediate

    9019: .seealso: DMMonitorSet()
    9020: @*/
    9021: PetscErrorCode DMMonitorCancel(DM dm)
    9022: {
    9024:   PetscInt       m;

    9028:   for (m = 0; m < dm->numbermonitors; ++m) {
    9029:     if (dm->monitordestroy[m]) {(*dm->monitordestroy[m])(&dm->monitorcontext[m]);}
    9030:   }
    9031:   dm->numbermonitors = 0;
    9032:   return(0);
    9033: }

    9035: /*@C
    9036:   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user

    9038:   Collective on DM

    9040:   Input Parameters:
    9041: + dm   - DM object you wish to monitor
    9042: . name - the monitor type one is seeking
    9043: . help - message indicating what monitoring is done
    9044: . manual - manual page for the monitor
    9045: . monitor - the monitor function
    9046: - 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

    9048:   Output Parameter:
    9049: . flg - Flag set if the monitor was created

    9051:   Level: developer

    9053: .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
    9054:           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
    9055:           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
    9056:           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
    9057:           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
    9058:           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
    9059:           PetscOptionsFList(), PetscOptionsEList()
    9060: @*/
    9061: PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
    9062: {
    9063:   PetscViewer       viewer;
    9064:   PetscViewerFormat format;
    9065:   PetscErrorCode    ierr;

    9069:   PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);
    9070:   if (*flg) {
    9071:     PetscViewerAndFormat *vf;

    9073:     PetscViewerAndFormatCreate(viewer, format, &vf);
    9074:     PetscObjectDereference((PetscObject) viewer);
    9075:     if (monitorsetup) {(*monitorsetup)(dm, vf);}
    9076:     DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);
    9077:   }
    9078:   return(0);
    9079: }

    9081: /*@
    9082:    DMMonitor - runs the user provided monitor routines, if they exist

    9084:    Collective on DM

    9086:    Input Parameters:
    9087: .  dm - The DM

    9089:    Level: developer

    9091: .seealso: DMMonitorSet()
    9092: @*/
    9093: PetscErrorCode DMMonitor(DM dm)
    9094: {
    9095:   PetscInt       m;

    9099:   if (!dm) return(0);
    9101:   for (m = 0; m < dm->numbermonitors; ++m) {
    9102:     (*dm->monitor[m])(dm, dm->monitorcontext[m]);
    9103:   }
    9104:   return(0);
    9105: }