From ec7e69538d0944d16b87537caff6c15b3cca8b16 Mon Sep 17 00:00:00 2001 From: Timo Koch <timo.koch@iws.uni-stuttgart.de> Date: Fri, 12 Jun 2020 14:50:23 +0200 Subject: [PATCH] [test] Add test for cylinder integration --- test/common/geometry/CMakeLists.txt | 1 + .../geometry/test_cylinderintegration.cc | 168 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 test/common/geometry/test_cylinderintegration.cc diff --git a/test/common/geometry/CMakeLists.txt b/test/common/geometry/CMakeLists.txt index 92ea708139..f1a6d093ce 100644 --- a/test/common/geometry/CMakeLists.txt +++ b/test/common/geometry/CMakeLists.txt @@ -9,6 +9,7 @@ dumux_add_test(SOURCES test_2d3d_intersection.cc LABELS unit) dumux_add_test(SOURCES test_graham_convex_hull.cc LABELS unit) dumux_add_test(SOURCES test_intersectingentity_cartesiangrid.cc LABELS unit) dumux_add_test(SOURCES test_circlepoints.cc LABELS unit) +dumux_add_test(SOURCES test_cylinderintegration.cc LABELS unit) dune_symlink_to_source_files(FILES ball.msh) dumux_add_test(SOURCES test_intersectionentityset.cc diff --git a/test/common/geometry/test_cylinderintegration.cc b/test/common/geometry/test_cylinderintegration.cc new file mode 100644 index 0000000000..f756c24dbb --- /dev/null +++ b/test/common/geometry/test_cylinderintegration.cc @@ -0,0 +1,168 @@ +#include <config.h> + +#include <iostream> +#include <iomanip> +#include <cmath> + +#include <dune/common/float_cmp.hh> +#include <dune/common/fvector.hh> +#include <dune/common/exceptions.hh> + +#include <dumux/common/math.hh> +#include <dumux/multidomain/embedded/cylinderintegration.hh> +#include "transformation.hh" + +namespace Dumux { + +template<class Scalar> +void checkVolumeIntegral(const Scalar volIntegralComputed, const Scalar volIntegralExact) +{ + std::cout << std::setprecision(7) << std::scientific + << "Volume integral: " << volIntegralComputed << " (computed), " + << volIntegralExact << " (exact)" << "\n"; + if (Dune::FloatCmp::ne(volIntegralComputed, volIntegralExact, 1e-7)) + DUNE_THROW(Dune::Exception, "Volume integral is not exact!"); +} + +template<class Scalar> +void checkAreaIntegral(const Scalar areaIntegralComputed, const Scalar areaIntegralExact) +{ + std::cout << std::setprecision(7) << std::scientific + << "Area integral: " << areaIntegralComputed << " (computed), " + << areaIntegralExact << " (exact)" << "\n"; + if (Dune::FloatCmp::ne(areaIntegralComputed, areaIntegralExact, 1e-7)) + DUNE_THROW(Dune::Exception, "Area integral is not exact!"); +} + +template<class GlobalPosition> +void checkCentroid(const GlobalPosition& centroidComputed, const GlobalPosition& centroidExact) +{ + std::cout << std::setprecision(7) << std::scientific + << "Centroid: " << centroidComputed << " (computed), " + << centroidExact << " (exact)" << "\n"; + if (Dune::FloatCmp::ne(centroidComputed, centroidExact, 1e-7)) + DUNE_THROW(Dune::Exception, "Centroid is wrong!"); +} + +template<class TestData> +void checkCylinderIntegration(const TestData& data, const double characteristicLength) +{ + using Point = typename TestData::Point; + + std::cout << std::endl; + EmbeddedCoupling::CylinderIntegration<double> cylinderIntegration(characteristicLength); + cylinderIntegration.setGeometry(data.bottomCenter, data.topCenter, data.radius, /*verbosity=*/1); + double volumeIntegral = 0.0; + Point centroid({0.0, 0.0, 0.0}); + for (std::size_t i = 0; i < cylinderIntegration.size(); ++i) + { + volumeIntegral += cylinderIntegration.integrationElement(i); + centroid.axpy(cylinderIntegration.integrationElement(i), cylinderIntegration.integrationPoint(i)); + } + centroid /= volumeIntegral; + + checkVolumeIntegral(volumeIntegral, data.exactVolumeIntegral); + checkCentroid(centroid, data.exactCentroid); +} + +template<class TestData, class EllipseData> +void checkEllipticCylinderIntegration(const TestData& data, const EllipseData& ell, const double characteristicLength) +{ + using Point = typename TestData::Point; + + std::cout << std::endl; + EmbeddedCoupling::EllipticCylinderIntegration<double> ellCylIntegration(characteristicLength); + ellCylIntegration.setGeometry(data.bottomCenter, data.topCenter, ell.firstAxis, ell.secondAxis, /*verbosity=*/1); + double volumeIntegral = 0.0; + Point centroid({0.0, 0.0, 0.0}); + for (std::size_t i = 0; i < ellCylIntegration.size(); ++i) + { + volumeIntegral += ellCylIntegration.integrationElement(i); + centroid.axpy(ellCylIntegration.integrationElement(i), ellCylIntegration.integrationPoint(i)); + } + centroid /= volumeIntegral; + + checkVolumeIntegral(volumeIntegral, data.exactVolumeIntegral); + checkCentroid(centroid, data.exactCentroid); + + // check top cap ellipse + std::cout << std::endl; + EmbeddedCoupling::EllipseIntegration<double> ellIntegration(characteristicLength); + ellIntegration.setGeometry(data.topCenter, ell.firstAxis, ell.secondAxis, /*verbosity=*/1); + double areaIntegral = 0.0; + Point topCentroid({0.0, 0.0, 0.0}); + for (std::size_t i = 0; i < ellIntegration.size(); ++i) + { + areaIntegral += ellIntegration.integrationElement(i); + topCentroid.axpy(ellIntegration.integrationElement(i), ellIntegration.integrationPoint(i)); + } + topCentroid /= areaIntegral; + + checkAreaIntegral(areaIntegral, ell.firstAxis.two_norm()*ell.secondAxis.two_norm()*M_PI); + checkCentroid(topCentroid, data.topCenter); +} + +} // end namespace Dumux + +int main(int argc, char* argv[]) +{ + using namespace Dumux; + using Point = Dune::FieldVector<double, 3>; + + struct TestData { + using Point = Dune::FieldVector<double, 3>; + Point bottomCenter, topCenter; + double radius; + double exactVolumeIntegral; + Point exactCentroid; + }; + + TestData data; + data.bottomCenter = Point({1.2, 2.3, 4.5}); + data.topCenter = Point({8.2, 4.3, 6.5}); + data.radius = 4.0; + data.exactVolumeIntegral = M_PI*data.radius*data.radius*(data.topCenter-data.bottomCenter).two_norm(); + data.exactCentroid = data.bottomCenter; data.exactCentroid.axpy(0.5, data.topCenter-data.bottomCenter); + + ///////////////////////////////////////////////////////////////////// + // Determine cylinder volume and centroid by integration + //////////////////////////////////////////////////////////////////// + checkCylinderIntegration(data, 0.05); + + ///////////////////////////////////////////////////////////////////// + // Determine elliptic cylinder volume and centroid by integration + // Construct an perfect cylinder (a == b == radius and orthogonal caps) + //////////////////////////////////////////////////////////////////// + struct EllipseData { Point firstAxis, secondAxis; }; + auto topNormal = data.topCenter-data.bottomCenter; topNormal /= topNormal.two_norm(); + auto firstAxis = crossProduct(topNormal, Point({1.0, 0.0, 0.0})); + firstAxis /= firstAxis.two_norm(); + auto secondAxis = crossProduct(topNormal, firstAxis); + // scale both axis with the same radius -> circle + firstAxis *= data.radius; secondAxis *= data.radius; + checkEllipticCylinderIntegration(data, EllipseData{firstAxis, secondAxis}, 0.05); + + ///////////////////////////////////////////////////////////////////// + // Determine elliptic cylinder volume and centroid by integration + // Construct an elliptic cylinder (a == 4*b and orthogonal caps) + //////////////////////////////////////////////////////////////////// + + firstAxis *= 2; secondAxis *= 0.5; + checkEllipticCylinderIntegration(data, EllipseData{firstAxis, secondAxis}, 0.025); + + ///////////////////////////////////////////////////////////////////// + // Determine elliptic cylinder volume and centroid by integration + // Construct an elliptic cylinder (a == 2*b and tilted caps) + //////////////////////////////////////////////////////////////////// + + // rotate about the first major axis + const auto rotationAngle = M_PI*0.25; + auto rotationAxis = firstAxis; rotationAxis /= rotationAxis.two_norm(); + const auto rotate = make3DTransformation(1.0, Point(0.0), rotationAxis, rotationAngle, /*verbose*/false); + secondAxis = rotate(secondAxis); + // scale second axis so that the volume stays the same as for the orthonal cap case + secondAxis /= std::cos(rotationAngle); + checkEllipticCylinderIntegration(data, EllipseData{firstAxis, secondAxis}, 0.025); + + return 0; +} -- GitLab