Skip to content

15_diffusion_evidence_cg.cpp

End-to-end invariant propagation from a PDE construction into CG.

#include "numerics.hpp"

#include <cmath>
#include <iostream>

int main() {
    constexpr int points_per_side = 32;
    constexpr double timestep_diffusivity = 0.05;

    const num::grid2d grid{points_per_side, 1.0 / (points_per_side + 1)};

    // The Dirichlet backward-Euler construction establishes that I - dt*L is
    // positive definite.  That evidence is part of the returned operator, so
    // CG accepts it directly: there is no assume_spd() at the call site.
    const num::operators::backward_euler_2d system(grid.N, timestep_diffusivity);
    static_assert(num::claims<decltype(system), num::law::spd>);

    num::vec<num::real> rhs(grid.size(), 0.0);
    for (int i = 0; i < grid.N; ++i) {
        for (int j = 0; j < grid.N; ++j) {
            const double x = grid.x(i);
            const double y = grid.y(j);
            rhs[grid.flat(i, j)] = std::sin(num::pi * x) * std::sin(num::pi * y);
        }
    }

    num::vec<num::real> solution(rhs.size(), 0.0);
    const auto result =
        num::cg(system, rhs, solution,
                num::cg_options{.tolerance = 1e-12, .max_iterations = 4 * solution.size()});

    std::cout << "backward-Euler diffusion: " << result.iterations << " CG iterations, residual "
              << result.residual << '\n';
    return result.converged ? 0 : 1;
}

Possible output:

backward-Euler diffusion: 1 CG iterations, residual 1.97955e-15