Date: 2022-03-04T17:39:14+00:00

Actual source code: ex65.c

      2: /*
      3:  Partial differential equation

      5:    d   d u = 1, 0 < x < 1,
      6:    --   --
      7:    dx   dx
      8: with boundary conditions

     10:    u = 0 for x = 0, x = 1

     12:    This uses multigrid to solve the linear system

     14:    Demonstrates how to build a DMSHELL for managing multigrid. The DMSHELL simply creates a
     15:    DMDA1d to construct all the needed PETSc objects.

     17: */

     19: static char help[] = "Solves 1D constant coefficient Laplacian using DMSHELL and multigrid.\n\n";

     21: #include <petscdm.h>
     22: #include <petscdmda.h>
     23: #include <petscdmshell.h>
     24: #include <petscksp.h>

     26: static PetscErrorCode ComputeMatrix(KSP,Mat,Mat,void*);
     27: static PetscErrorCode ComputeRHS(KSP,Vec,void*);
     28: static PetscErrorCode CreateMatrix(DM,Mat*);
     29: static PetscErrorCode CreateGlobalVector(DM,Vec*);
     30: static PetscErrorCode CreateLocalVector(DM,Vec*);
     31: static PetscErrorCode Refine(DM,MPI_Comm,DM*);
     32: static PetscErrorCode Coarsen(DM,MPI_Comm,DM*);
     33: static PetscErrorCode CreateInterpolation(DM,DM,Mat*,Vec*);
     34: static PetscErrorCode CreateRestriction(DM,DM,Mat*);

     36: static PetscErrorCode MyDMShellCreate(MPI_Comm comm,DM da,DM *shell)
     37: {

     40:   DMShellCreate(comm,shell);
     41:   DMShellSetContext(*shell,da);
     42:   DMShellSetCreateMatrix(*shell,CreateMatrix);
     43:   DMShellSetCreateGlobalVector(*shell,CreateGlobalVector);
     44:   DMShellSetCreateLocalVector(*shell,CreateLocalVector);
     45:   DMShellSetRefine(*shell,Refine);
     46:   DMShellSetCoarsen(*shell,Coarsen);
     47:   DMShellSetCreateInterpolation(*shell,CreateInterpolation);
     48:   DMShellSetCreateRestriction(*shell,CreateRestriction);
     49:   return 0;
     50: }

     52: int main(int argc,char **argv)
     53: {
     55:   KSP            ksp;
     56:   DM             da,shell;
     57:   PetscInt       levels;

     59:   PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
     60:   KSPCreate(PETSC_COMM_WORLD,&ksp);
     61:   DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,129,1,1,0,&da);
     62:   DMSetFromOptions(da);
     63:   DMSetUp(da);
     64:   MyDMShellCreate(PETSC_COMM_WORLD,da,&shell);
     65:   /* these two lines are not needed but allow PCMG to automatically know how many multigrid levels the user wants */
     66:   DMGetRefineLevel(da,&levels);
     67:   DMSetRefineLevel(shell,levels);

     69:   KSPSetDM(ksp,shell);
     70:   KSPSetComputeRHS(ksp,ComputeRHS,NULL);
     71:   KSPSetComputeOperators(ksp,ComputeMatrix,NULL);
     72:   KSPSetFromOptions(ksp);
     73:   KSPSolve(ksp,NULL,NULL);

     75:   KSPDestroy(&ksp);
     76:   DMDestroy(&shell);
     77:   DMDestroy(&da);
     78:   PetscFinalize();
     79:   return ierr;
     80: }

     82: static PetscErrorCode CreateMatrix(DM shell,Mat *A)
     83: {
     85:   DM             da;

     87:   DMShellGetContext(shell,&da);
     88:   DMCreateMatrix(da,A);
     89:   return 0;
     90: }

     92: static PetscErrorCode CreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
     93: {
     94:   DM             da1,da2;

     97:   DMShellGetContext(dm1,&da1);
     98:   DMShellGetContext(dm2,&da2);
     99:   DMCreateInterpolation(da1,da2,mat,vec);
    100:   return 0;
    101: }

    103: static PetscErrorCode CreateRestriction(DM dm1,DM dm2,Mat *mat)
    104: {
    105:   DM             da1,da2;
    107:   Mat            tmat;

    109:   DMShellGetContext(dm1,&da1);
    110:   DMShellGetContext(dm2,&da2);
    111:   DMCreateInterpolation(da1,da2,&tmat,NULL);
    112:   MatTranspose(tmat,MAT_INITIAL_MATRIX,mat);
    113:   MatDestroy(&tmat);
    114:   return 0;
    115: }

    117: static PetscErrorCode CreateGlobalVector(DM shell,Vec *x)
    118: {
    120:   DM             da;

    122:   DMShellGetContext(shell,&da);
    123:   DMCreateGlobalVector(da,x);
    124:   VecSetDM(*x,shell);
    125:   return 0;
    126: }

    128: static PetscErrorCode CreateLocalVector(DM shell,Vec *x)
    129: {
    131:   DM             da;

    133:   DMShellGetContext(shell,&da);
    134:   DMCreateLocalVector(da,x);
    135:   VecSetDM(*x,shell);
    136:   return 0;
    137: }

    139: static PetscErrorCode Refine(DM shell,MPI_Comm comm,DM *dmnew)
    140: {
    142:   DM             da,dafine;

    144:   DMShellGetContext(shell,&da);
    145:   DMRefine(da,comm,&dafine);
    146:   MyDMShellCreate(PetscObjectComm((PetscObject)shell),dafine,dmnew);
    147:   return 0;
    148: }

    150: static PetscErrorCode Coarsen(DM shell,MPI_Comm comm,DM *dmnew)
    151: {
    153:   DM             da,dacoarse;

    155:   DMShellGetContext(shell,&da);
    156:   DMCoarsen(da,comm,&dacoarse);
    157:   MyDMShellCreate(PetscObjectComm((PetscObject)shell),dacoarse,dmnew);
    158:   /* discard an "extra" reference count to dacoarse */
    159:   DMDestroy(&dacoarse);
    160:   return 0;
    161: }

    163: static PetscErrorCode ComputeRHS(KSP ksp,Vec b,void *ctx)
    164: {
    166:   PetscInt       mx,idx[2];
    167:   PetscScalar    h,v[2];
    168:   DM             da,shell;

    171:   KSPGetDM(ksp,&shell);
    172:   DMShellGetContext(shell,&da);
    173:   DMDAGetInfo(da,0,&mx,0,0,0,0,0,0,0,0,0,0,0);
    174:   h      = 1.0/((mx-1));
    175:   VecSet(b,h);
    176:   idx[0] = 0; idx[1] = mx -1;
    177:   v[0]   = v[1] = 0.0;
    178:   VecSetValues(b,2,idx,v,INSERT_VALUES);
    179:   VecAssemblyBegin(b);
    180:   VecAssemblyEnd(b);
    181:   return(0);
    182: }

    184: static PetscErrorCode ComputeMatrix(KSP ksp,Mat J,Mat jac,void *ctx)
    185: {
    187:   PetscInt       i,mx,xm,xs;
    188:   PetscScalar    v[3],h;
    189:   MatStencil     row,col[3];
    190:   DM             da,shell;

    193:   KSPGetDM(ksp,&shell);
    194:   DMShellGetContext(shell,&da);
    195:   DMDAGetInfo(da,0,&mx,0,0,0,0,0,0,0,0,0,0,0);
    196:   DMDAGetCorners(da,&xs,0,0,&xm,0,0);
    197:   h    = 1.0/(mx-1);

    199:   for (i=xs; i<xs+xm; i++) {
    200:     row.i = i;
    201:     if (i==0 || i==mx-1) {
    202:       v[0] = 2.0/h;
    203:       MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
    204:     } else {
    205:       v[0]  = (-1.0)/h;col[0].i = i-1;
    206:       v[1]  = (2.0)/h;col[1].i = row.i;
    207:       v[2]  = (-1.0)/h;col[2].i = i+1;
    208:       MatSetValuesStencil(jac,1,&row,3,col,v,INSERT_VALUES);
    209:     }
    210:   }
    211:   MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
    212:   MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
    213:   return(0);
    214: }

    216: /*TEST

    218:    test:
    219:       nsize: 4
    220:       args: -ksp_monitor -pc_type mg -da_refine 3

    222: TEST*/