From 7bf9e339d6f680d7aaf9fddc812a6dc969e56d80 Mon Sep 17 00:00:00 2001
From: Timo Koch <timo.koch@iws.uni-stuttgart.de>
Date: Sat, 4 Apr 2020 19:22:33 +0200
Subject: [PATCH] [test][0d3d] Run intersection test with various
 transformations

---
 .../common/geometry/test_0d3d_intersection.cc | 98 +++++++++++++------
 1 file changed, 69 insertions(+), 29 deletions(-)

diff --git a/test/common/geometry/test_0d3d_intersection.cc b/test/common/geometry/test_0d3d_intersection.cc
index 5bff2e0698..16c4899888 100644
--- a/test/common/geometry/test_0d3d_intersection.cc
+++ b/test/common/geometry/test_0d3d_intersection.cc
@@ -3,7 +3,9 @@
 #include <iostream>
 #include <algorithm>
 #include <functional>
+#include <type_traits>
 
+#include <dune/common/classname.hh>
 #include <dune/common/exceptions.hh>
 #include <dune/common/fvector.hh>
 #include <dune/geometry/type.hh>
@@ -16,28 +18,42 @@
 template<class Geometry>
 bool testIntersection(const Geometry& geo,
                       const typename Geometry::GlobalCoordinate& p,
-                      bool foundExpected)
+                      bool foundExpected, bool verbose)
 {
     bool found = Dumux::intersectsPointGeometry(p, geo);
     if (!found && foundExpected)
-        std::cerr << "  Failed detecting intersection with " << p << std::endl;
-    else if (found && foundExpected)
-        std::cout << "  Found intersection with " << p << std::endl;
+    {
+        std::cerr << "  Failed detecting intersection of " << geo.type();
+        for (int i = 0; i < geo.corners(); ++i)
+            std::cerr << " (" << geo.corner(i) << ")";
+        std::cerr << " with point: " << p << std::endl;
+    }
     else if (found && !foundExpected)
-        std::cerr << "  Found false positive: intersection with " << p << std::endl;
-    else if (!found && !foundExpected)
-        std::cout << "  No intersection with " << p << std::endl;
+    {
+        std::cerr << "  Found false positive: intersection of " << geo.type();
+        for (int i = 0; i < geo.corners(); ++i)
+            std::cerr << " (" << geo.corner(i) << ")";
+        std::cerr << " with point: " << p << std::endl;
+    }
+    if (verbose)
+    {
+        if (found && foundExpected)
+            std::cout << "  Found intersection with " << p << std::endl;
+        else if (!found && !foundExpected)
+            std::cout << "  No intersection with " << p << std::endl;
+    }
     return (found == foundExpected);
 }
 
-template<class ctype, class Transformation>
-void runTest(std::vector<bool>& returns, const Transformation& transform)
+template<class Transformation>
+void runIntersectionTest(std::vector<bool>& returns, const Transformation& transform, bool verbose)
 {
+    using ctype = typename std::decay_t<decltype(transform({0.0}))>::value_type;
     using Geo = Dune::MultiLinearGeometry<ctype, 3, 3>;
     using Points = std::vector<typename Geo::GlobalCoordinate>;
 
     // test tetrahedron-point intersections
-    std::cout << "\n  -- Test tetrahedron-point intersections" << std::endl;
+    if (verbose) std::cout << "\n  -- Test tetrahedron-point intersections" << std::endl;
 
     auto cornersTet = Points({{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}});
     std::transform(cornersTet.begin(), cornersTet.end(), cornersTet.begin(),
@@ -45,15 +61,15 @@ void runTest(std::vector<bool>& returns, const Transformation& transform)
     const auto tetrahedron = Geo(Dune::GeometryTypes::tetrahedron, cornersTet);
 
     for (const auto& corner : cornersTet)
-        returns.push_back(testIntersection(tetrahedron, corner, true));
-    returns.push_back(testIntersection(tetrahedron, transform({0.0, 0.0, 0.5}), true));
-    returns.push_back(testIntersection(tetrahedron, transform({0.25, 0.25, 0.5}), true));
-    returns.push_back(testIntersection(tetrahedron, transform({0.5, 0.5, 0.5}), false));
-    returns.push_back(testIntersection(tetrahedron, transform({1.01, 0.0, 0.0}), false));
-    returns.push_back(testIntersection(tetrahedron, transform({0.5, 0.0, 0.51}), false));
+        returns.push_back(testIntersection(tetrahedron, corner, true, verbose));
+    returns.push_back(testIntersection(tetrahedron, transform({0.0, 0.0, 0.5}), true, verbose));
+    returns.push_back(testIntersection(tetrahedron, transform({0.25, 0.25, 0.5}), true, verbose));
+    returns.push_back(testIntersection(tetrahedron, transform({0.5, 0.5, 0.5}), false, verbose));
+    returns.push_back(testIntersection(tetrahedron, transform({1.01, 0.0, 0.0}), false, verbose));
+    returns.push_back(testIntersection(tetrahedron, transform({0.5, 0.0, 0.51}), false, verbose));
 
     // test hexahedron-point intersections
-    std::cout << "\n  -- Test hexahedron-point intersections" << std::endl;
+    if (verbose) std::cout << "\n  -- Test hexahedron-point intersections" << std::endl;
 
     auto cornersHex = Points({{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0},
                               {0.0, 0.0, 1.0}, {1.0, 0.0, 1.0}, {0.0, 1.0, 1.0}, {1.0, 1.0, 1.0}});
@@ -62,10 +78,15 @@ void runTest(std::vector<bool>& returns, const Transformation& transform)
     auto hexahedron = Geo(Dune::GeometryTypes::hexahedron, cornersHex);
 
     for (const auto& corner : cornersHex)
-        returns.push_back(testIntersection(hexahedron, corner, true));
+        returns.push_back(testIntersection(hexahedron, corner, true, verbose));
+    returns.push_back(testIntersection(hexahedron, transform({0.5, 0.5, 0.5}), true, verbose));
+    returns.push_back(testIntersection(hexahedron, transform({0.01, 0.01, 0.0001}), true, verbose));
+    returns.push_back(testIntersection(hexahedron, transform({1.01, 0.5, 0.5}), false, verbose));
+    returns.push_back(testIntersection(hexahedron, transform({2.0, 2.0, 2.0}), false, verbose));
+    returns.push_back(testIntersection(hexahedron, transform({-0.5, -0.0, -0.51}), false, verbose));
 
     // test pyramid-point intersections
-    std::cout << "\n  -- Test pyramid-point intersections" << std::endl;
+    if (verbose) std::cout << "\n  -- Test pyramid-point intersections" << std::endl;
 
     auto cornersPyramid = Points({{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0},
                                   {1.0, 1.0, 0.0}, {0.5, 0.5, 1.0}});
@@ -74,10 +95,18 @@ void runTest(std::vector<bool>& returns, const Transformation& transform)
     auto pyramid = Geo(Dune::GeometryTypes::pyramid, cornersPyramid);
 
     for (const auto& corner : cornersPyramid)
-        returns.push_back(testIntersection(pyramid, corner, true));
+        returns.push_back(testIntersection(pyramid, corner, true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.5, 0.5, 0.0}), true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.5, 0.5, 0.7}), true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.5, 0.5, -0.0001}), false, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.25, 0.25, 0.5}), true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.25, 0.75, 0.5}), true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.75, 0.75, 0.5}), true, verbose));
+    returns.push_back(testIntersection(pyramid, transform({0.25, 0.25, 0.5001}), false, verbose));
+    returns.push_back(testIntersection(pyramid, transform({1.0, 1.0, 0.0001}), false, verbose));
 
     // test prism-point intersections
