Date: 2022-03-31T04:47:36+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: {
     33:   DM_Shell       *shell = (DM_Shell*)dm->data;

     36:   VecScatterBegin(shell->gtol,g,l,mode,SCATTER_FORWARD);
     37:   return 0;
     38: }

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

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

     50:    Level: advanced

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

     59:   VecScatterEnd(shell->gtol,g,l,mode,SCATTER_FORWARD);
     60:   return 0;
     61: }

     63: /*@
     64:    DMLocalToGlobalBeginDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to begin a local to global scatter
     65:    Collective

     67:    Input Parameters:
     68: +  dm - shell DM
     69: .  l - local vector
     70: .  mode - InsertMode
     71: -  g - global vector

     73:    Level: advanced

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

     77: .seealso: DMLocalToGlobalEndDefaultShell()
     78: @*/
     79: PetscErrorCode DMLocalToGlobalBeginDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
     80: {
     81:   DM_Shell       *shell = (DM_Shell*)dm->data;

     84:   VecScatterBegin(shell->ltog,l,g,mode,SCATTER_FORWARD);
     85:   return 0;
     86: }

     88: /*@
     89:    DMLocalToGlobalEndDefaultShell - Uses the LocalToGlobal VecScatter context set by the user to end a local to global scatter
     90:    Collective

     92:    Input Parameters:
     93: +  dm - shell DM
     94: .  l - local vector
     95: .  mode - InsertMode
     96: -  g - global vector

     98:    Level: advanced

    100: .seealso: DMLocalToGlobalBeginDefaultShell()
    101: @*/
    102: PetscErrorCode DMLocalToGlobalEndDefaultShell(DM dm,Vec l,InsertMode mode,Vec g)
    103: {
    104:   DM_Shell       *shell = (DM_Shell*)dm->data;

    107:   VecScatterEnd(shell->ltog,l,g,mode,SCATTER_FORWARD);
    108:   return 0;
    109: }

    111: /*@
    112:    DMLocalToLocalBeginDefaultShell - Uses the LocalToLocal VecScatter context set by the user to begin a local to local scatter
    113:    Collective

    115:    Input Parameters:
    116: +  dm - shell DM
    117: .  g - the original local vector
    118: -  mode - InsertMode

    120:    Output Parameter:
    121: .  l  - the local vector with correct ghost values

    123:    Level: advanced

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

    127: .seealso: DMLocalToLocalEndDefaultShell()
    128: @*/
    129: PetscErrorCode DMLocalToLocalBeginDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
    130: {
    131:   DM_Shell       *shell = (DM_Shell*)dm->data;

    134:   VecScatterBegin(shell->ltol,g,l,mode,SCATTER_FORWARD);
    135:   return 0;
    136: }

    138: /*@
    139:    DMLocalToLocalEndDefaultShell - Uses the LocalToLocal VecScatter context set by the user to end a local to local scatter
    140:    Collective

    142:    Input Parameters:
    143: +  dm - shell DM
    144: .  g - the original local vector
    145: -  mode - InsertMode

    147:    Output Parameter:
    148: .  l  - the local vector with correct ghost values

    150:    Level: advanced

    152: .seealso: DMLocalToLocalBeginDefaultShell()
    153: @*/
    154: PetscErrorCode DMLocalToLocalEndDefaultShell(DM dm,Vec g,InsertMode mode,Vec l)
    155: {
    156:   DM_Shell       *shell = (DM_Shell*)dm->data;

    159:   VecScatterEnd(shell->ltol,g,l,mode,SCATTER_FORWARD);
    160:   return 0;
    161: }

    163: static PetscErrorCode DMCreateMatrix_Shell(DM dm,Mat *J)
    164: {
    165:   DM_Shell       *shell = (DM_Shell*)dm->data;
    166:   Mat            A;

    170:   if (!shell->A) {
    171:     if (shell->Xglobal) {
    172:       PetscInt m,M;
    173:       PetscInfo(dm,"Naively creating matrix using global vector distribution without preallocation\n");
    174:       VecGetSize(shell->Xglobal,&M);
    175:       VecGetLocalSize(shell->Xglobal,&m);
    176:       MatCreate(PetscObjectComm((PetscObject)dm),&shell->A);
    177:       MatSetSizes(shell->A,m,m,M,M);
    178:       MatSetType(shell->A,dm->mattype);
    179:       MatSetUp(shell->A);
    180:     } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Must call DMShellSetMatrix(), DMShellSetCreateMatrix(), or provide a vector");
    181:   }
    182:   A = shell->A;
    183:   MatDuplicate(A,MAT_SHARE_NONZERO_PATTERN,J);
    184:   MatSetDM(*J,dm);
    185:   return 0;
    186: }

    188: PetscErrorCode DMCreateGlobalVector_Shell(DM dm,Vec *gvec)
    189: {
    190:   DM_Shell       *shell = (DM_Shell*)dm->data;
    191:   Vec            X;

    195:   *gvec = NULL;
    196:   X     = shell->Xglobal;
    198:   /* Need to create a copy in order to attach the DM to the vector */
    199:   VecDuplicate(X,gvec);
    200:   VecZeroEntries(*gvec);
    201:   VecSetDM(*gvec,dm);
    202:   return 0;
    203: }

    205: PetscErrorCode DMCreateLocalVector_Shell(DM dm,Vec *gvec)
    206: {
    207:   DM_Shell       *shell = (DM_Shell*)dm->data;
    208:   Vec            X;

    212:   *gvec = NULL;
    213:   X     = shell->Xlocal;
    215:   /* Need to create a copy in order to attach the DM to the vector */
    216:   VecDuplicate(X,gvec);
    217:   VecZeroEntries(*gvec);
    218:   VecSetDM(*gvec,dm);
    219:   return 0;
    220: }

    222: /*@
    223:    DMShellSetContext - set some data to be usable by this DM

    225:    Collective

    227:    Input Parameters:
    228: +  dm - shell DM
    229: -  ctx - the context

    231:    Level: advanced

    233: .seealso: DMCreateMatrix(), DMShellGetContext()
    234: @*/
    235: PetscErrorCode DMShellSetContext(DM dm,void *ctx)
    236: {
    237:   DM_Shell       *shell = (DM_Shell*)dm->data;
    238:   PetscBool      isshell;

    241:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    242:   if (!isshell) return 0;
    243:   shell->ctx = ctx;
    244:   return 0;
    245: }

    247: /*@
    248:    DMShellGetContext - Returns the user-provided context associated to the DM

    250:    Collective

    252:    Input Parameter:
    253: .  dm - shell DM

    255:    Output Parameter:
    256: .  ctx - the context

    258:    Level: advanced

    260: .seealso: DMCreateMatrix(), DMShellSetContext()
    261: @*/
    262: PetscErrorCode DMShellGetContext(DM dm,void *ctx)
    263: {
    264:   DM_Shell       *shell = (DM_Shell*)dm->data;
    265:   PetscBool      isshell;

    268:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    270:   *(void**)ctx = shell->ctx;
    271:   return 0;
    272: }

    274: /*@
    275:    DMShellSetMatrix - sets a template matrix associated with the DMShell

    277:    Collective

    279:    Input Parameters:
    280: +  dm - shell DM
    281: -  J - template matrix

    283:    Level: advanced

    285:    Developer Notes:
    286:     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.

    288: .seealso: DMCreateMatrix(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    289: @*/
    290: PetscErrorCode DMShellSetMatrix(DM dm,Mat J)
    291: {
    292:   DM_Shell       *shell = (DM_Shell*)dm->data;
    293:   PetscBool      isshell;
    294:   DM             mdm;

    298:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    299:   if (!isshell) return 0;
    300:   if (J == shell->A) return 0;
    301:   MatGetDM(J,&mdm);
    302:   PetscObjectReference((PetscObject)J);
    303:   MatDestroy(&shell->A);
    304:   if (mdm == dm) {
    305:     MatDuplicate(J,MAT_SHARE_NONZERO_PATTERN,&shell->A);
    306:     MatSetDM(shell->A,NULL);
    307:   } else shell->A = J;
    308:   return 0;
    309: }

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

    314:    Logically Collective on dm

    316:    Input Parameters:
    317: +  dm - the shell DM
    318: -  func - the function to create a matrix

    320:    Level: advanced

    322: .seealso: DMCreateMatrix(), DMShellSetMatrix(), DMShellSetContext(), DMShellGetContext()
    323: @*/
    324: PetscErrorCode DMShellSetCreateMatrix(DM dm,PetscErrorCode (*func)(DM,Mat*))
    325: {
    327:   dm->ops->creatematrix = func;
    328:   return 0;
    329: }

    331: /*@
    332:    DMShellSetGlobalVector - sets a template global vector associated with the DMShell

    334:    Logically Collective on dm

    336:    Input Parameters:
    337: +  dm - shell DM
    338: -  X - template vector

    340:    Level: advanced

    342: .seealso: DMCreateGlobalVector(), DMShellSetMatrix(), DMShellSetCreateGlobalVector()
    343: @*/
    344: PetscErrorCode DMShellSetGlobalVector(DM dm,Vec X)
    345: {
    346:   DM_Shell       *shell = (DM_Shell*)dm->data;
    347:   PetscBool      isshell;
    348:   DM             vdm;

    352:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    353:   if (!isshell) return 0;
    354:   VecGetDM(X,&vdm);
    355:   /*
    356:       if the vector proposed as the new base global vector for the DM is a DM vector associated
    357:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
    358:       we get a circular dependency that prevents the DM from being destroy when it should be.
    359:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
    360:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
    361:       to set its input vector (which is associated with the DM) as the base global vector.
    362:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
    363:       for pointing out the problem.
    364:    */
    365:   if (vdm == dm) return 0;
    366:   PetscObjectReference((PetscObject)X);
    367:   VecDestroy(&shell->Xglobal);
    368:   shell->Xglobal = X;
    369:   return 0;
    370: }

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

    375:    Not collective

    377:    Input Parameters:
    378: +  dm - shell DM
    379: -  X - template vector

    381:    Level: advanced

    383: .seealso: DMShellSetGlobalVector(), DMShellSetCreateGlobalVector(), DMCreateGlobalVector()
    384: @*/
    385: PetscErrorCode DMShellGetGlobalVector(DM dm, Vec *X)
    386: {
    387:   DM_Shell      *shell = (DM_Shell *) dm->data;
    388:   PetscBool      isshell;

    392:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    393:   if (!isshell) return 0;
    394:   *X = shell->Xglobal;
    395:   return 0;
    396: }

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

    401:    Logically Collective

    403:    Input Parameters:
    404: +  dm - the shell DM
    405: -  func - the creation routine

    407:    Level: advanced

    409: .seealso: DMShellSetGlobalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    410: @*/
    411: PetscErrorCode DMShellSetCreateGlobalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
    412: {
    414:   dm->ops->createglobalvector = func;
    415:   return 0;
    416: }

    418: /*@
    419:    DMShellSetLocalVector - sets a template local vector associated with the DMShell

    421:    Logically Collective on dm

    423:    Input Parameters:
    424: +  dm - shell DM
    425: -  X - template vector

    427:    Level: advanced

    429: .seealso: DMCreateLocalVector(), DMShellSetMatrix(), DMShellSetCreateLocalVector()
    430: @*/
    431: PetscErrorCode DMShellSetLocalVector(DM dm,Vec X)
    432: {
    433:   DM_Shell       *shell = (DM_Shell*)dm->data;
    434:   PetscBool      isshell;
    435:   DM             vdm;

    439:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    440:   if (!isshell) return 0;
    441:   VecGetDM(X,&vdm);
    442:   /*
    443:       if the vector proposed as the new base global vector for the DM is a DM vector associated
    444:       with the same DM then the current base global vector for the DM is ok and if we replace it with the new one
    445:       we get a circular dependency that prevents the DM from being destroy when it should be.
    446:       This occurs when SNESSet/GetNPC() is used with a SNES that does not have a user provided
    447:       DM attached to it since the inner SNES (which shares the DM with the outer SNES) tries
    448:       to set its input vector (which is associated with the DM) as the base global vector.
    449:       Thanks to Juan P. Mendez Granado Re: [petsc-maint] Nonlinear conjugate gradien
    450:       for pointing out the problem.
    451:    */
    452:   if (vdm == dm) return 0;
    453:   PetscObjectReference((PetscObject)X);
    454:   VecDestroy(&shell->Xlocal);
    455:   shell->Xlocal = X;
    456:   return 0;
    457: }

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

    462:    Logically Collective

    464:    Input Parameters:
    465: +  dm - the shell DM
    466: -  func - the creation routine

    468:    Level: advanced

    470: .seealso: DMShellSetLocalVector(), DMShellSetCreateMatrix(), DMShellSetContext(), DMShellGetContext()
    471: @*/
    472: PetscErrorCode DMShellSetCreateLocalVector(DM dm,PetscErrorCode (*func)(DM,Vec*))
    473: {
    475:   dm->ops->createlocalvector = func;
    476:   return 0;
    477: }

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

    482:    Logically Collective on dm

    484:    Input Parameters
    485: +  dm - the shell DM
    486: .  begin - the routine that begins the global to local scatter
    487: -  end - the routine that ends the global to local scatter

    489:    Notes:
    490:     If these functions are not provided but DMShellSetGlobalToLocalVecScatter() is called then
    491:    DMGlobalToLocalBeginDefaultShell()/DMGlobalToLocalEndDefaultShell() are used to to perform the transfers

    493:    Level: advanced

    495: .seealso: DMShellSetLocalToGlobal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
    496: @*/
    497: PetscErrorCode DMShellSetGlobalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    498: {
    500:   dm->ops->globaltolocalbegin = begin;
    501:   dm->ops->globaltolocalend = end;
    502:   return 0;
    503: }

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

    508:    Logically Collective on dm

    510:    Input Parameters
    511: +  dm - the shell DM
    512: .  begin - the routine that begins the local to global scatter
    513: -  end - the routine that ends the local to global scatter

    515:    Notes:
    516:     If these functions are not provided but DMShellSetLocalToGlobalVecScatter() is called then
    517:    DMLocalToGlobalBeginDefaultShell()/DMLocalToGlobalEndDefaultShell() are used to to perform the transfers

    519:    Level: advanced

    521: .seealso: DMShellSetGlobalToLocal()
    522: @*/
    523: PetscErrorCode DMShellSetLocalToGlobal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    524: {
    526:   dm->ops->localtoglobalbegin = begin;
    527:   dm->ops->localtoglobalend = end;
    528:   return 0;
    529: }

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

    534:    Logically Collective on dm

    536:    Input Parameters
    537: +  dm - the shell DM
    538: .  begin - the routine that begins the local to local scatter
    539: -  end - the routine that ends the local to local scatter

    541:    Notes:
    542:     If these functions are not provided but DMShellSetLocalToLocalVecScatter() is called then
    543:    DMLocalToLocalBeginDefaultShell()/DMLocalToLocalEndDefaultShell() are used to to perform the transfers

    545:    Level: advanced

    547: .seealso: DMShellSetGlobalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
    548: @*/
    549: PetscErrorCode DMShellSetLocalToLocal(DM dm,PetscErrorCode (*begin)(DM,Vec,InsertMode,Vec),PetscErrorCode (*end)(DM,Vec,InsertMode,Vec))
    550: {
    552:   dm->ops->localtolocalbegin = begin;
    553:   dm->ops->localtolocalend = end;
    554:   return 0;
    555: }

    557: /*@
    558:    DMShellSetGlobalToLocalVecScatter - Sets a VecScatter context for global to local communication

    560:    Logically Collective on dm

    562:    Input Parameters
    563: +  dm - the shell DM
    564: -  gtol - the global to local VecScatter context

    566:    Level: advanced

    568: .seealso: DMShellSetGlobalToLocal(), DMGlobalToLocalBeginDefaultShell(), DMGlobalToLocalEndDefaultShell()
    569: @*/
    570: PetscErrorCode DMShellSetGlobalToLocalVecScatter(DM dm, VecScatter gtol)
    571: {
    572:   DM_Shell       *shell = (DM_Shell*)dm->data;

    576:   PetscObjectReference((PetscObject)gtol);
    577:   VecScatterDestroy(&shell->gtol);
    578:   shell->gtol = gtol;
    579:   return 0;
    580: }

    582: /*@
    583:    DMShellSetLocalToGlobalVecScatter - Sets a VecScatter context for local to global communication

    585:    Logically Collective on dm

    587:    Input Parameters
    588: +  dm - the shell DM
    589: -  ltog - the local to global VecScatter context

    591:    Level: advanced

    593: .seealso: DMShellSetLocalToGlobal(), DMLocalToGlobalBeginDefaultShell(), DMLocalToGlobalEndDefaultShell()
    594: @*/
    595: PetscErrorCode DMShellSetLocalToGlobalVecScatter(DM dm, VecScatter ltog)
    596: {
    597:   DM_Shell       *shell = (DM_Shell*)dm->data;

    601:   PetscObjectReference((PetscObject)ltog);
    602:   VecScatterDestroy(&shell->ltog);
    603:   shell->ltog = ltog;
    604:   return 0;
    605: }

    607: /*@
    608:    DMShellSetLocalToLocalVecScatter - Sets a VecScatter context for local to local communication

    610:    Logically Collective on dm

    612:    Input Parameters
    613: +  dm - the shell DM
    614: -  ltol - the local to local VecScatter context

    616:    Level: advanced

    618: .seealso: DMShellSetLocalToLocal(), DMLocalToLocalBeginDefaultShell(), DMLocalToLocalEndDefaultShell()
    619: @*/
    620: PetscErrorCode DMShellSetLocalToLocalVecScatter(DM dm, VecScatter ltol)
    621: {
    622:   DM_Shell       *shell = (DM_Shell*)dm->data;

    626:   PetscObjectReference((PetscObject)ltol);
    627:   VecScatterDestroy(&shell->ltol);
    628:   shell->ltol = ltol;
    629:   return 0;
    630: }

    632: /*@C
    633:    DMShellSetCoarsen - Set the routine used to coarsen the shell DM

    635:    Logically Collective on dm

    637:    Input Parameters
    638: +  dm - the shell DM
    639: -  coarsen - the routine that coarsens the DM

    641:    Level: advanced

    643: .seealso: DMShellSetRefine(), DMCoarsen(), DMShellGetCoarsen(), DMShellSetContext(), DMShellGetContext()
    644: @*/
    645: PetscErrorCode DMShellSetCoarsen(DM dm, PetscErrorCode (*coarsen)(DM,MPI_Comm,DM*))
    646: {
    647:   PetscBool      isshell;

    650:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    651:   if (!isshell) return 0;
    652:   dm->ops->coarsen = coarsen;
    653:   return 0;
    654: }

    656: /*@C
    657:    DMShellGetCoarsen - Get the routine used to coarsen the shell DM

    659:    Logically Collective on dm

    661:    Input Parameter:
    662: .  dm - the shell DM

    664:    Output Parameter:
    665: .  coarsen - the routine that coarsens the DM

    667:    Level: advanced

    669: .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
    670: @*/
    671: PetscErrorCode DMShellGetCoarsen(DM dm, PetscErrorCode (**coarsen)(DM,MPI_Comm,DM*))
    672: {
    673:   PetscBool      isshell;

    676:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    678:   *coarsen = dm->ops->coarsen;
    679:   return 0;
    680: }

    682: /*@C
    683:    DMShellSetRefine - Set the routine used to refine the shell DM

    685:    Logically Collective on dm

    687:    Input Parameters
    688: +  dm - the shell DM
    689: -  refine - the routine that refines the DM

    691:    Level: advanced

    693: .seealso: DMShellSetCoarsen(), DMRefine(), DMShellGetRefine(), DMShellSetContext(), DMShellGetContext()
    694: @*/
    695: PetscErrorCode DMShellSetRefine(DM dm, PetscErrorCode (*refine)(DM,MPI_Comm,DM*))
    696: {
    697:   PetscBool      isshell;

    700:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    701:   if (!isshell) return 0;
    702:   dm->ops->refine = refine;
    703:   return 0;
    704: }

    706: /*@C
    707:    DMShellGetRefine - Get the routine used to refine the shell DM

    709:    Logically Collective on dm

    711:    Input Parameter:
    712: .  dm - the shell DM

    714:    Output Parameter:
    715: .  refine - the routine that refines the DM

    717:    Level: advanced

    719: .seealso: DMShellSetCoarsen(), DMCoarsen(), DMShellSetRefine(), DMRefine()
    720: @*/
    721: PetscErrorCode DMShellGetRefine(DM dm, PetscErrorCode (**refine)(DM,MPI_Comm,DM*))
    722: {
    723:   PetscBool      isshell;

    726:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    728:   *refine = dm->ops->refine;
    729:   return 0;
    730: }

    732: /*@C
    733:    DMShellSetCreateInterpolation - Set the routine used to create the interpolation operator

    735:    Logically Collective on dm

    737:    Input Parameters
    738: +  dm - the shell DM
    739: -  interp - the routine to create the interpolation

    741:    Level: advanced

    743: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateInterpolation(), DMShellSetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    744: @*/
    745: PetscErrorCode DMShellSetCreateInterpolation(DM dm, PetscErrorCode (*interp)(DM,DM,Mat*,Vec*))
    746: {
    747:   PetscBool      isshell;

    750:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    751:   if (!isshell) return 0;
    752:   dm->ops->createinterpolation = interp;
    753:   return 0;
    754: }

    756: /*@C
    757:    DMShellGetCreateInterpolation - Get the routine used to create the interpolation operator

    759:    Logically Collective on dm

    761:    Input Parameter:
    762: .  dm - the shell DM

    764:    Output Parameter:
    765: .  interp - the routine to create the interpolation

    767:    Level: advanced

    769: .seealso: DMShellGetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    770: @*/
    771: PetscErrorCode DMShellGetCreateInterpolation(DM dm, PetscErrorCode (**interp)(DM,DM,Mat*,Vec*))
    772: {
    773:   PetscBool      isshell;

    776:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    778:   *interp = dm->ops->createinterpolation;
    779:   return 0;
    780: }

    782: /*@C
    783:    DMShellSetCreateRestriction - Set the routine used to create the restriction operator

    785:    Logically Collective on dm

    787:    Input Parameters
    788: +  dm - the shell DM
    789: -  striction- the routine to create the restriction

    791:    Level: advanced

    793: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellGetCreateRestriction(), DMShellSetContext(), DMShellGetContext()
    794: @*/
    795: PetscErrorCode DMShellSetCreateRestriction(DM dm, PetscErrorCode (*restriction)(DM,DM,Mat*))
    796: {
    797:   PetscBool      isshell;

    800:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    801:   if (!isshell) return 0;
    802:   dm->ops->createrestriction = restriction;
    803:   return 0;
    804: }

    806: /*@C
    807:    DMShellGetCreateRestriction - Get the routine used to create the restriction operator

    809:    Logically Collective on dm

    811:    Input Parameter:
    812: .  dm - the shell DM

    814:    Output Parameter:
    815: .  restriction - the routine to create the restriction

    817:    Level: advanced

    819: .seealso: DMShellSetCreateInjection(), DMCreateInterpolation(), DMShellSetContext(), DMShellGetContext()
    820: @*/
    821: PetscErrorCode DMShellGetCreateRestriction(DM dm, PetscErrorCode (**restriction)(DM,DM,Mat*))
    822: {
    823:   PetscBool      isshell;

    826:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    828:   *restriction = dm->ops->createrestriction;
    829:   return 0;
    830: }

    832: /*@C
    833:    DMShellSetCreateInjection - Set the routine used to create the injection operator

    835:    Logically Collective on dm

    837:    Input Parameters:
    838: +  dm - the shell DM
    839: -  inject - the routine to create the injection

    841:    Level: advanced

    843: .seealso: DMShellSetCreateInterpolation(), DMCreateInjection(), DMShellGetCreateInjection(), DMShellSetContext(), DMShellGetContext()
    844: @*/
    845: PetscErrorCode DMShellSetCreateInjection(DM dm, PetscErrorCode (*inject)(DM,DM,Mat*))
    846: {
    847:   PetscBool      isshell;

    850:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    851:   if (!isshell) return 0;
    852:   dm->ops->createinjection = inject;
    853:   return 0;
    854: }

    856: /*@C
    857:    DMShellGetCreateInjection - Get the routine used to create the injection operator

    859:    Logically Collective on dm

    861:    Input Parameter:
    862: .  dm - the shell DM

    864:    Output Parameter:
    865: .  inject - the routine to create the injection

    867:    Level: advanced

    869: .seealso: DMShellGetCreateInterpolation(), DMCreateInjection(), DMShellSetContext(), DMShellGetContext()
    870: @*/
    871: PetscErrorCode DMShellGetCreateInjection(DM dm, PetscErrorCode (**inject)(DM,DM,Mat*))
    872: {
    873:   PetscBool      isshell;

    876:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    878:   *inject = dm->ops->createinjection;
    879:   return 0;
    880: }

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

    885:    Logically Collective on dm

    887:    Input Parameters:
    888: +  dm - the shell DM
    889: -  decomp - the routine to create the decomposition

    891:    Level: advanced

    893: .seealso: DMCreateFieldDecomposition(), DMShellSetContext(), DMShellGetContext()
    894: @*/
    895: PetscErrorCode DMShellSetCreateFieldDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,DM**))
    896: {
    897:   PetscBool      isshell;

    900:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    901:   if (!isshell) return 0;
    902:   dm->ops->createfielddecomposition = decomp;
    903:   return 0;
    904: }

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

    909:    Logically Collective on dm

    911:    Input Parameters:
    912: +  dm - the shell DM
    913: -  decomp - the routine to create the decomposition

    915:    Level: advanced

    917: .seealso: DMCreateDomainDecomposition(), DMShellSetContext(), DMShellGetContext()
    918: @*/
    919: PetscErrorCode DMShellSetCreateDomainDecomposition(DM dm, PetscErrorCode (*decomp)(DM,PetscInt*,char***, IS**,IS**,DM**))
    920: {
    921:   PetscBool      isshell;

    924:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    925:   if (!isshell) return 0;
    926:   dm->ops->createdomaindecomposition = decomp;
    927:   return 0;
    928: }

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

    933:    Logically Collective on dm

    935:    Input Parameters:
    936: +  dm - the shell DM
    937: -  scatter - the routine to create the scatters

    939:    Level: advanced

    941: .seealso: DMCreateDomainDecompositionScatters(), DMShellSetContext(), DMShellGetContext()
    942: @*/
    943: PetscErrorCode DMShellSetCreateDomainDecompositionScatters(DM dm, PetscErrorCode (*scatter)(DM,PetscInt,DM*,VecScatter**,VecScatter**,VecScatter**))
    944: {
    945:   PetscBool      isshell;

    948:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    949:   if (!isshell) return 0;
    950:   dm->ops->createddscatters = scatter;
    951:   return 0;
    952: }

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

    957:    Logically Collective on dm

    959:    Input Parameters:
    960: +  dm - the shell DM
    961: -  subdm - the routine to create the decomposition

    963:    Level: advanced

    965: .seealso: DMCreateSubDM(), DMShellGetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
    966: @*/
    967: PetscErrorCode DMShellSetCreateSubDM(DM dm, PetscErrorCode (*subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
    968: {
    969:   PetscBool      isshell;

    972:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    973:   if (!isshell) return 0;
    974:   dm->ops->createsubdm = subdm;
    975:   return 0;
    976: }

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

    981:    Logically Collective on dm

    983:    Input Parameter:
    984: .  dm - the shell DM

    986:    Output Parameter:
    987: .  subdm - the routine to create the decomposition

    989:    Level: advanced

    991: .seealso: DMCreateSubDM(), DMShellSetCreateSubDM(), DMShellSetContext(), DMShellGetContext()
    992: @*/
    993: PetscErrorCode DMShellGetCreateSubDM(DM dm, PetscErrorCode (**subdm)(DM,PetscInt,const PetscInt[],IS*,DM*))
    994: {
    995:   PetscBool      isshell;

    998:   PetscObjectTypeCompare((PetscObject)dm,DMSHELL,&isshell);
    1000:   *subdm = dm->ops->createsubdm;
    1001:   return 0;
    1002: }

    1004: static PetscErrorCode DMDestroy_Shell(DM dm)
    1005: {
    1006:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1008:   MatDestroy(&shell->A);
    1009:   VecDestroy(&shell->Xglobal);
    1010:   VecDestroy(&shell->Xlocal);
    1011:   VecScatterDestroy(&shell->gtol);
    1012:   VecScatterDestroy(&shell->ltog);
    1013:   VecScatterDestroy(&shell->ltol);
    1014:   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
    1015:   PetscFree(shell);
    1016:   return 0;
    1017: }

    1019: static PetscErrorCode DMView_Shell(DM dm,PetscViewer v)
    1020: {
    1021:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1023:   VecView(shell->Xglobal,v);
    1024:   return 0;
    1025: }

    1027: static PetscErrorCode DMLoad_Shell(DM dm,PetscViewer v)
    1028: {
    1029:   DM_Shell       *shell = (DM_Shell*)dm->data;

    1031:   VecCreate(PetscObjectComm((PetscObject)dm),&shell->Xglobal);
    1032:   VecLoad(shell->Xglobal,v);
    1033:   return 0;
    1034: }

    1036: PetscErrorCode DMCreateSubDM_Shell(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
    1037: {
    1038:   if (subdm) DMShellCreate(PetscObjectComm((PetscObject) dm), subdm);
    1039:   DMCreateSectionSubDM(dm, numFields, fields, is, subdm);
    1040:   return 0;
    1041: }

    1043: PETSC_EXTERN PetscErrorCode DMCreate_Shell(DM dm)
    1044: {
    1045:   DM_Shell       *shell;

    1047:   PetscNewLog(dm,&shell);
    1048:   dm->data = shell;

    1050:   dm->ops->destroy            = DMDestroy_Shell;
    1051:   dm->ops->createglobalvector = DMCreateGlobalVector_Shell;
    1052:   dm->ops->createlocalvector  = DMCreateLocalVector_Shell;
    1053:   dm->ops->creatematrix       = DMCreateMatrix_Shell;
    1054:   dm->ops->view               = DMView_Shell;
    1055:   dm->ops->load               = DMLoad_Shell;
    1056:   dm->ops->globaltolocalbegin = DMGlobalToLocalBeginDefaultShell;
    1057:   dm->ops->globaltolocalend   = DMGlobalToLocalEndDefaultShell;
    1058:   dm->ops->localtoglobalbegin = DMLocalToGlobalBeginDefaultShell;
    1059:   dm->ops->localtoglobalend   = DMLocalToGlobalEndDefaultShell;
    1060:   dm->ops->localtolocalbegin  = DMLocalToLocalBeginDefaultShell;
    1061:   dm->ops->localtolocalend    = DMLocalToLocalEndDefaultShell;
    1062:   dm->ops->createsubdm        = DMCreateSubDM_Shell;
    1063:   DMSetMatType(dm,MATDENSE);
    1064:   return 0;
    1065: }

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

    1070:     Collective

    1072:     Input Parameter:
    1073: .   comm - the processors that will share the global vector

    1075:     Output Parameters:
    1076: .   shell - the shell DM

    1078:     Level: advanced

    1080: .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateLocalVector(), DMShellSetContext(), DMShellGetContext()
    1081: @*/
    1082: PetscErrorCode  DMShellCreate(MPI_Comm comm,DM *dm)
    1083: {
    1085:   DMCreate(comm,dm);
    1086:   DMSetType(*dm,DMSHELL);
    1087:   DMSetUp(*dm);
    1088:   return 0;
    1089: }