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:   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;
 71:   PetscCall(DMCreateMatrix(dm, pA));
 72:   A = *pA;
 73:   PetscCall(DMCreateGlobalVector(dm, pb));
 74:   b = *pb;
 75:   PetscCall(DMStagGetCorners(dm, &start, NULL, NULL, &n, NULL, NULL, &n_extra, NULL, NULL));
 76:   PetscCall(DMStagGetGlobalSizes(dm, &N, NULL, NULL));

 78:   /* Loop over all elements, including the non-physical, extra one past the right boundary */
 79:   for (PetscInt e = start; e < start + n + n_extra; ++e) {
 80:     DMStagStencil row;

 82:     row.i   = e;
 83:     row.c   = 0;
 84:     row.loc = DMSTAG_LEFT;

 86:     if (e == 0) {
 87:       /* Left boundary conditions (Dirichlet) */
 88:       PetscScalar val;

 90:       val = 1.0;
 91:       PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 1, &row, &val, INSERT_VALUES));
 92:     } else if (e == N) {
 93:       /* Right boundary (Dirichlet Boundary conditions)*/
 94:       DMStagStencil row_extra;
 95:       PetscScalar   val;

 97:       row_extra.i   = e;
 98:       row_extra.c   = 0;
 99:       row_extra.loc = DMSTAG_LEFT;
100:       val           = 1.0;

102:       PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row_extra, 1, &row_extra, &val, INSERT_VALUES));
103:     } else {
104:       /* Interior */
105:       DMStagStencil col[3];
106:       PetscScalar   val[3];

108:       col[0].i   = e - 1;
109:       col[0].c   = 0;
110:       col[0].loc = DMSTAG_LEFT;
111:       val[0]     = 1.0;
112:       col[1].i   = e;
113:       col[1].c   = 0;
114:       col[1].loc = DMSTAG_LEFT;
115:       val[1]     = -2.0;
116:       col[2].i   = e + 1;
117:       col[2].c   = 0;
118:       col[2].loc = DMSTAG_LEFT;
119:       val[2]     = 1.0;

121:       PetscCall(DMStagMatSetValuesStencil(dm, A, 1, &row, 3, col, val, INSERT_VALUES));
122:     }

124:     /* Forcing */
125:     {
126:       PetscScalar x, f, h;

128:       h = 1.0 / N;              /* Assume a constant spacing instead of accessing coordinates */
129:       x = e / ((PetscScalar)N); // 0 - 1
130:       f = (x - 0.5) * h * h;    // Scale by h^2
131:       PetscCall(DMStagVecSetValuesStencil(dm, b, 1, &row, &f, INSERT_VALUES));
132:     }
133:   }

135:   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
136:   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
137:   PetscCall(VecAssemblyBegin(b));
138:   PetscCall(VecAssemblyEnd(b));
139:   PetscFunctionReturn(PETSC_SUCCESS);
140: }

142: PetscErrorCode AssembleSystem(DM dm, Mat *pA, Vec *pb)
143: {
144:   PetscInt dim;

146:   PetscFunctionBeginUser;
147:   PetscCall(DMSetMatrixPreallocateOnly(dm, PETSC_TRUE));
148:   PetscCall(DMGetDimension(dm, &dim));
149:   switch (dim) {
150:   case 1:
151:     PetscCall(AssembleSystem1DVertexCentered(dm, pA, pb));
152:     break;
153:   default:
154:     SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unsupported dimension: %" PetscInt_FMT, dim);
155:   }
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: /*TEST
160:    test:
161:       args: -pc_type mg -pc_mg_galerkin -pc_mg_levels 7 -stag_grid_x 512 -ksp_converged_reason

163: TEST*/