-    std::cout << "\n  -- Test prism-point intersections" << std::endl;
+    if (verbose) std::cout << "\n  -- Test prism-point intersections" << std::endl;
 
     auto cornersPrism = Points({{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0},
                                 {0.0, 0.0, 1.0}, {1.0, 0.0, 1.0}, {0.0, 1.0, 1.0}});
@@ -86,7 +115,13 @@ void runTest(std::vector<bool>& returns, const Transformation& transform)
     auto prism = Geo(Dune::GeometryTypes::prism, cornersPrism);
 
     for (const auto& corner : cornersPrism)
-        returns.push_back(testIntersection(prism, corner, true));
+        returns.push_back(testIntersection(prism, corner, true, verbose));
+    returns.push_back(testIntersection(prism, transform({0.25, 0.0, 0.25}), true, verbose));
+    returns.push_back(testIntersection(prism, transform({0.0, 0.25, 0.25}), true, verbose));
+    returns.push_back(testIntersection(prism, transform({0.25, 0.25, 1.0}), true, verbose));
+    returns.push_back(testIntersection(prism, transform({0.25, 0.25, 0.0}), true, verbose));
+    returns.push_back(testIntersection(prism, transform({0.25, 0.25, -0.0001}), false, verbose));
+    returns.push_back(testIntersection(prism, transform({0.25, 0.25, 1.0001}), false, verbose));
 }
 
 template<class ctype>
@@ -95,8 +130,9 @@ auto createTransformation(const ctype scale,
                           const Dune::FieldVector<ctype, 3>& rotationAxis,
                           const ctype rotationAngle)
 {
-    std::cout << "\n\n Created transformation with"
-              << " scaling: " << scale
+    std::cout << "Intersection test with transformation:"
+              << " ctype: " << Dune::className<ctype>()
+              << ", scaling: " << scale
               << ", translation: " << translate
               << ", rotationAxis: " << rotationAxis
               << ", rotationAngle: " << rotationAngle << std::endl;
@@ -104,25 +140,29 @@ auto createTransformation(const ctype scale,
     const ctype cosAngle = std::cos(rotationAngle);
     return [=](Dune::FieldVector<ctype, 3> p){
         p *= scale;
-        p += translate;
+        p.axpy(scale, translate);
         auto tp = p;
         tp *= cosAngle;
         tp.axpy(sinAngle, Dumux::crossProduct(rotationAxis, p));
         return tp.axpy((1.0-cosAngle)*(rotationAxis*p), rotationAxis);
     };
 }
+
 #endif
 
 int main (int argc, char *argv[]) try
 {
     // collect returns to determine exit code
     std::vector<bool> returns;
+    constexpr bool verbose = false;
 
+    using Vec = Dune::FieldVector<double, 3>;
     for (const double scaling : {1.0, 1e3, 1e12, 1e-12})
-    {
-        const auto transform = createTransformation(scaling, {0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, 0.0);
-        runTest<double>(returns, transform);
-    }
+        for (const double translation : {0.0, 1.0})
+            for (const double angle : {0.0, 0.2*M_PI, 0.5*M_PI, 0.567576567*M_PI, M_PI})
+                for (const auto& rotAxis : {Vec(std::sqrt(3.0)/3.0), Vec({std::sqrt(2.0)/2.0, std::sqrt(2.0)/2.0, 0.0})})
+                    runIntersectionTest(returns,
+                        createTransformation<double>(scaling, Vec(translation), rotAxis, angle), verbose);
 
     // determine the exit code
     if (std::any_of(returns.begin(), returns.end(), std::logical_not<bool>{}))
-- 
GitLab