#include #include "Eigen/SparseCore" #include "Eigen/SparseLU" #include "gtest/gtest.h" namespace mm { class PoissonImplicitTest : public ::testing::Test { public: // Parameters Vec2d size; Vec2d shift; int N; protected: void SetUp() override { size = {1, 1}; shift = {0, 0}; } template double solve(const BasisType& basis, int support_size, int num_nodes_x, const WeightType& weight) { // Closed form solution -- refer to cantilever_beam.nb for reference. std::function analytical = [=](const Vec2d& p) { return std::sin(PI*(p[0]-shift[0])/size[0])*std::sin(PI*(p[1]-shift[1])/size[1]); }; // Domain definition Vec2d low = shift, high = shift+size; BoxShape box(low, high); DomainDiscretization domain = box.discretizeWithStep(size[0] / num_nodes_x); N = domain.size(); domain.findSupport(FindClosest(support_size)); WLS approx(basis, weight); auto storage = domain.computeShapes(approx, domain.interior()); Eigen::SparseMatrix M(N, N); M.reserve(storage.supportSizes()); Eigen::VectorXd rhs(N); rhs.setZero(); auto op = storage.implicitOperators(M, rhs); // Set equation on interior for (int i : domain.interior()) { auto p = domain.pos(i); op.lap(i) = -PI*PI*(size.squaredNorm())/size[0]/size[0]/size[1]/size[1]* std::sin(PI*(p[0]-shift[0])/size[0])*std::sin(PI*(p[1]-shift[1])/size[1]); } for (int i : domain.boundary()) { op.value(i) = 0; } M.makeCompressed(); Eigen::SparseMatrix M2 = M; Eigen::SparseLU solver; solver.compute(M2); Eigen::VectorXd sol = solver.solve(rhs); Range error(N); double maxan = 0; for (int i = 0; i < N; ++i) { double an = analytical(domain.pos(i)); if (an > maxan) maxan = an; error[i] = std::abs(an - sol[i]); } double L_inf_error = *std::max_element(error.begin(), error.end()); return L_inf_error / maxan; } }; TEST_F(PoissonImplicitTest, Monomials5NoWeight) { Monomials mon5({{0, 0}, {0, 1}, {1, 0}, {2, 0}, {0, 2}}); int ss = 5; EXPECT_LT(solve(mon5, ss, 29, NoWeight()), 1e-3); EXPECT_LT(solve(mon5, ss, 93, NoWeight()), 1e-4); // EXPECT_LT(solve(mon5, ss, 300, NoWeight()), 1e-5); } TEST_F(PoissonImplicitTest, Monomials5NoWeightShifted) { shift = {-123.234, 234.98713}; Monomials mon5({{0, 0}, {0, 1}, {1, 0}, {2, 0}, {0, 2}}); int ss = 5; EXPECT_LT(solve(mon5, ss, 29, NoWeight()), 1e-3); } TEST_F(PoissonImplicitTest, Monomials5NoWeightScaledUp) { size = 1000.2345; Monomials mon5({{0, 0}, {0, 1}, {1, 0}, {2, 0}, {0, 2}}); int ss = 5; EXPECT_LT(solve(mon5, ss, 29, NoWeight()), 1e-3); } TEST_F(PoissonImplicitTest, Monomials5NoWeightScaledDown) { size = 0.00112; Monomials mon5({{0, 0}, {0, 1}, {1, 0}, {2, 0}, {0, 2}}); int ss = 5; EXPECT_LT(solve(mon5, ss, 29, NoWeight()), 1e-3); } TEST_F(PoissonImplicitTest, Gaussians5NoWeight) { double sigmaB = 100; Gaussians g5(5, sigmaB); int ss = 5; EXPECT_LT(solve(g5, ss, 29, NoWeight()), 1e-3); EXPECT_LT(solve(g5, ss, 93, NoWeight()), 1e-5); // stagnation error reached double err = solve(g5, ss, 167, NoWeight()); EXPECT_LT(err, 1e-4); // error starts increasing EXPECT_GT(err, 1e-5); } TEST_F(PoissonImplicitTest, Gaussians5Weight) { double sigmaB = 100; int ss = 5; Gaussians g5(ss, sigmaB); GaussianWeight w(1000.0); EXPECT_LT(solve(g5, ss, 29, NoWeight()), 1e-3); } TEST_F(PoissonImplicitTest, Monomials9NoWeight) { Monomials mon9 = Monomials::tensorBasis(2); int ss = 9; EXPECT_LT(solve(mon9, ss, 29, NoWeight()), 1e-3); EXPECT_LT(solve(mon9, ss, 93, NoWeight()), 1e-4); // EXPECT_LT(solve(mon9, ss, 300, NoWeight()), 1e-5); } TEST_F(PoissonImplicitTest, Monomials9Weight) { Monomials mon9 = Monomials::tensorBasis(2); GaussianWeight w(1000.0); // effectively constant w int ss = 9; EXPECT_LT(solve(mon9, ss, 29, w), 1e-3); EXPECT_LT(solve(mon9, ss, 93, w), 1e-4); } TEST_F(PoissonImplicitTest, Gaussians9NoWeight) { double sigmaB = 100; Gaussians g9(9, sigmaB); int ss = 9; EXPECT_LT(solve(g9, ss, 22, NoWeight()), 1e-2); EXPECT_LT(solve(g9, ss, 66, NoWeight()), 1e-3); EXPECT_LT(solve(g9, ss, 149, NoWeight()), 1e-4); } TEST_F(PoissonImplicitTest, Monomials6Weight) { GaussianWeight w(1.0); Monomials mon6(2); int ss = 9; EXPECT_LT(solve(mon6, ss, 18, w), 1e-2); EXPECT_LT(solve(mon6, ss, 59, w), 1e-3); // EXPECT_LT(solve(mon6, ss, 188, w), 1e-4); } // TEST_F(PoissonImplicitTest, GaussiansWeight) { // std::vector ns = {11, 12, 13, 15, 16, 18, 21, 23, 26, 29, 33, 37, 41, 46, 52, 59, 66, // 74, 83, 93, 105, 118, 133, 149, 167, 188, 212, 238, 267, 300}; // std::vector errs; // std::vector Ns; // for (int n : ns) { // double err = solve(mon, ss, n, w); // prn(err); // errs.push_back(err); // Ns.push_back(N); // } // // HDF hdf("tmp.h5", HDF::DESTROY); // hdf.writeDoubleArray("errs", errs); // hdf.writeDoubleArray("Ns", Ns); // } } // namespace mm