#include #include #include #include "gtest/gtest.h" namespace mm { TEST(Domains, BoxShapeBegEndSwitch) { BoxShape box1d({1.0}, {-1.0}); BoxShape box2d({1, -1}, {-1, 1}); BoxShape box3d({1, -1, 1}, {-1, 1, -1}); for (int i = 0; i < box1d.dim; ++i) { EXPECT_DOUBLE_EQ(box1d.beg()[i], -1); EXPECT_DOUBLE_EQ(box1d.end()[i], 1); } for (int i = 0; i < box2d.dim; ++i) { EXPECT_DOUBLE_EQ(box2d.beg()[i], -1); EXPECT_DOUBLE_EQ(box2d.end()[i], 1); } for (int i = 0; i < box2d.dim; ++i) { EXPECT_DOUBLE_EQ(box2d.beg()[i], -1); EXPECT_DOUBLE_EQ(box2d.end()[i], 1); } } TEST(Domains, BoxShapeContainsBasic1D) { BoxShape box1d({1.0}, {2.0}); EXPECT_TRUE(box1d.contains({1.5})); EXPECT_TRUE(box1d.contains({1.01})); EXPECT_TRUE(box1d.contains({1.99})); EXPECT_TRUE(box1d.contains({1})); EXPECT_TRUE(box1d.contains({2})); EXPECT_TRUE(box1d.contains({1 - 1e-13})); EXPECT_TRUE(box1d.contains({2 + 1e-13})); EXPECT_FALSE(box1d.contains({3})); EXPECT_FALSE(box1d.contains({0})); EXPECT_FALSE(box1d.contains({-1})); } TEST(Domains, BoxShapeContainsBasic2D) { BoxShape box2d({1, 3}, {1.2, 3.5}); EXPECT_TRUE(box2d.contains({1.1, 3.4})); EXPECT_FALSE(box2d.contains({0.9, 3.4})); EXPECT_FALSE(box2d.contains({1.1, 2.3})); EXPECT_FALSE(box2d.contains({0.6, -1.4})); } TEST(Domains, BoxShapeContainsBasic3D) { BoxShape box3d({0, 1, 2}, {-1, 2, 3}); EXPECT_TRUE(box3d.contains({-0.5, 1.5, 2.5})); EXPECT_TRUE(box3d.contains({0, 1, 2})); EXPECT_FALSE(box3d.contains({-1.5, 1.5, 2.5})); EXPECT_FALSE(box3d.contains({-0.5, 2.5, 2.5})); EXPECT_FALSE(box3d.contains({-0.5, 1.5, 3.5})); } template void testRectangleNormals(const DomainDiscretization& discretization, const BoxShape& domain) { double tol = 1e-15; for (int i : discretization.types() < 0) { int on_bnd = 0; for (int j = 0; j < discretization.dim; ++j) { if (std::abs(discretization.positions()[i][j] - domain.beg()[j]) < tol) on_bnd++; if (std::abs(discretization.positions()[i][j] - domain.end()[j]) < tol) on_bnd++; } if (on_bnd == 1) { // uniquely defined normal for (int j = 0; j < discretization.dim; ++j) { if (std::abs(discretization.positions()[i][j] - domain.beg()[j]) < tol) { EXPECT_EQ(-1, discretization.normal(i)[j]); } else if (std::abs(discretization.positions()[i][j] - domain.end()[j]) < tol) { EXPECT_EQ(1, discretization.normal(i)[j]); } else { EXPECT_EQ(0, discretization.normal(i)[j]); } } } } } TEST(Domains, BoxShapeNormalsUniform) { BoxShape domain1d({1}, {2}); auto discretization1d = domain1d.discretizeBoundary({3}); testRectangleNormals(discretization1d, domain1d); BoxShape domain2d({1, 3}, {1.2, 3.5}); auto discretization2d = domain2d.discretizeBoundary({3, 3}); testRectangleNormals(discretization2d, domain2d); BoxShape domain3d({0, 1, 2}, {-1, 2, 3}); auto discretization3d = domain3d.discretizeBoundary({3, 3, 3}); testRectangleNormals(discretization3d, domain3d); } TEST(Domains, BoxShapeleNormalsRandom) { BoxShape domain1d({1}, {2}); auto discretization1d = domain1d.discretizeWithStep(0.1); testRectangleNormals(discretization1d, domain1d); BoxShape domain2d({1, 3}, {1.2, 3.5}); auto discretization2d = domain2d.discretizeWithStep(0.1); testRectangleNormals(discretization2d, domain2d); BoxShape domain3d({0, 1, 2}, {-1, 2, 3}); auto discretization3d = domain3d.discretizeWithStep(0.1); testRectangleNormals(discretization3d, domain3d); } TEST(Domains, BoxDiscretize1d) { BoxShape shape({-1.2}, {-0.4}); auto d = shape.discretizeWithStep(0.1); Range internal = d.positions()[d.interior()]; std::sort(internal.begin(), internal.end()); Range expected = {-1.1, -1, -0.9, -0.8, -0.7, -0.6, -0.5}; double tol = 1e-15; ASSERT_EQ(expected.size(), internal.size()); int n = expected.size(); for (int i = 0; i < n; ++i) { EXPECT_NEAR(expected[i], internal[i][0], tol); } } TEST(Domains, BoxDiscretize2d) { BoxShape shape({1, 3}, {1.4, 3.5}); auto d = shape.discretizeWithStep(0.1); Range internal = d.positions()[d.interior()]; std::sort(internal.begin(), internal.end()); Range expected = {{1.1, 3.1}, {1.1, 3.2}, {1.1, 3.3}, {1.1, 3.4}, {1.2, 3.1}, {1.2, 3.2}, {1.2, 3.3}, {1.2, 3.4}, {1.3, 3.1}, {1.3, 3.2}, {1.3, 3.3}, {1.3, 3.4}}; double tol = 1e-15; ASSERT_EQ(expected.size(), internal.size()); int n = expected.size(); for (int i = 0; i < n; ++i) { EXPECT_NEAR(expected[i][0], internal[i][0], tol); EXPECT_NEAR(expected[i][1], internal[i][1], tol); } } TEST(Domains, BoxDiscretize3d) { BoxShape shape({1, 3, -2.4}, {1.4, 3.5, -2.6+1e-15}); auto d = shape.discretizeWithStep(0.1); Range internal = d.positions()[d.interior()]; std::sort(internal.begin(), internal.end()); Range expected = {{1.1, 3.1, -2.5}, {1.1, 3.2, -2.5}, {1.1, 3.3, -2.5}, {1.1, 3.4, -2.5}, {1.2, 3.1, -2.5}, {1.2, 3.2, -2.5}, {1.2, 3.3, -2.5}, {1.2, 3.4, -2.5}, {1.3, 3.1, -2.5}, {1.3, 3.2, -2.5}, {1.3, 3.3, -2.5}, {1.3, 3.4, -2.5}}; double tol = 1e-15; ASSERT_EQ(expected.size(), internal.size()); int n = expected.size(); for (int i = 0; i < n; ++i) { EXPECT_NEAR(expected[i][0], internal[i][0], tol); EXPECT_NEAR(expected[i][1], internal[i][1], tol); EXPECT_NEAR(expected[i][2], internal[i][2], tol); } } TEST(Domains, BoxDiscretizeBoundary3d) { BoxShape domain3d(0, 1); double dx = 0.05; double tol = 0.05; double s = 0; double c = 0; auto discretization3d = domain3d.discretizeBoundaryWithStep(dx); KDTree tree(discretization3d.positions()); for (int i = 0; i < discretization3d.size(); ++i) { Range distances2 = std::get<1>(tree.query(discretization3d.pos(i), 2)); s += std::sqrt(distances2[1]); c += 1; } EXPECT_NEAR(dx, s/c, dx*tol); // 5% error tolerance } TEST(Domains, BoxDiscretizeBoundaryWithDensity2d) { BoxShape domain2d(0, 1); double dx1 = 0.05; double dx2 = 0.01; double tol = 0.05; double s1 = 0; double c1 = 0; double s2 = 0; double c2 = 0; auto fill = [=](const Vec2d& p) { return (p[0] < 0.5) ? dx1 : dx2; }; auto discretization2d = domain2d.discretizeBoundaryWithDensity(fill); KDTree tree(discretization2d.positions()); for (int i = 0; i < discretization2d.size(); ++i) { if (discretization2d.pos(i, 0) < 0.5 - tol) { Range distances2 = std::get<1>(tree.query(discretization2d.pos(i), 2)); s1 += std::sqrt(distances2[1]); c1 += 1; } else if (discretization2d.pos(i, 0) > 0.5 + tol) { Range distances2 = std::get<1>(tree.query(discretization2d.pos(i), 2)); s2 += std::sqrt(distances2[1]); c2 += 1; } } EXPECT_NEAR(dx1, s1/c1, dx1*tol); // 5% error tolerance EXPECT_NEAR(dx2, s2/c2, dx2*tol); } TEST(Domains, BoxDiscretizeBoundaryWithDensity3d) { BoxShape domain3d(0, 1); double dx1 = 0.05; double dx2 = 0.11; double tol = 0.05; double s1 = 0; double c1 = 0; double s2 = 0; double c2 = 0; auto fill = [=](const Vec3d& p) { return (p[0] < 0.5) ? dx1 : dx2; }; auto discretization3d = domain3d.discretizeBoundaryWithDensity(fill); KDTree tree(discretization3d.positions()); for (int i = 0; i < discretization3d.size(); ++i) { if (discretization3d.pos(i, 0) < 0.5 - tol) { Range distances2 = std::get<1>(tree.query(discretization3d.pos(i), 2)); s1 += std::sqrt(distances2[1]); c1 += 1; } else if (discretization3d.pos(i, 0) > 0.5 + tol) { Range distances2 = std::get<1>(tree.query(discretization3d.pos(i), 2)); s2 += std::sqrt(distances2[1]); c2 += 1; } } EXPECT_NEAR(dx1, s1/c1, dx1*tol); // 5% error tolerance EXPECT_NEAR(dx2, s2/c2, dx2*tol); } TEST(Domains, DISABLED_BoxShapeUsageExample) { /// [BoxShape usage example] BoxShape box({0, 0.3, -0.1}, {1, 2, 5}); if (box.contains({0.5, 1.3, 3.4})) { // do something } auto d = box.discretizeWithStep(0.1); std::cout << box << std::endl; /// [BoxShape usage example] (void) d; // remove unused warning } } // namespace mm