Actual source code: ex34.c

  1: /*T
  2:    Concepts: KSP^solving a system of linear equations
  3:    Concepts: KSP^Laplacian, 3d
  4:    Processors: n
  5: T*/

  7: /*
  8: Laplacian in 3D. Modeled by the partial differential equation

 10:    div  grad u = f,  0 < x,y,z < 1,

 12: with pure Neumann boundary conditions

 14:    u = 0 for x = 0, x = 1, y = 0, y = 1, z = 0, z = 1.

 16: The functions are cell-centered

 18: This uses multigrid to solve the linear system

 20:        Contributed by Jianming Yang <jianming-yang@uiowa.edu>
 21: */

 23: static char help[] = "Solves 3D Laplacian using multigrid.\n\n";

 25:  #include petscda.h
 26:  #include petscksp.h
 27:  #include petscmg.h
 28:  #include petscdmmg.h


 33: typedef enum {DIRICHLET, NEUMANN} BCType;

 35: typedef struct {
 36:   BCType        bcType;
 37: } UserContext;

 41: int main(int argc,char **argv)
 42: {
 43:   DMMG           *dmmg;
 44:   DA             da;
 45:   UserContext    user;
 46:   PetscReal      norm;
 47:   const char     *bcTypes[2] = {"dirichlet","neumann"};
 49:   PetscInt       l,bc;

 51:   PetscInt       i,j,k,mx,my,mz,xm,ym,zm,xs,ys,zs;
 52:   PetscScalar    Hx,Hy,Hz;
 53:   PetscScalar    ***array;


 56:   PetscInitialize(&argc,&argv,(char *)0,help);
 57: 
 58:   DMMGCreate(PETSC_COMM_WORLD,3,PETSC_NULL,&dmmg);
 59:   DACreate3d(PETSC_COMM_WORLD,DA_NONPERIODIC,DA_STENCIL_STAR,-3,-3,-3,PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE,1,1,0,0,0,&da);
 60:   DASetInterpolationType(da, DA_Q0);

 62:   DMMGSetDM(dmmg,(DM)da);
 63:   DADestroy(da);
 64:   for (l = 0; l < DMMGGetLevels(dmmg); l++) {
 65:     DMMGSetUser(dmmg,l,&user);
 66:   }
 67: 
 68:   PetscOptionsBegin(PETSC_COMM_WORLD, "", "Options for the inhomogeneous Poisson equation", "DMMG");
 69:   bc          = (PetscInt)NEUMANN;
 70:   PetscOptionsEList("-bc_type","Type of boundary condition","ex34.c",bcTypes,2,bcTypes[0],&bc,PETSC_NULL);
 71:   user.bcType = (BCType)bc;
 72:   PetscOptionsEnd();
 73: 
 74:   DMMGSetKSP(dmmg,ComputeRHS,ComputeJacobian);
 75:   if (user.bcType == NEUMANN) {
 76:     DMMGSetNullSpace(dmmg,PETSC_TRUE,0,PETSC_NULL);
 77:   }

 79:   DMMGSolve(dmmg);
 80: 
 81:   MatMult(DMMGGetJ(dmmg),DMMGGetx(dmmg),DMMGGetr(dmmg));
 82:   VecAXPY(DMMGGetr(dmmg),-1.0,DMMGGetRHS(dmmg));
 83:   VecNorm(DMMGGetr(dmmg),NORM_2,&norm);
 84:   PetscPrintf(PETSC_COMM_WORLD,"Residual norm %G\n",norm);
 85: 
 86:   DAGetInfo(DMMGGetDA(dmmg), 0, &mx, &my, &mz, 0,0,0,0,0,0,0);
 87:   Hx   = 1.0 / (PetscReal)(mx);
 88:   Hy   = 1.0 / (PetscReal)(my);
 89:   Hz   = 1.0 / (PetscReal)(mz);
 90:   DAGetCorners(DMMGGetDA(dmmg),&xs,&ys,&zs,&xm,&ym,&zm);
 91:   DAVecGetArray(DMMGGetDA(dmmg), DMMGGetx(dmmg), &array);

 93:   for (k=zs; k<zs+zm; k++){
 94:     for (j=ys; j<ys+ym; j++){
 95:       for(i=xs; i<xs+xm; i++){
 96:         array[k][j][i] -=
 97:           PetscCosScalar(2*PETSC_PI*(((PetscReal)i+0.5)*Hx))*
 98:           PetscCosScalar(2*PETSC_PI*(((PetscReal)j+0.5)*Hy))*
 99:           PetscCosScalar(2*PETSC_PI*(((PetscReal)k+0.5)*Hz));
100:       }
101:     }
102:   }
103:   DAVecRestoreArray(DMMGGetDA(dmmg), DMMGGetx(dmmg), &array);
104:   VecAssemblyBegin(DMMGGetx(dmmg));
105:   VecAssemblyEnd(DMMGGetx(dmmg));

107:   VecNorm(DMMGGetx(dmmg),NORM_INFINITY,&norm);
108:   PetscPrintf(PETSC_COMM_WORLD,"Error norm %g\n",norm);
109:   VecNorm(DMMGGetx(dmmg),NORM_1,&norm);
110:   PetscPrintf(PETSC_COMM_WORLD,"Error norm %g\n",norm/((PetscReal)(mx)*(PetscReal)(my)*(PetscReal)(mz)));
111:   VecNorm(DMMGGetx(dmmg),NORM_2,&norm);
112:   PetscPrintf(PETSC_COMM_WORLD,"Error norm %g\n",norm/((PetscReal)(mx)*(PetscReal)(my)*(PetscReal)(mz)));

114:   DMMGDestroy(dmmg);
115:   PetscFinalize();
116:   return 0;
117: }

