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, NULL, 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: PetscCheck(dim == 1, PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported dimension: %" PetscInt_FMT, dim);
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: PetscCall(DMSetFromOptions(dm));
32: PetscCall(DMSetUp(dm));
34: /* Assemble the discrete system */
35: PetscCall(AssembleSystem(dm, &A, &b));
37: /* Solve */
38: PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &ksp));
39: PetscCall(KSPSetType(ksp, KSPFGMRES));
40: PetscCall(KSPSetOperators(ksp, A, A));
41: PetscCall(KSPSetDM(ksp, dm));
42: PetscCall(KSPSetDMActive(ksp, PETSC_FALSE));
43: PetscCall(KSPSetFromOptions(ksp));
44: PetscCall(VecDuplicate(b, &x));
45: PetscCall(KSPSolve(ksp, b, x));
46: {
47: KSPConvergedReason reason;
49: PetscCall(KSPGetConvergedReason(ksp, &reason));
50: PetscCheck(reason >= 0, PETSC_COMM_WORLD, PETSC_ERR_CONV_FAILED, "Linear solve failed");
51: }
53: /* Destroy PETSc objects and finalize */
54: PetscCall(MatDestroy(&A));
55: PetscCall(VecDestroy(&x));
56: PetscCall(VecDestroy(&b));
57: PetscCall(KSPDestroy(&ksp));
58: PetscCall(DMDestroy(&dm));
59: PetscCall(PetscFinalize());
60: return 0;
61: }
63: static PetscErrorCode AssembleSystem1DVertexCentered(DM dm, Mat *pA, Vec *pb)
64: {
65: Mat A;
66: Vec b;
67: PetscInt start, n, n_extra, N;
69: PetscFunctionBeginUser;
70: PetscCall(DMCreateMatrix(dm, pA));
71: A = *pA;
72: PetscCall(DMCreateGlobalVector(dm, pb));
73: b = *pb;
74: PetscCall(DMStagGetCorners(dm, &start, NULL, NULL, &n, NULL, NULL, &n_extra, NULL, NULL));
75: PetscCall(DMStagGetGlobalSizes(dm, &N, NULL, NULL));
77: /* Loop over all elements, including the non-physical, extra one past the right boundary */
78: for (PetscInt e = start; e < start + n + n_extra; ++e) {
79: DMStagStencil row;
81: row.i = e;
82: row.c = 0;
83: row.loc = DMSTAG_LEFT;
85: if (e == 0) {
86: /* Left boundary conditions (Dirichlet) */
87: PetscScalar val;
89: val = 1.0;
90: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 1, &row, &val, INSERT_VALUES));
91: } else if (e == N) {
92: /* Right boundary (Dirichlet Boundary conditions)*/
93: DMStagStencil row_extra;
94: PetscScalar val;
96: row_extra.i = e;
97: row_extra.c = 0;
98: row_extra.loc = DMSTAG_LEFT;
99: val = 1.0;
101: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row_extra, 1, &row_extra, &val, INSERT_VALUES));
102: } else {
103: /* Interior */
104: DMStagStencil col[3];
105: PetscScalar val[3];
107: col[0].i = e - 1;
108: col[0].c = 0;
109: col[0].loc = DMSTAG_LEFT;
110: val[0] = 1.0;
111: col[1].i = e;
112: col[1].c = 0;
113: col[1].loc = DMSTAG_LEFT;
114: val[1] = -2.0;
115: col[2].i = e + 1;
116: col[2].c = 0;
117: col[2].loc = DMSTAG_LEFT;
118: val[2] = 1.0;
120: PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 3, col, val, INSERT_VALUES));
121: }
123: /* Forcing */
124: {
125: PetscScalar x, f, h;
127: h = 1.0 / N; /* Assume a constant spacing instead of accessing coordinates */
128: x = e / ((PetscScalar)N); // 0 - 1
129: f = (x - 0.5) * h * h; // Scale by h^2
130: PetscCall(DMStagVecSetValuesStencil(dm, b, 1, &row, &f, INSERT_VALUES));
131: }
132: }
134: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
135: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
136: PetscCall(VecAssemblyBegin(b));
137: PetscCall(VecAssemblyEnd(b));
138: PetscFunctionReturn(PETSC_SUCCESS);
139: }
141: PetscErrorCode AssembleSystem(DM dm, Mat *pA, Vec *pb)
142: {
143: PetscInt dim;
145: PetscFunctionBeginUser;
146: PetscCall(DMSetMatrixPreallocateOnly(dm, PETSC_TRUE));
147: PetscCall(DMGetDimension(dm, &dim));
148: switch (dim) {
149: case 1:
150: PetscCall(AssembleSystem1DVertexCentered(dm, pA, pb));
151: break;
152: default:
153: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported dimension: %" PetscInt_FMT, dim);
154: }
155: PetscFunctionReturn(PETSC_SUCCESS);
156: }
158: /*TEST
159: test:
160: args: -pc_type mg -pc_mg_galerkin -pc_mg_levels 7 -stag_grid_x 512 -ksp_converged_reason
162: TEST*/