Actual source code: ex68.c

  1: #include <petscdt.h>
  2: #include <petscdraw.h>
  3: #include <petscviewer.h>
  4: #include <petscksp.h>

  6: /*
  7:       Solves -Laplacian u = f,  u(-1) = u(1) = 0 with a single spectral element for n = 4 to N GLL points

  9:       Plots the L_2 norm of the error (evaluated via the GLL nodes and weights) as a function of n.

 11: */
 12: PetscErrorCode ComputeSolution(PetscInt n, PetscReal *nodes, PetscReal *weights, Vec x)
 13: {
 14:   PetscInt     i, m;
 15:   PetscScalar *xx;
 16:   PetscReal    xd;

 18:   PetscFunctionBegin;
 19:   PetscCall(VecGetSize(x, &m));
 20:   PetscCall(VecGetArray(x, &xx));
 21:   for (i = 0; i < m; i++) {
 22:     xd    = nodes[i];
 23:     xx[i] = (xd * xd - 1.0) * PetscCosReal(5. * PETSC_PI * xd);
 24:   }
 25:   PetscCall(VecRestoreArray(x, &xx));
 26:   PetscFunctionReturn(PETSC_SUCCESS);
 27: }

 29: /*
 30:       Evaluates \integral_{-1}^{1} f*v_i  where v_i is the ith basis polynomial via the GLL nodes and weights, since the v_i
 31:       basis function is zero at all nodes except the ith one the integral is simply the weight_i * f(node_i)
 32: */
 33: PetscErrorCode ComputeRhs(PetscInt n, PetscReal *nodes, PetscReal *weights, Vec b)
 34: {
 35:   PetscInt     i, m;
 36:   PetscScalar *bb;
 37:   PetscReal    xd;

 39:   PetscFunctionBegin;
 40:   PetscCall(VecGetSize(b, &m));
 41:   PetscCall(VecGetArray(b, &bb));
 42:   for (i = 0; i < m; i++) {
 43:     xd    = nodes[i];
 44:     bb[i] = -weights[i] * (-20. * PETSC_PI * xd * PetscSinReal(5. * PETSC_PI * xd) + (2. - (5. * PETSC_PI) * (5. * PETSC_PI) * (xd * xd - 1.)) * PetscCosReal(5. * PETSC_PI * xd));
 45:   }
 46:   PetscCall(VecRestoreArray(b, &bb));
 47:   PetscFunctionReturn(PETSC_SUCCESS);
 48: }

 50: int main(int argc, char **args)
 51: {
 52:   PetscReal    *nodes;
 53:   PetscReal    *weights;
 54:   PetscInt      N = 80, n;
 55:   PetscReal   **A;
 56:   Mat           K;
 57:   KSP           ksp;
 58:   PC            pc;
 59:   Vec           x, b;
 60:   PetscInt      rows[2];
 61:   PetscReal     norm, xc, yc;
 62:   PetscScalar  *f;
 63:   PetscDraw     draw;
 64:   PetscDrawLG   lg;
 65:   PetscDrawAxis axis;

 67:   PetscFunctionBeginUser;
 68:   PetscCall(PetscInitialize(&argc, &args, NULL, NULL));
 69:   PetscCall(PetscOptionsGetInt(NULL, NULL, "-N", &N, NULL));

 71:   PetscCall(PetscDrawCreate(PETSC_COMM_SELF, NULL, "Log(Error norm) vs Number of GLL points", 0, 0, 500, 500, &draw));
 72:   PetscCall(PetscDrawSetFromOptions(draw));
 73:   PetscCall(PetscDrawLGCreate(draw, 1, &lg));
 74:   PetscCall(PetscDrawLGSetUseMarkers(lg, PETSC_TRUE));
 75:   PetscCall(PetscDrawLGGetAxis(lg, &axis));
 76:   PetscCall(PetscDrawAxisSetLabels(axis, NULL, "Number of GLL points", "Log(Error Norm)"));

 78:   for (n = 4; n < N; n += 2) {
 79:     /*
 80:        compute GLL node and weight values
 81:     */
 82:     PetscCall(PetscMalloc2(n, &nodes, n, &weights));
 83:     PetscCall(PetscDTGaussLobattoLegendreQuadrature(n, PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA, nodes, weights));
 84:     /*
 85:        Creates the element stiffness matrix for the given gll
 86:     */
 87:     PetscCall(PetscGaussLobattoLegendreElementLaplacianCreate(n, nodes, weights, &A));
 88:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF, n, n, &A[0][0], &K));
 89:     rows[0] = 0;
 90:     rows[1] = n - 1;
 91:     PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp));
 92:     PetscCall(MatCreateVecs(K, &x, &b));
 93:     PetscCall(ComputeRhs(n, nodes, weights, b));
 94:     /*
 95:         Replace the first and last rows/columns of the matrix with the identity to obtain the zero Dirichlet boundary conditions
 96:     */
 97:     PetscCall(MatZeroRowsColumns(K, 2, rows, 1.0, x, b));
 98:     PetscCall(KSPSetOperators(ksp, K, K));
 99:     PetscCall(KSPGetPC(ksp, &pc));
100:     PetscCall(PCSetType(pc, PCLU));
101:     PetscCall(KSPSetFromOptions(ksp));
102:     PetscCall(KSPSolve(ksp, b, x));

104:     /* compute the error to the continium problem */
105:     PetscCall(ComputeSolution(n, nodes, weights, b));
106:     PetscCall(VecAXPY(x, -1.0, b));

108:     /* compute the L^2 norm of the error */
109:     PetscCall(VecGetArray(x, &f));
110:     PetscCall(PetscGaussLobattoLegendreIntegrate(n, nodes, weights, f, &norm));
111:     PetscCall(VecRestoreArray(x, &f));
112:     norm = PetscSqrtReal(norm);
113:     PetscCall(PetscViewerASCIIPrintf(PETSC_VIEWER_STDOUT_SELF, "L^2 norm of the error %" PetscInt_FMT " %g\n", n, (double)norm));
114:     xc = (PetscReal)n;
115:     yc = PetscLog10Real(norm);
116:     PetscCall(PetscDrawLGAddPoint(lg, &xc, &yc));
117:     PetscCall(PetscDrawLGDraw(lg));

119:     PetscCall(VecDestroy(&b));
120:     PetscCall(VecDestroy(&x));
121:     PetscCall(KSPDestroy(&ksp));
122:     PetscCall(MatDestroy(&K));
123:     PetscCall(PetscGaussLobattoLegendreElementLaplacianDestroy(n, nodes, weights, &A));
124:     PetscCall(PetscFree2(nodes, weights));
125:   }
126:   PetscCall(PetscDrawSetPause(draw, -2));
127:   PetscCall(PetscDrawLGDestroy(&lg));
128:   PetscCall(PetscDrawDestroy(&draw));
129:   PetscCall(PetscFinalize());
130:   return 0;
131: }

133: /*TEST

135:   build:
136:       requires: !complex

138:    test:

140: TEST*/