Actual source code: ex8.c
1: static char help[] = "Solves the Poisson equation using DMStag, with a single field in 1D,\n"
2: "intended to demonstrate the simplest use of geometric multigrid\n\n";
4: #include <petscdm.h>
5: #include <petscksp.h>
6: #include <petscdmstag.h>
8: static PetscErrorCode AssembleSystem(DM, Mat *, Vec *);
10: int main(int argc, char **argv)
11: {
12: Mat A;
13: Vec x, b;
14: KSP ksp;
15: DM dm;
16: PetscInt dim;
18: PetscFunctionBeginUser;
19: PetscCall(PetscInitialize(&argc, &argv, (char *)0, help));
21: dim = 1;
23: /* Create a DMStag object with a single degree of freedom for each point
24: on a single stratum, either vertices (0-cells) or elements (d-cells in d dimensions) */
25: if (dim == 1) {
26: PetscCall(DMStagCreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, 8, /* Global element count */
27: 1, /* Unknowns per vertex */
28: 0, /* Unknowns per element */
29: DMSTAG_STENCIL_BOX, 1, /* Elementwise stencil width */
30: NULL, &dm));
31: } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported dimension: %" PetscInt_FMT, dim);
32: PetscCall(DMSetFromOptions(dm));
33: PetscCall(DMSetUp(dm));
35: /* Assemble the discrete system */
36: PetscCall(AssembleSystem(dm, &A, &b));
38: /* Solve */
39: PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
40: PetscCall(KSPSetType(ksp, KSPFGMRES));
41: PetscCall(KSPSetOperators(ksp, A, A));
42: PetscCall(KSPSetDM(ksp, dm));
43: PetscCall(KSPSetDMActive(ksp, PETSC_FALSE));
44: PetscCall(KSPSetFromOptions(ksp));
45: PetscCall(VecDuplicate(b, &x));
46: PetscCall(KSPSolve(ksp, b, x));
47: {
48: KSPConvergedReason reason;
50: PetscCall(KSPGetConvergedReason(ksp, &reason));
51: PetscCheck(reason >= 0, PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED, "Linear solve failed");
52: }
54: /* Destroy PETSc objects and finalize */
55: PetscCall(MatDestroy(&A));
56: PetscCall(VecDestroy(&x));
57: PetscCall(VecDestroy(&b));
58: PetscCall(KSPDestroy(&ksp));
59: PetscCall(DMDestroy(&dm));
60: PetscCall(PetscFinalize());
61: return 0;
62: }
64: static PetscErrorCode AssembleSystem1DVertexCentered(DM dm, Mat *pA, Vec *pb)
65: {
66: Mat A;
67: Vec b;
68: PetscInt start, n, n_extra, N;
70: PetscFunctionBeginUser;
72: PetscCall(DMCreateMatrix(dm, pA));
73: A = *pA;
74: PetscCall(DMCreateGlobalVector(dm, pb));
75: b = *pb;
76: PetscCall(DMStagGetCorners(dm, &start, NULL, NULL, &n, NULL, NULL, &n_extra, NULL, NULL));
77: PetscCall(DMStagGetGlobalSizes(dm, &N, NULL, NULL));
79: /* Loop over all elements, including the non-physical, extra one past the right boundary */
80: for (PetscInt e = start; e < start + n + n_extra; ++e) {
81: DMStagStencil row;
83: row.i = e;
84: row.c = 0;
85: row.loc = DMSTAG_LEFT;
87: if (e == 0) {
88: /* Left boundary conditions (Dirichlet) */
89: PetscScalar val;
91: val = 1.0;
92: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 1, &row, &val, INSERT_VALUES));
93: } else if (e == N) {
94: /* Right boundary (Dirichlet Boundary conditions)*/
95: DMStagStencil row_extra;
96: PetscScalar val;
98: row_extra.i = e;
99: row_extra.c = 0;
100: row_extra.loc = DMSTAG_LEFT;
101: val = 1.0;
103: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row_extra, 1, &row_extra, &val, INSERT_VALUES));
104: } else {
105: /* Interior */
106: DMStagStencil col[3];
107: PetscScalar val[3];
109: col[0].i = e - 1;
110: col[0].c = 0;
111: col[0].loc = DMSTAG_LEFT;
112: val[0] = 1.0;
113: col[1].i = e;
114: col[1].c = 0;
115: col[1].loc = DMSTAG_LEFT;
116: val[1] = -2.0;
117: col[2].i = e + 1;
118: col[2].c = 0;
119: col[2].loc = DMSTAG_LEFT;
120: val[2] = 1.0;
122: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 3, col, val, INSERT_VALUES));
123: }
125: /* Forcing */
126: {
127: PetscScalar x, f, h;
129: h = 1.0 / N; /* Assume a constant spacing instead of accessing coordinates */
130: x = e / ((PetscScalar)N); // 0 - 1
131: f = (x - 0.5) * h * h; // Scale by h^2
132: PetscCall(DMStagVecSetValuesStencil(dm, b, 1, &row, &f, INSERT_VALUES));
133: }
134: }
136: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
137: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
138: PetscCall(VecAssemblyBegin(b));
139: PetscCall(VecAssemblyEnd(b));
141: PetscFunctionReturn(PETSC_SUCCESS);
142: }
144: PetscErrorCode AssembleSystem(DM dm, Mat *pA, Vec *pb)
145: {
146: PetscInt dim;
148: PetscFunctionBeginUser;
149: PetscCall(DMSetMatrixPreallocateOnly(dm, PETSC_TRUE));
150: PetscCall(DMGetDimension(dm, &dim));
151: switch (dim) {
152: case 1:
153: PetscCall(AssembleSystem1DVertexCentered(dm, pA, pb));
154: break;
155: default:
156: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported dimension: %" PetscInt_FMT, dim);
157: }
158: PetscFunctionReturn(PETSC_SUCCESS);
159: }
161: /*TEST
162: test:
163: args: -pc_type mg -pc_mg_galerkin -pc_mg_levels 7 -stag_grid_x 512 -ksp_converged_reason
165: TEST*/