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

Actual source code: dmshell.c

      1: #include <petscdmshell.h>
      2: #include <petscmat.h>
      3: #include <petsc/private/dmimpl.h>

      5: typedef struct  {
      6:   Vec        Xglobal;
      7:   Vec        Xlocal;
      8:   Mat        A;
      9:   VecScatter gtol;
     10:   VecScatter ltog;
     11:   VecScatter ltol;
     12:   void       *ctx;
     13: } DM_Shell;

     15: /*@
     16:    DMGlobalToLocalBeginDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to begin a global to local scatter
     17:    Collective

     19:    Input Parameters:
     20: +  dm - shell DM
     21: .  g - global vector
     22: .  mode - InsertMode
     23: -  l - local vector

     25:    Level: advanced

     27:    Note:  This is not normally called directly by user code, generally user code calls DMGlobalToLocalBegin() and DMGlobalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function.

     29: .seealso: DMGlobalToLocalEndDefaultShell()
     30: @*/
     31: PetscErrorCode DMGlobalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
     32: {
     34:   DM_Shell       *shell = (DM_Shell*)dm->data;

     37:   if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
     38:   VecScatterBegin(shell->gtol,g,l,mode,SCATTER_FORWARD);
     39:   return(0);
     40: }

     42: /*@
     43:    DMGlobalToLocalEndDefaultShell - Uses the GlobalToLocal VecScatter context set by the user to end a global to local scatter
     44:    Collective

     46:    Input Parameters:
     47: +  dm - shell DM
     48: .  g - global vector
     49: .  mode - InsertMode
     50: -  l - local vector

     52:    Level: advanced

     54: .seealso: DMGlobalToLocalBeginDefaultShell()
     55: @*/
     56: PetscErrorCode DMGlobalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
     57: {
     59:   DM_Shell       *shell = (DM_Shell*)dm->data;

     62:    if (!shell->gtol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
     63:   VecScatterEnd(shell->gtol,g,l,mode,SCATTER_FORWARD);
     64:   return(0);
     65: }

     67: /*@
     68:    DMLocalToGlobalBeginDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to begin a local to global scatter
     69:    Collective

     71:    Input Parameters:
     72: +  dm - shell DM
     73: .  l - local vector
     74: .  mode - InsertMode
     75: -  g - global vector

     77:    Level: advanced

     79:    Note:  This is not normally called directly by user code, generally user code calls DMLocalToGlobalBegin() and DMLocalToGlobalEnd(). If the user provides their own custom routines to DMShellSetLocalToGlobal() then those routines might have reason to call this function.

     81: .seealso: DMLocalToGlobalEndDefaultShell()
     82: @*/
     83: PetscErrorCode DMLocalToGlobalBeginDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
     84: {
     86:   DM_Shell       *shell = (DM_Shell*)dm->data;

     89:   if (!shell->ltog) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()");
     90:   VecScatterBegin(shell->ltog,l,g,mode,SCATTER_FORWARD);
     91:   return(0);
     92: }

     94: /*@
     95:    DMLocalToGlobalEndDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to end a local to global scatter
     96:    Collective

     98:    Input Parameters:
     99: +  dm - shell DM
    100: .  l - local vector
    101: .  mode - InsertMode
    102: -  g - global vector

    104:    Level: advanced

    106: .seealso: DMLocalToGlobalBeginDefaultShell()
    107: @*/
    108: PetscErrorCode DMLocalToGlobalEndDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
    109: {
    111:   DM_Shell       *shell = (DM_Shell*)dm->data;

    114:    if (!shell->ltog) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToGlobalVecScatter()");
    115:   VecScatterEnd(shell->ltog,l,g,mode,SCATTER_FORWARD);
    116:   return(0);
    117: }

    119: /*@
    120:    DMLocalToLocalBeginDefaultShell - Uses the LocalToLocal VecScatter context set by the user to begin a local to local scatter
    121:    Collective

    123:    Input Parameters:
    124: +  dm - shell DM
    125: .  g - the original local vector
    126: -  mode - InsertMode

    128:    Output Parameter:
    129: .  l  - the local vector with correct ghost values

    131:    Level: advanced

    133:    Note:  This is not normally called directly by user code, generally user code calls DMLocalToLocalBegin() and DMLocalToLocalEnd(). If the user provides their own custom routines to DMShellSetLocalToLocal() then those routines might have reason to call this function.

    135: .seealso: DMLocalToLocalEndDefaultShell()
    136: @*/
    137: PetscErrorCode DMLocalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
    138: {
    140:   DM_Shell       *shell = (DM_Shell*)dm->data;

    143:   if (!shell->ltol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetLocalToLocalVecScatter()");
    144:   VecScatterBegin(shell->ltol,g,l,mode,SCATTER_FORWARD);
    145:   return(0);
    146: }

    148: /*@
    149:    DMLocalToLocalEndDefaultShell - Uses the LocalToLocal VecScatter context set by the user to end a local to local scatter
    150:    Collective

    152:    Input Parameters:
    153: +  dm - shell DM
    154: .  g - the original local vector
    155: -  mode - InsertMode

    157:    Output Parameter:
    158: .  l  - the local vector with correct ghost values

    160:    Level: advanced

    162: .seealso: DMLocalToLocalBeginDefaultShell()
    163: @*/
    164: PetscErrorCode DMLocalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
    165: {
    167:   DM_Shell       *shell = (DM_Shell*)dm->data;

    170:    if (!shell->ltol) SETERRQ(((PetscObject)dm)->comm,PETSC_ERR_ARG_WRONGSTATE, "Cannot be used without first setting the scatter context via DMShellSetGlobalToLocalVecScatter()");
    171:   VecScatterEnd(shell->ltol,g,l,mode,SCATTER_FORWARD);
    172:   return(0);
    173: }

    175: static PetscErrorCode DMCreateMatrix_Shell(DM dm,Mat *J)
    176: {
    178:   DM_Shell       *shell = (DM_Shell*)dm->data;
    179:   Mat            A;

    184:   if (!shell->A) {
    185:     if (shell->Xglobal) {
    186:       PetscInt m,M;
    187:       PetscInfo(dm,"Naively creating matrix using global vector distribution without preallocation\n");
    188:       VecGetSize(shell->Xglobal,&M);
    189:       VecGetLocalSize(shell->Xglobal,&m);
    190:       MatCreate(PetscObjectComm((PetscObject)dm),&shell->A);
    191:       MatSetSizes(shell->A,m,m,M,M);
    192:       MatSetType(shell->A,dm->mattype);
    193:       MatSetUp(shell->A);
    194:     } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector");
    195:   }
    196:   A = shell->A;
    197:   MatDuplicate(A,MAT_SHARE_NONZERO_PATTERN,J);
    198:   MatSetDM(*J,dm);
    199:   return(0);
    200: }

    202: PetscErrorCode DMCreateGlobalVector_Shell(DM dm,Vec *gvec)
    203: {
    205:   DM_Shell       *shell = (DM_Shell*)dm->data;
    206:   Vec            X;

    211:   *gvec = NULL;
    212:   X     = shell->Xglobal;
    213:   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetGlobalVector() or DMShellSetCreateGlobalVector()");
    214:   /* Need to create a copy in order to attach the DM to the vector */
    215:   VecDuplicate(X,gvec);
    216:   VecZeroEntries(*gvec);
    217:   VecSetDM(*gvec,dm);
    218:   return(0);
    219: }

    221: PetscErrorCode DMCreateLocalVector_Shell(DM dm,Vec *gvec)
    222: {
    224:   DM_Shell       *shell = (DM_Shell*)dm->data;
    225:   Vec            X;

    230:   *gvec = NULL;
    231:   X     = shell->Xlocal;
    232:   if (!X) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetLocalVector() or DMShellSetCreateLocalVector()");
    233:   /* Need to create a copy in order to attach the DM to the vector */
    234:   VecDuplicate(X,gvec);
    235:   VecZeroEntries(*gvec);
    236:   VecSetDM(*gvec,dm);
    237:   return(0);
    238: }

    240: /*@
    241:    DMShellSetContext - set some data to be usable by this DM

    243:    Collective

    245:    Input Parameters:
    246: +  dm - shell DM
    247: -  ctx - the context

    249:    Level: advanced

    251: .seealso: DMCreateMatrix(), DMShellGetContext()
    252: @*/
    253: PetscErrorCode DMShellSetContext(DM dm,void *ctx)
    254: {
    255:   DM_Shell       *shell = (DM_Shell*)dm->data;
    257:   PetscBool      isshell;

    261:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    262:   if (!isshell) return(0);
    263:   shell->ctx = ctx;
    264:   return(0);
    265: }

    267: /*@
    268:    DMShellGetContext - Returns the user-provided context associated to the DM

    270:    Collective

    272:    Input Parameter:
    273: .  dm - shell DM

    275:    Output Parameter:
    276: .  ctx - the context

    278:    Level: advanced

    280: .seealso: DMCreateMatrix(), DMShellSetContext()
    281: @*/
    282: PetscErrorCode DMShellGetContext(DM dm,void *ctx)
    283: {
    284:   DM_Shell       *shell = (DM_Shell*)dm->data;
    286:   PetscBool      isshell;

    290:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    291:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    292:   *(void**)ctx = shell->ctx;
    293:   return(0);
    294: }

    296: /*@
    297:    DMShellSetMatrix - sets a template matrix associated with the DMShell

    299:    Collective

    301:    Input Parameters:
    302: +  dm - shell DM
    303: -  J - template matrix

    305:    Level: advanced

    307:    Developer Notes:
    308:     To avoid circular references, if J is already associated to the same DM, then MatDuplicate(SHARE_NONZERO_PATTERN) is called, followed by removing the DM reference from the private template.

    310: .seealso: DMCreateMatrix(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    311: @*/
    312: PetscErrorCode DMShellSetMatrix(DM dm,Mat J)
    313: {
    314:   DM_Shell       *shell = (DM_Shell*)dm->data;
    316:   PetscBool      isshell;
    317:   DM             mdm;

    322:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    323:   if (!isshell) return(0);
    324:   if (J == shell->A) return(0);
    325:   MatGetDM(J,&mdm);
    326:   PetscObjectReference((PetscObject)J);
    327:   MatDestroy(&shell->A);
    328:   if (mdm == dm) {
    329:     MatDuplicate(J,MAT_SHARE_NONZERO_PATTERN,&shell->A);
    330:     MatSetDM(shell->A,NULL);
    331:   } else shell->A = J;
    332:   return(0);
    333: }

    335: /*@C
    336:    DMShellSetCreateMatrix - sets the routine to create a matrix associated with the shell DM

    338:    Logically Collective on dm

    340:    Input Parameters:
    341: +  dm - the shell DM
    342: -  func - the function to create a matrix

    344:    Level: advanced

    346: .seealso: DMCreateMatrix(), DMShellSetMatrix(), DMShellSetContext(), DMShellGetContext()
    347: @*/
    348: PetscErrorCode DMShellSetCreateMatrix(DM dm,PetscErrorCode (*func)(DM,Mat*))
    349: {
    352:   dm->ops->creatematrix = func;
    353:   return(0);
    354: }

    356: /*@
    357:    DMShellSetGlobalVector - sets a template global vector associated with the DMShell

    359:    Logically Collective on dm

    361:    Input Parameters:
    362: +  dm - shell DM
    363: -  X - template vector

    365:    Level: advanced

    367: .seealso: DMCreateGlobalVector(), DMShellSetMatrix(), DMShellSetCreateGlobalVector()
    368: @*/
    369: PetscErrorCode DMShellSetGlobalVector(DM dm,Vec X)
    370: {
    371:   DM_Shell       *shell = (DM_Shell*)dm->data;
    373:   PetscBool      isshell;
    374:   DM             vdm;

    379:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    380:   if (!isshell) return(0);
    381:   VecGetDM(X,&vdm);
    382:   /*
    383:       if the vector proposed as the new base global vector for the DM is a DM vector associated
    384:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
    385:       we get a circular dependency that prevents the DM from being destroy when it should be.
    386:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
    387:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
    388:       to set its input vector (which is associated with the DM) as the base global vector.
    389:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
    390:       for pointing out the problem.
    391:    */
    392:   if (vdm == dm) return(0);
    393:   PetscObjectReference((PetscObject)X);
    394:   VecDestroy(&shell->Xglobal);
    395:   shell->Xglobal = X;
    396:   return(0);
    397: }

    399: /*@
    400:   DMShellGetGlobalVector - Returns the template global vector associated with the DMShell, or NULL if it was not set

    402:    Not collective

    404:    Input Parameters:
    405: +  dm - shell DM
    406: -  X - template vector

    408:    Level: advanced

    410: .seealso: DMShellSetGlobalVector(), DMShellSetCreateGlobalVector(), DMCreateGlobalVector()
    411: @*/
    412: PetscErrorCode DMShellGetGlobalVector(DM dm, Vec *X)
    413: {
    414:   DM_Shell      *shell = (DM_Shell *) dm->data;
    415:   PetscBool      isshell;

    421:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    422:   if (!isshell) return(0);
    423:   *X = shell->Xglobal;
    424:   return(0);
    425: }

    427: /*@C
    428:    DMShellSetCreateGlobalVector - sets the routine to create a global vector associated with the shell DM

    430:    Logically Collective

    432:    Input Parameters:
    433: +  dm - the shell DM
    434: -  func - the creation routine

    436:    Level: advanced

    438: .seealso: DMShellSetGlobalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    439: @*/
    440: PetscErrorCode DMShellSetCreateGlobalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
    441: {
    444:   dm->ops->createglobalvector = func;
    445:   return(0);
    446: }

    448: /*@
    449:    DMShellSetLocalVector - sets a template local vector associated with the DMShell

    451:    Logically Collective on dm

    453:    Input Parameters:
    454: +  dm - shell DM
    455: -  X - template vector

    457:    Level: advanced

    459: .seealso: DMCreateLocalVector(), DMShellSetMatrix(), DMShellSetCreateLocalVector()
    460: @*/
    461: PetscErrorCode DMShellSetLocalVector(DM dm,Vec X)
    462: {
    463:   DM_Shell       *shell = (DM_Shell*)dm->data;
    465:   PetscBool      isshell;
    466:   DM             vdm;

    471:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    472:   if (!isshell) return(0);
    473:   VecGetDM(X,&vdm);
    474:   /*
    475:       if the vector proposed as the new base global vector for the DM is a DM vector associated
    476:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
    477:       we get a circular dependency that prevents the DM from being destroy when it should be.
    478:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
    479:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
    480:       to set its input vector (which is associated with the DM) as the base global vector.
    481:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
    482:       for pointing out the problem.
    483:    */
    484:   if (vdm == dm) return(0);
    485:   PetscObjectReference((PetscObject)X);
    486:   VecDestroy(&shell->Xlocal);
    487:   shell->Xlocal = X;
    488:   return(0);
    489: }

    491: /*@C
    492:    DMShellSetCreateLocalVector - sets the routine to create a local vector associated with the shell DM

    494:    Logically Collective

    496:    Input Parameters:
    497: +  dm - the shell DM
    498: -  func - the creation routine

    500:    Level: advanced

    502: .seealso: DMShellSetLocalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    503: @*/
    504: PetscErrorCode DMShellSetCreateLocalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
    505: {
    508:   dm->ops->createlocalvector = func;
    509:   return(0);
    510: }

    512: /*@C
    513:    DMShellSetGlobalToLocal - Sets the routines used to perform a global to local scatter

    515:    Logically Collective on dm

    517:    Input Parameters
    518: +  dm - the shell DM
    519: .  begin - the routine that begins the global to local scatter
    520: -  end - the routine that ends the global to local scatter

    522:    Notes:
    523:     If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then
    524:    DMGlobalToLocalBeginDefaultShell()/DMGlobalToLocalEndDefaultShell() are used to to perform the transfers

    526:    Level: advanced

    528: .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
    529: @*/
    530: PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    531: {
    534:   dm->ops->globaltolocalbegin = begin;
    535:   dm->ops->globaltolocalend = end;
    536:   return(0);
    537: }

    539: /*@C
    540:    DMShellSetLocalToGlobal - Sets the routines used to perform a local to global scatter

    542:    Logically Collective on dm

    544:    Input Parameters
    545: +  dm - the shell DM
    546: .  begin - the routine that begins the local to global scatter
    547: -  end - the routine that ends the local to global scatter

    549:    Notes:
    550:     If these functions are not provided but DMShellSetLocalToGlobalVecScatter() is called then
    551:    DMLocalToGlobalBeginDefaultShell()/DMLocalToGlobalEndDefaultShell() are used to to perform the transfers

    553:    Level: advanced

    555: .seealso: DMShellSetGlobalToLocal()
    556: @*/
    557: PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    558: {
    561:   dm->ops->localtoglobalbegin = begin;
    562:   dm->ops->localtoglobalend = end;
    563:   return(0);
    564: }

    566: /*@C
    567:    DMShellSetLocalToLocal - Sets the routines used to perform a local to local scatter

    569:    Logically Collective on dm

    571:    Input Parameters
    572: +  dm - the shell DM
    573: .  begin - the routine that begins the local to local scatter
    574: -  end - the routine that ends the local to local scatter

    576:    Notes:
    577:     If these functions are not provided but DMShellSetLocalToLocalVecScatter() is called then
    578:    DMLocalToLocalBeginDefaultShell()/DMLocalToLocalEndDefaultShell() are used to to perform the transfers

    580:    Level: advanced

    582: .seealso: DMShellSetGlobalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
    583: @*/
    584: PetscErrorCode DMShellSetLocalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    585: {
    588:   dm->ops->localtolocalbegin = begin;
    589:   dm->ops->localtolocalend = end;
    590:   return(0);
    591: }

    593: /*@
    594:    DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication

    596:    Logically Collective on dm

    598:    Input Parameters
    599: +  dm - the shell DM
    600: -  gtol - the global to local VecScatter context

    602:    Level: advanced

    604: .seealso: DMShellSetGlobalToLocal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
    605: @*/
    606: PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
    607: {
    608:   DM_Shell       *shell = (DM_Shell*)dm->data;

    614:   PetscObjectReference((PetscObject)gtol);
    615:   VecScatterDestroy(&shell->gtol);
    616:   shell->gtol = gtol;
    617:   return(0);
    618: }

    620: /*@
    621:    DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication

    623:    Logically Collective on dm

    625:    Input Parameters
    626: +  dm - the shell DM
    627: -  ltog - the local to global VecScatter context

    629:    Level: advanced

    631: .seealso: DMShellSetLocalToGlobal(), DMLocalToGlobalBeginDefaultShell(), DMLocalToGlobalEndDefaultShell()
    632: @*/
    633: PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
    634: {
    635:   DM_Shell       *shell = (DM_Shell*)dm->data;

    641:   PetscObjectReference((PetscObject)ltog);
    642:   VecScatterDestroy(&shell->ltog);
    643:   shell->ltog = ltog;
    644:   return(0);
    645: }

    647: /*@
    648:    DMShellSetLocalToLocalVecScatter - Sets a VecScatter context for local to local communication

    650:    Logically Collective on dm

    652:    Input Parameters
    653: +  dm - the shell DM
    654: -  ltol - the local to local VecScatter context

    656:    Level: advanced

    658: .seealso: DMShellSetLocalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
    659: @*/
    660: PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
    661: {
    662:   DM_Shell       *shell = (DM_Shell*)dm->data;

    668:   PetscObjectReference((PetscObject)ltol);
    669:   VecScatterDestroy(&shell->ltol);
    670:   shell->ltol = ltol;
    671:   return(0);
    672: }

    674: /*@C
    675:    DMShellSetCoarsen - Set the routine used to coarsen the shell DM

    677:    Logically Collective on dm

    679:    Input Parameters
    680: +  dm - the shell DM
    681: -  coarsen - the routine that coarsens the DM

    683:    Level: advanced

    685: .seealso: DMShellSetRefine(), DMCoarsen(), DMShellGetCoarsen(), DMShellSetContext(), DMShellGetContext()
    686: @*/
    687: PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM,MPI_Comm,DM*))
    688: {
    690:   PetscBool      isshell;

    694:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    695:   if (!isshell) return(0);
    696:   dm->ops->coarsen = coarsen;
    697:   return(0);
    698: }

    700: /*@C
    701:    DMShellGetCoarsen - Get the routine used to coarsen the shell DM

    703:    Logically Collective on dm

    705:    Input Parameter:
    706: .  dm - the shell DM

    708:    Output Parameter:
    709: .  coarsen - the routine that coarsens the DM

    711:    Level: advanced

    713: .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
    714: @*/
    715: PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM,MPI_Comm,DM*))
    716: {
    718:   PetscBool      isshell;

    722:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    723:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    724:   *coarsen = dm->ops->coarsen;
    725:   return(0);
    726: }

    728: /*@C
    729:    DMShellSetRefine - Set the routine used to refine the shell DM

    731:    Logically Collective on dm

    733:    Input Parameters
    734: +  dm - the shell DM
    735: -  refine - the routine that refines the DM

    737:    Level: advanced

    739: .seealso: DMShellSetCoarsen(), DMRefine(), DMShellGetRefine(), DMShellSetContext(), DMShellGetContext()
    740: @*/
    741: PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM,MPI_Comm,DM*))
    742: {
    744:   PetscBool      isshell;

    748:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    749:   if (!isshell) return(0);
    750:   dm->ops->refine = refine;
    751:   return(0);
    752: }

    754: /*@C
    755:    DMShellGetRefine - Get the routine used to refine the shell DM

    757:    Logically Collective on dm

    759:    Input Parameter:
    760: .  dm - the shell DM

    762:    Output Parameter:
    763: .  refine - the routine that refines the DM

    765:    Level: advanced

    767: .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
    768: @*/
    769: PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM,MPI_Comm,DM*))
    770: {
    772:   PetscBool      isshell;

    776:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    777:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    778:   *refine = dm->ops->refine;
    779:   return(0);
    780: }

    782: /*@C
    783:    DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator

    785:    Logically Collective on dm

    787:    Input Parameters
    788: +  dm - the shell DM
    789: -  interp - the routine to create the interpolation

    791:    Level: advanced

    793: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateInterpolation(), DMShellSetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    794: @*/
    795: PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM,DM,Mat*,Vec*))
    796: {
    798:   PetscBool      isshell;

    802:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    803:   if (!isshell) return(0);
    804:   dm->ops->createinterpolation = interp;
    805:   return(0);
    806: }

    808: /*@C
    809:    DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator

    811:    Logically Collective on dm

    813:    Input Parameter:
    814: .  dm - the shell DM

    816:    Output Parameter:
    817: .  interp - the routine to create the interpolation

    819:    Level: advanced

    821: .seealso: DMShellGetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    822: @*/
    823: PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM,DM,Mat*,Vec*))
    824: {
    826:   PetscBool      isshell;

    830:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    831:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    832:   *interp = dm->ops->createinterpolation;
    833:   return(0);
    834: }

    836: /*@C
    837:    DMShellSetCreateRestriction - Set the routine used to create the restriction operator

    839:    Logically Collective on dm

    841:    Input Parameters
    842: +  dm - the shell DM
    843: -  striction- the routine to create the restriction

    845:    Level: advanced

    847: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    848: @*/
    849: PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM,DM,Mat*))
    850: {
    852:   PetscBool      isshell;

    856:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    857:   if (!isshell) return(0);
    858:   dm->ops->createrestriction = restriction;
    859:   return(0);
    860: }

    862: /*@C
    863:    DMShellGetCreateRestriction - Get the routine used to create the restriction operator

    865:    Logically Collective on dm

    867:    Input Parameter:
    868: .  dm - the shell DM

    870:    Output Parameter:
    871: .  restriction - the routine to create the restriction

    873:    Level: advanced

    875: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellSetContext(), DMShellGetContext()
    876: @*/
    877: PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM,DM,Mat*))
    878: {
    880:   PetscBool      isshell;

    884:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    885:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    886:   *restriction = dm->ops->createrestriction;
    887:   return(0);
    888: }

    890: /*@C
    891:    DMShellSetCreateInjection - Set the routine used to create the injection operator

    893:    Logically Collective on dm

    895:    Input Parameters:
    896: +  dm - the shell DM
    897: -  inject - the routine to create the injection

    899:    Level: advanced

    901: .seealso: DMShellSetCreateInterpolation(), DMCreateInjection(), DMShellGetCreateInjection(), DMShellSetContext(), DMShellGetContext()
    902: @*/
    903: PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM,DM,Mat*))
    904: {
    906:   PetscBool      isshell;

    910:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    911:   if (!isshell) return(0);
    912:   dm->ops->createinjection = inject;
    913:   return(0);
    914: }

    916: /*@C
    917:    DMShellGetCreateInjection - Get the routine used to create the injection operator

    919:    Logically Collective on dm

    921:    Input Parameter:
    922: .  dm - the shell DM

    924:    Output Parameter:
    925: .  inject - the routine to create the injection

    927:    Level: advanced

    929: .seealso: DMShellGetCreateInterpolation(), DMCreateInjection(), DMShellSetContext(), DMShellGetContext()
    930: @*/
    931: PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM,DM,Mat*))
    932: {
    934:   PetscBool      isshell;

    938:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    939:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    940:   *inject = dm->ops->createinjection;
    941:   return(0);
    942: }

    944: /*@C
    945:    DMShellSetCreateFieldDecomposition - Set the routine used to create a decomposition of fields for the shell DM

    947:    Logically Collective on dm

    949:    Input Parameters:
    950: +  dm - the shell DM
    951: -  decomp - the routine to create the decomposition

    953:    Level: advanced

    955: .seealso: DMCreateFieldDecomposition(), DMShellSetContext(), DMShellGetContext()
    956: @*/
    957: PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,DM**))
    958: {
    960:   PetscBool      isshell;

    964:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    965:   if (!isshell) return(0);
    966:   dm->ops->createfielddecomposition = decomp;
    967:   return(0);
    968: }

    970: /*@C
    971:    DMShellSetCreateDomainDecomposition - Set the routine used to create a domain decomposition for the shell DM

    973:    Logically Collective on dm

    975:    Input Parameters:
    976: +  dm - the shell DM
    977: -  decomp - the routine to create the decomposition

    979:    Level: advanced

    981: .seealso: DMCreateDomainDecomposition(), DMShellSetContext(), DMShellGetContext()
    982: @*/
    983: PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,IS**,DM**))
    984: {
    986:   PetscBool      isshell;

    990:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    991:   if (!isshell) return(0);
    992:   dm->ops->createdomaindecomposition = decomp;
    993:   return(0);
    994: }

    996: /*@C
    997:    DMShellSetCreateDomainDecompositionScatters - Set the routine used to create the scatter contexts for domain decomposition with a shell DM

    999:    Logically Collective on dm

    1001:    Input Parameters:
    1002: +  dm - the shell DM
    1003: -  scatter - the routine to create the scatters

    1005:    Level: advanced

    1007: .seealso: DMCreateDomainDecompositionScatters(), DMShellSetContext(), DMShellGetContext()
    1008: @*/
    1009: PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM,PetscInt,DM*,VecScatter**,VecScatter**,VecScatter**))
    1010: {
    1012:   PetscBool      isshell;

    1016:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    1017:   if (!isshell) return(0);
    1018:   dm->ops->createddscatters = scatter;
    1019:   return(0);
    1020: }

    1022: /*@C
    1023:    DMShellSetCreateSubDM - Set the routine used to create a sub DM from the shell DM

    1025:    Logically Collective on dm

    1027:    Input Parameters:
    1028: +  dm - the shell DM
    1029: -  subdm - the routine to create the decomposition

    1031:    Level: advanced

    1033: .seealso: DMCreateSubDM(), DMShellGetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
    1034: @*/
    1035: PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
    1036: {
    1038:   PetscBool      isshell;

    1042:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    1043:   if (!isshell) return(0);
    1044:   dm->ops->createsubdm = subdm;
    1045:   return(0);
    1046: }

    1048: /*@C
    1049:    DMShellGetCreateSubDM - Get the routine used to create a sub DM from the shell DM

    1051:    Logically Collective on dm

    1053:    Input Parameter:
    1054: .  dm - the shell DM

    1056:    Output Parameter:
    1057: .  subdm - the routine to create the decomposition

    1059:    Level: advanced

    1061: .seealso: DMCreateSubDM(), DMShellSetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
    1062: @*/
    1063: PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
    1064: {
    1066:   PetscBool      isshell;

    1070:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    1071:   if (!isshell) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Can only use with DMSHELL type DMs");
    1072:   *subdm = dm->ops->createsubdm;
    1073:   return(0);
    1074: }

    1076: static PetscErrorCode DMDestroy_Shell(DM dm)
    1077: {
    1079:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1082:   MatDestroy(&shell->A);
    1083:   VecDestroy(&shell->Xglobal);
    1084:   VecDestroy(&shell->Xlocal);
    1085:   VecScatterDestroy(&shell->gtol);
    1086:   VecScatterDestroy(&shell->ltog);
    1087:   VecScatterDestroy(&shell->ltol);
    1088:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
    1089:   PetscFree(shell);
    1090:   return(0);
    1091: }

    1093: static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
    1094: {
    1096:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1099:   VecView(shell->Xglobal,v);
    1100:   return(0);
    1101: }

    1103: static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
    1104: {
    1106:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1109:   VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);
    1110:   VecLoad(shell->Xglobal,v);
    1111:   return(0);
    1112: }

    1114: PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1115: {

    1119:   if (subdm) {DMShellCreate(PetscObjectComm((PetscObject) dm), subdm);}
    1120:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
    1121:   return(0);
    1122: }

    1124: PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
    1125: {
    1127:   DM_Shell       *shell;

    1130:   PetscNewLog(dm,&shell);
    1131:   dm->data = shell;

    1133:   dm->ops->destroy            = DMDestroy_Shell;
    1134:   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
    1135:   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
    1136:   dm->ops->creatematrix       = DMCreateMatrix_Shell;
    1137:   dm->ops->view               = DMView_Shell;
    1138:   dm->ops->load               = DMLoad_Shell;
    1139:   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
    1140:   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
    1141:   dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell;
    1142:   dm->ops->localtoglobalend   = DMLocalToGlobalEndDefaultShell;
    1143:   dm->ops->localtolocalbegin  = DMLocalToLocalBeginDefaultShell;
    1144:   dm->ops->localtolocalend    = DMLocalToLocalEndDefaultShell;
    1145:   dm->ops->createsubdm        = DMCreateSubDM_Shell;
    1146:   DMSetMatType(dm,MATDENSE);
    1147:   return(0);
    1148: }

    1150: /*@
    1151:     DMShellCreate - Creates a shell DM object, used to manage user-defined problem data

    1153:     Collective

    1155:     Input Parameter:
    1156: .   comm - the processors that will share the global vector

    1158:     Output Parameters:
    1159: .   shell - the shell DM

    1161:     Level: advanced

    1163: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector(), DMShellSetContext(), DMShellGetContext()
    1164: @*/
    1165: PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
    1166: {

    1171:   DMCreate(comm,dm);
    1172:   DMSetType(*dm,DMSHELL);
    1173:   DMSetUp(*dm);
    1174:   return(0);
    1175: }