121: PetscErrorCode ComputeRHS(DMMG dmmg, Vec b)
122: {
123:   DA             da = (DA)dmmg->dm;
124:   UserContext    *user = (UserContext *) dmmg->user;
126:   PetscInt       i,j,k,mx,my,mz,xm,ym,zm,xs,ys,zs;
127:   PetscScalar    Hx,Hy,Hz;
128:   PetscScalar    ***array;

131:   DAGetInfo(da, 0, &mx, &my, &mz, 0,0,0,0,0,0,0);
132:   Hx   = 1.0 / (PetscReal)(mx);
133:   Hy   = 1.0 / (PetscReal)(my);
134:   Hz   = 1.0 / (PetscReal)(mz);
135:   DAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm);
136:   DAVecGetArray(da, b, &array);
137:   for (k=zs; k<zs+zm; k++){
138:     for (j=ys; j<ys+ym; j++){
139:       for(i=xs; i<xs+xm; i++){
140:         array[k][j][i] = 12*PETSC_PI*PETSC_PI
141:           *PetscCosScalar(2*PETSC_PI*(((PetscReal)i+0.5)*Hx))
142:           *PetscCosScalar(2*PETSC_PI*(((PetscReal)j+0.5)*Hy))
143:           *PetscCosScalar(2*PETSC_PI*(((PetscReal)k+0.5)*Hz))
144:           *Hx*Hy*Hz;
145:       }
146:     }
147:   }
148:   DAVecRestoreArray(da, b, &array);
149:   VecAssemblyBegin(b);
150:   VecAssemblyEnd(b);

152:   /* force right hand side to be consistent for singular matrix */
153:   /* note this is really a hack, normally the model would provide you with a consistent right handside */
154:   if (user->bcType == NEUMANN)
155:     {
156:       MatNullSpace nullspace;
157: 
158:       KSPGetNullSpace(dmmg->ksp,&nullspace);
159:       MatNullSpaceRemove(nullspace,b,PETSC_NULL);
160:     }

162:   return(0);
163: }

