blob: b46b04e1a4c1c72d1f725c2a8bd8c295a3f9a386 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
// Steady convection-diffusion -eps (u_xx + u_yy) + b_x u_x + b_y u_y = 1 on the
// unit square, u = 0 on the boundary, with centered differences. The 1-D
// operators eps D + b G (D = tridiag(-1, 2, -1) / h^2, G = tridiag(-1, 0, 1) / 2h)
// are not symmetric, so BartelsStewart takes the Schur path; the result agrees
// with SparseLU on the assembled matrix.
#include <contrib/Eigen/StructuredMatrices>
#include <iostream>
using namespace Eigen;
SparseMatrix<double> convectionDiffusion(int n, double eps, double b) {
const double h = 1.0 / (n + 1);
SparseMatrix<double> A(n, n);
A.reserve(VectorXi::Constant(n, 3)); // at most 3 nonzeros per column
for (int i = 0; i < n; ++i) {
A.insert(i, i) = 2 * eps / (h * h);
if (i > 0) A.insert(i, i - 1) = -eps / (h * h) - b / (2 * h);
if (i + 1 < n) A.insert(i, i + 1) = -eps / (h * h) + b / (2 * h);
}
A.makeCompressed();
return A;
}
int main() {
const int n = 100;
const double eps = 0.05;
const auto L = makeKroneckerSum(convectionDiffusion(n, eps, 0.5), convectionDiffusion(n, eps, 1.0));
const BartelsStewart<std::decay_t<decltype(L)>> solver(L);
const VectorXd f = VectorXd::Ones(n * n);
const VectorXd u = solver.solve(f);
SparseMatrix<double> A;
A = L; // the assembled n^2 x n^2 matrix, for comparison
const VectorXd uLU = SparseLU<SparseMatrix<double>>(A).solve(f);
std::cout << "fast diagonalization: " << (solver.isHermitian() ? "yes" : "no") << "\n";
std::cout << "max u: " << u.maxCoeff() << "\n";
std::cout << "relative residual: " << (A * u - f).norm() / f.norm() << "\n";
std::cout << "|u - u_SparseLU|/|u|: " << (u - uLU).norm() / u.norm() << "\n";
}