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, KSP_DMACTIVE_ALL, 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*/