165: 
168: PetscErrorCode ComputeJacobian(DMMG dmmg, Mat J,Mat jac)
169: {
170:   DA             da = (DA) dmmg->dm;
171:   UserContext    *user = (UserContext *) dmmg->user;
173:   PetscInt       i,j,k,mx,my,mz,xm,ym,zm,xs,ys,zs,num, numi, numj, numk;
174:   PetscScalar    v[7],Hx,Hy,Hz,HyHzdHx,HxHzdHy,HxHydHz;
175:   MatStencil     row, col[7];

178:   DAGetInfo(da,0,&mx,&my,&mz,0,0,0,0,0,0,0);
179:   Hx    = 1.0 / (PetscReal)(mx);
180:   Hy    = 1.0 / (PetscReal)(my);
181:   Hz    = 1.0 / (PetscReal)(mz);
182:   HyHzdHx = Hy*Hz/Hx;
183:   HxHzdHy = Hx*Hz/Hy;
184:   HxHydHz = Hx*Hy/Hz;
185:   DAGetCorners(da,&xs,&ys,&zs,&xm,&ym,&zm);
186:   for (k=zs; k<zs+zm; k++)
187:     {
188:       for (j=ys; j<ys+ym; j++)
189:         {
190:           for(i=xs; i<xs+xm; i++)
191:             {
192:               row.i = i; row.j = j; row.k = k;
193:               if (i==0 || j==0 || k==0 || i==mx-1 || j==my-1 || k==mz-1)
194:                 {
195:                   if (user->bcType == DIRICHLET)
196:                     {
197:                       SETERRQ(PETSC_ERR_SUP,"Dirichlet boundary conditions not supported !\n");
198:                       v[0] = 2.0*(HyHzdHx + HxHzdHy + HxHydHz);
199:                       MatSetValuesStencil(jac,1,&row,1,&row,v,INSERT_VALUES);
200: 
201:                     }
202:                   else if (user->bcType == NEUMANN)
203:                     {
204:                       num = 0; numi=0; numj=0; numk=0;
205:                       if (k!=0)
206:                         {
207:                           v[num] = -HxHydHz;
208:                           col[num].i = i;
209:                           col[num].j = j;
210:                           col[num].k = k-1;
211:                           num++; numk++;
212:                         }
213:                       if (j!=0)
214:                         {
215:                           v[num] = -HxHzdHy;
216:                           col[num].i = i;
217:                           col[num].j = j-1;
218:                           col[num].k = k;
219:                           num++; numj++;
220:                         }
221:                       if (i!=0)
222:                         {
223:                           v[num] = -HyHzdHx;
224:                           col[num].i = i-1;
225:                           col[num].j = j;
226:                           col[num].k = k;
227:                           num++; numi++;
228:                         }
229:                       if (i!=mx-1)
230:                         {
231:                           v[num] = -HyHzdHx;
232:                           col[num].i = i+1;
233:                           col[num].j = j;
234:                           col[num].k = k;
235:                           num++; numi++;
236:                         }
237:                       if (j!=my-1)
238:                         {
239:                           v[num] = -HxHzdHy;
240:                           col[num].i = i;
241:                           col[num].j = j+1;
242:                           col[num].k = k;
243:                           num++; numj++;
244:                         }
245:                       if (k!=mz-1)
246:                         {
247:                           v[num] = -HxHydHz;
248:                           col[num].i = i;
249:                           col[num].j = j;
250:                           col[num].k = k+1;
251:                           num++; numk++;
252:                         }
253:                       v[num]   = (PetscReal)(numk)*HxHydHz + (PetscReal)(numj)*HxHzdHy + (PetscReal)(numi)*HyHzdHx;
254:                       col[num].i = i;   col[num].j = j;   col[num].k = k;
255:                       num++;
256:                       MatSetValuesStencil(jac,1,&row,num,col,v,INSERT_VALUES);
257:                     }
258:                 }
259:               else
260:                 {
261:                   v[0] = -HxHydHz;                          col[0].i = i;   col[0].j = j;   col[0].k = k-1;
262:                   v[1] = -HxHzdHy;                          col[1].i = i;   col[1].j = j-1; col[1].k = k;
263:                   v[2] = -HyHzdHx;                          col[2].i = i-1; col[2].j = j;   col[2].k = k;
264:                   v[3] = 2.0*(HyHzdHx + HxHzdHy + HxHydHz); col[3].i = i;   col[3].j = j;   col[3].k = k;
265:                   v[4] = -HyHzdHx;                          col[4].i = i+1; col[4].j = j;   col[4].k = k;
266:                   v[5] = -HxHzdHy;                          col[5].i = i;   col[5].j = j+1; col[5].k = k;
267:                   v[6] = -HxHydHz;                          col[6].i = i;   col[6].j = j;   col[6].k = k+1;
268:                   MatSetValuesStencil(jac,1,&row,7,col,v,INSERT_VALUES);
269:                 }
270:             }
271:         }
272:     }
273:   MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
274:   MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);

276:   return(0);
277: }