Actual source code: ex66.c
1: /* DMDA/KSP solving a system of linear equations.
2: Poisson equation in 2D:
4: div(grad p) = f, 0 < x,y < 1
5: with
6: forcing function f = -cos(m*pi*x)*cos(n*pi*y),
7: Periodic boundary conditions
8: p(x=0) = p(x=1)
9: Neumann boundary conditions
10: dp/dy = 0 for y = 0, y = 1.
12: This example uses the DM_BOUNDARY_MIRROR to implement the Neumann boundary conditions, see the manual pages for DMBoundaryType
14: Compare to ex50.c
15: */
17: static char help[] = "Solves 2D Poisson equation,\n\
18: using mirrored boundaries to implement Neumann boundary conditions,\n\
19: using multigrid.\n\n";
21: #include <petscdm.h>
22: #include <petscdmda.h>
23: #include <petscksp.h>
24: #include <petscsys.h>
25: #include <petscvec.h>
27: extern PetscErrorCode ComputeJacobian(KSP, Mat, Mat, void *);
28: extern PetscErrorCode ComputeRHS(KSP, Vec, void *);
30: typedef struct {
31: PetscScalar uu, tt;
32: } UserContext;
34: int main(int argc, char **argv)
35: {
36: KSP ksp;
37: DM da;
38: UserContext user;
40: PetscFunctionBeginUser;
41: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
42: PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
43: PetscCall(DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_PERIODIC, DM_BOUNDARY_MIRROR, DMDA_STENCIL_STAR, 11, 11, PETSC_DECIDE, PETSC_DECIDE, 1, 1, NULL, NULL, &da));
44: PetscCall(DMSetFromOptions(da));
45: PetscCall(DMSetUp(da));
46: PetscCall(KSPSetDM(ksp, (DM)da));
47: PetscCall(DMSetApplicationContext(da, &user));
49: user.uu = 1.0;
50: user.tt = 1.0;
52: PetscCall(KSPSetComputeRHS(ksp, ComputeRHS, &user));
53: PetscCall(KSPSetComputeOperators(ksp, ComputeJacobian, &user));
54: PetscCall(KSPSetFromOptions(ksp));
55: PetscCall(KSPSolve(ksp, NULL, NULL));
57: PetscCall(DMDestroy(&da));
58: PetscCall(KSPDestroy(&ksp));
59: PetscCall(PetscFinalize());
60: return 0;
61: }
63: PetscErrorCode ComputeRHS(KSP ksp, Vec b, void *ctx)
64: {
65: UserContext *user = (UserContext *)ctx;
66: PetscInt i, j, M, N, xm, ym, xs, ys;
67: PetscScalar Hx, Hy, pi, uu, tt;
68: PetscScalar **array;
69: DM da;
70: MatNullSpace nullspace;
72: PetscFunctionBeginUser;
73: PetscCall(KSPGetDM(ksp, &da));
74: PetscCall(DMDAGetInfo(da, 0, &M, &N, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
75: uu = user->uu;
76: tt = user->tt;
77: pi = 4 * PetscAtanReal(1.0);
78: Hx = 1.0 / (PetscReal)M;
79: Hy = 1.0 / (PetscReal)N;
81: PetscCall(DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0)); /* Fine grid */
82: PetscCall(DMDAVecGetArray(da, b, &array));
83: for (j = ys; j < ys + ym; j++) {
84: for (i = xs; i < xs + xm; i++) array[j][i] = -PetscCosScalar(uu * pi * ((PetscReal)i + 0.5) * Hx) * PetscCosScalar(tt * pi * ((PetscReal)j + 0.5) * Hy) * Hx * Hy;
85: }
86: PetscCall(DMDAVecRestoreArray(da, b, &array));
87: PetscCall(VecAssemblyBegin(b));
88: PetscCall(VecAssemblyEnd(b));
90: /* force right-hand side to be consistent for singular matrix */
91: /* note this is really a hack, normally the model would provide you with a consistent right handside */
92: PetscCall(MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, 0, &nullspace));
93: PetscCall(MatNullSpaceRemove(nullspace, b));
94: PetscCall(MatNullSpaceDestroy(&nullspace));
95: PetscFunctionReturn(PETSC_SUCCESS);
96: }
98: PetscErrorCode ComputeJacobian(KSP ksp, Mat J, Mat jac, void *ctx)
99: {
100: PetscInt i, j, M, N, xm, ym, xs, ys;
101: PetscScalar v[5], Hx, Hy, HydHx, HxdHy;
102: MatStencil row, col[5];
103: DM da;
104: MatNullSpace nullspace;
106: PetscFunctionBeginUser;
107: PetscCall(KSPGetDM(ksp, &da));
108: PetscCall(DMDAGetInfo(da, 0, &M, &N, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
109: Hx = 1.0 / (PetscReal)M;
110: Hy = 1.0 / (PetscReal)N;
111: HxdHy = Hx / Hy;
112: HydHx = Hy / Hx;
113: PetscCall(DMDAGetCorners(da, &xs, &ys, 0, &xm, &ym, 0));
114: for (j = ys; j < ys + ym; j++) {
115: for (i = xs; i < xs + xm; i++) {
116: row.i = i;
117: row.j = j;
118: v[0] = -HxdHy;
119: col[0].i = i;
120: col[0].j = j - 1;
121: v[1] = -HydHx;
122: col[1].i = i - 1;
123: col[1].j = j;
124: v[2] = 2.0 * (HxdHy + HydHx);
125: col[2].i = i;
126: col[2].j = j;
127: v[3] = -HydHx;
128: col[3].i = i + 1;
129: col[3].j = j;
130: v[4] = -HxdHy;
131: col[4].i = i;
132: col[4].j = j + 1;
133: PetscCall(MatSetValuesStencil(jac, 1, &row, 5, col, v, ADD_VALUES));
134: }
135: }
136: PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
137: PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
139: PetscCall(MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, 0, &nullspace));
140: PetscCall(MatSetNullSpace(J, nullspace));
141: PetscCall(MatNullSpaceDestroy(&nullspace));
142: PetscFunctionReturn(PETSC_SUCCESS);
143: }
145: /*TEST
147: build:
148: requires: !complex !single
150: test:
151: args: -pc_type mg -pc_mg_type full -ksp_monitor_short -da_refine 3 -mg_coarse_pc_type svd -ksp_view
153: test:
154: suffix: 2
155: nsize: 4
156: args: -pc_type mg -pc_mg_type full -ksp_monitor_short -da_refine 3 -mg_coarse_pc_type redundant -mg_coarse_redundant_pc_type svd -ksp_view
158: TEST*/