diff --git a/src/geometry/AffineTransformation.hpp b/src/geometry/AffineTransformation.hpp deleted file mode 100644 index ed5a5509b39a6439eea197058d1d69df439b6768..0000000000000000000000000000000000000000 --- a/src/geometry/AffineTransformation.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef AFFINE_TRANSFORMATION_HPP -#define AFFINE_TRANSFORMATION_HPP - -#include <algebra/TinyMatrix.hpp> -#include <algebra/TinyVector.hpp> - -#include <array> - -template <size_t Dimension> -class AffineTransformation -{ - private: - constexpr static size_t NumberOfPoints = Dimension + 1; - - TinyMatrix<Dimension> m_jacobian; - TinyVector<Dimension> m_shift; - double m_jacobian_determinant; - - public: - PUGS_INLINE - TinyVector<Dimension> - operator()(const TinyVector<Dimension>& x) const - { - return m_jacobian * x + m_shift; - } - - double - jacobianDeterminant() const - { - return m_jacobian_determinant; - } - - PUGS_INLINE - AffineTransformation(const std::array<TinyVector<Dimension>, NumberOfPoints>& image_nodes) - { - static_assert(Dimension >= 1 and Dimension <= 3, "invalid dimension"); - if constexpr (Dimension == 1) { - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - - m_jacobian(0, 0) = 0.5 * (b[0] - a[0]); - - m_shift[0] = 0.5 * (a[0] + b[0]); - } else if constexpr (Dimension == 2) { - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - - for (size_t i = 0; i < Dimension; ++i) { - m_jacobian(i, 0) = b[i] - a[i]; - m_jacobian(i, 1) = c[i] - a[i]; - } - - m_shift = a; - } else { - static_assert(Dimension == 3); - - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - const TinyVector<Dimension>& d = image_nodes[3]; - - for (size_t i = 0; i < Dimension; ++i) { - m_jacobian(i, 0) = b[i] - a[i]; - m_jacobian(i, 1) = c[i] - a[i]; - m_jacobian(i, 2) = d[i] - a[i]; - } - - m_shift = a; - } - - m_jacobian_determinant = det(m_jacobian); - } - - ~AffineTransformation() = default; -}; - -#endif // AFFINE_TRANSFORMATION_HPP diff --git a/src/geometry/CubeTransformation.hpp b/src/geometry/CubeTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7bc12c324e4a55750b41b1584633cc789f8a7b2d --- /dev/null +++ b/src/geometry/CubeTransformation.hpp @@ -0,0 +1,79 @@ +#ifndef CUBE_TRANSFORMATION_HPP +#define CUBE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <array> + +class CubeTransformation +{ + public: + constexpr static size_t Dimension = 3; + constexpr static size_t NumberOfPoints = 8; + + private: + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + const TinyVector<NumberOfPoints - 1> X = + {x[0], x[1], x[2], x[0] * x[1], x[1] * x[2], x[0] * x[2], x[0] * x[1] * x[2]}; + return m_coefficients * X + m_shift; + } + + PUGS_INLINE double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + static_assert(Dimension == 3, "invalid dimension"); + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 3) * y + T(0, 5) * z + T(0, 6) * y * z, + T(0, 1) + T(0, 3) * x + T(0, 4) * z + T(0, 6) * x * z, + T(0, 2) + T(0, 4) * y + T(0, 5) * x + T(0, 6) * x * y, + // + T(1, 0) + T(1, 3) * y + T(1, 5) * z + T(1, 6) * y * z, + T(1, 1) + T(1, 3) * x + T(1, 4) * z + T(1, 6) * x * z, + T(1, 2) + T(1, 4) * y + T(1, 5) * x + T(1, 6) * x * y, + // + T(2, 0) + T(2, 3) * y + T(2, 5) * z + T(2, 6) * y * z, + T(2, 1) + T(2, 3) * x + T(2, 4) * z + T(2, 6) * x * z, + T(2, 2) + T(2, 4) * y + T(2, 5) * x + T(2, 6) * x * y}; + + return det(J); + } + + PUGS_INLINE + CubeTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e, + const TinyVector<Dimension>& f, + const TinyVector<Dimension>& g, + const TinyVector<Dimension>& h) + { + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.125 * (-a[i] + b[i] + c[i] - d[i] - e[i] + f[i] + g[i] - h[i]); + m_coefficients(i, 1) = 0.125 * (-a[i] - b[i] + c[i] + d[i] - e[i] - f[i] + g[i] + h[i]); + m_coefficients(i, 2) = 0.125 * (-a[i] - b[i] - c[i] - d[i] + e[i] + f[i] + g[i] + h[i]); + m_coefficients(i, 3) = 0.125 * (+a[i] - b[i] + c[i] - d[i] + e[i] - f[i] + g[i] - h[i]); + m_coefficients(i, 4) = 0.125 * (+a[i] + b[i] - c[i] - d[i] - e[i] - f[i] + g[i] + h[i]); + m_coefficients(i, 5) = 0.125 * (+a[i] - b[i] - c[i] + d[i] - e[i] + f[i] + g[i] - h[i]); + m_coefficients(i, 6) = 0.125 * (-a[i] + b[i] - c[i] + d[i] + e[i] - f[i] + g[i] - h[i]); + + m_shift[i] = 0.125 * (a[i] + b[i] + c[i] + d[i] + e[i] + f[i] + g[i] + h[i]); + } + } + + ~CubeTransformation() = default; +}; + +#endif // CUBE_TRANSFORMATION_HPP diff --git a/src/geometry/LineTransformation.hpp b/src/geometry/LineTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..641821809f583e007851c259e959584fbcc2e48c --- /dev/null +++ b/src/geometry/LineTransformation.hpp @@ -0,0 +1,40 @@ +#ifndef LINE_TRANSFORMATION_HPP +#define LINE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class LineTransformation +{ + public: + constexpr static size_t Dimension = 1; + + private: + TinyMatrix<Dimension> m_jacobian; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<1>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian(0, 0); + } + + PUGS_INLINE + LineTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b) + { + m_jacobian(0, 0) = 0.5 * (b[0] - a[0]); + m_shift[0] = 0.5 * (a[0] + b[0]); + } + + ~LineTransformation() = default; +}; + +#endif // LINE_TRANSFORMATION_HPP diff --git a/src/geometry/PrismTransformation.hpp b/src/geometry/PrismTransformation.hpp index 730710bba373584d4c21c8e3dfbedf20a62e96b9..5e6e509ed0c92023b81ea13a3e686392dec52fcd 100644 --- a/src/geometry/PrismTransformation.hpp +++ b/src/geometry/PrismTransformation.hpp @@ -4,8 +4,6 @@ #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> -#include <array> - class PrismTransformation { private: @@ -47,17 +45,15 @@ class PrismTransformation } PUGS_INLINE - PrismTransformation(const std::array<TinyVector<Dimension>, NumberOfPoints>& image_nodes) + PrismTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e, + const TinyVector<Dimension>& f) { static_assert(Dimension == 3, "invalid dimension"); - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - const TinyVector<Dimension>& d = image_nodes[3]; - const TinyVector<Dimension>& e = image_nodes[4]; - const TinyVector<Dimension>& f = image_nodes[5]; - for (size_t i = 0; i < Dimension; ++i) { m_coefficients(i, 0) = 0.5 * (b[i] - a[i] + e[i] - d[i]); m_coefficients(i, 1) = 0.5 * (c[i] + f[i] - a[i] - d[i]); diff --git a/src/geometry/PyramidTransformation.hpp b/src/geometry/PyramidTransformation.hpp index 19e7822ba3bc3e01da7be2840522e24707b68007..2fa3eaa8d8b010dda5ac3d591b1183db707ea3f8 100644 --- a/src/geometry/PyramidTransformation.hpp +++ b/src/geometry/PyramidTransformation.hpp @@ -4,8 +4,6 @@ #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> -#include <array> - class PyramidTransformation { private: @@ -46,16 +44,14 @@ class PyramidTransformation } PUGS_INLINE - PyramidTransformation(const std::array<TinyVector<Dimension>, NumberOfPoints>& image_nodes) + PyramidTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d, + const TinyVector<Dimension>& e) { static_assert(Dimension == 3, "invalid dimension"); - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - const TinyVector<Dimension>& d = image_nodes[3]; - const TinyVector<Dimension>& e = image_nodes[4]; - m_shift = 0.25 * (a + b + c + d); for (size_t i = 0; i < Dimension; ++i) { diff --git a/src/geometry/Q1Transformation.hpp b/src/geometry/Q1Transformation.hpp deleted file mode 100644 index 55e87bcbb11fede5993e8f0bb8f9a19881b76352..0000000000000000000000000000000000000000 --- a/src/geometry/Q1Transformation.hpp +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef Q1_TRANSFORMATION_HPP -#define Q1_TRANSFORMATION_HPP - -#include <algebra/TinyMatrix.hpp> -#include <algebra/TinyVector.hpp> - -#include <array> - -template <size_t Dimension> -class Q1Transformation -{ - private: - constexpr static size_t NumberOfPoints = 1 << Dimension; - - TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; - TinyVector<Dimension> m_shift; - - public: - PUGS_INLINE - TinyVector<Dimension> - operator()(const TinyVector<Dimension>& x) const - { - if constexpr (Dimension == 1) { - return m_coefficients * x + m_shift; - } else if constexpr (Dimension == 2) { - const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[0] * x[1]}; - return m_coefficients * X + m_shift; - } else { - static_assert(Dimension == 3, "invalid dimension"); - const TinyVector<NumberOfPoints - 1> X = - {x[0], x[1], x[2], x[0] * x[1], x[1] * x[2], x[0] * x[2], x[0] * x[1] * x[2]}; - return m_coefficients * X + m_shift; - } - } - - PUGS_INLINE double - jacobianDeterminant([[maybe_unused]] const TinyVector<Dimension>& X) const - { - if constexpr (Dimension == 1) { - return m_coefficients(0, 0); - } else if constexpr (Dimension == 2) { - const auto& T = m_coefficients; - const double& x = X[0]; - const double& y = X[1]; - - const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 2) * y, // - T(0, 1) + T(0, 2) * x, - // - T(1, 0) + T(1, 2) * y, // - T(1, 1) + T(1, 2) * x}; - return det(J); - } else { - static_assert(Dimension == 3, "invalid dimension"); - const auto& T = m_coefficients; - const double& x = X[0]; - const double& y = X[1]; - const double& z = X[2]; - - const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 3) * y + T(0, 5) * z + T(0, 6) * y * z, - T(0, 1) + T(0, 3) * x + T(0, 4) * z + T(0, 6) * x * z, - T(0, 2) + T(0, 4) * y + T(0, 5) * x + T(0, 6) * x * y, - // - T(1, 0) + T(1, 3) * y + T(1, 5) * z + T(1, 6) * y * z, - T(1, 1) + T(1, 3) * x + T(1, 4) * z + T(1, 6) * x * z, - T(1, 2) + T(1, 4) * y + T(1, 5) * x + T(1, 6) * x * y, - // - T(2, 0) + T(2, 3) * y + T(2, 5) * z + T(2, 6) * y * z, - T(2, 1) + T(2, 3) * x + T(2, 4) * z + T(2, 6) * x * z, - T(2, 2) + T(2, 4) * y + T(2, 5) * x + T(2, 6) * x * y}; - - return det(J); - } - } - - PUGS_INLINE - Q1Transformation(const std::array<TinyVector<Dimension>, NumberOfPoints>& image_nodes) - { - static_assert(Dimension >= 1 and Dimension <= 3, "invalid dimension"); - if constexpr (Dimension == 1) { - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - - m_coefficients(0, 0) = 0.5 * (b[0] - a[0]); - - m_shift[0] = 0.5 * (a[0] + b[0]); - } else if constexpr (Dimension == 2) { - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - const TinyVector<Dimension>& d = image_nodes[3]; - - for (size_t i = 0; i < Dimension; ++i) { - m_coefficients(i, 0) = 0.25 * (-a[i] + b[i] + c[i] - d[i]); - m_coefficients(i, 1) = 0.25 * (-a[i] - b[i] + c[i] + d[i]); - m_coefficients(i, 2) = 0.25 * (+a[i] - b[i] + c[i] - d[i]); - - m_shift[i] = 0.25 * (a[i] + b[i] + c[i] + d[i]); - } - } else { - static_assert(Dimension == 3); - - const TinyVector<Dimension>& a = image_nodes[0]; - const TinyVector<Dimension>& b = image_nodes[1]; - const TinyVector<Dimension>& c = image_nodes[2]; - const TinyVector<Dimension>& d = image_nodes[3]; - const TinyVector<Dimension>& e = image_nodes[4]; - const TinyVector<Dimension>& f = image_nodes[5]; - const TinyVector<Dimension>& g = image_nodes[6]; - const TinyVector<Dimension>& h = image_nodes[7]; - - for (size_t i = 0; i < Dimension; ++i) { - m_coefficients(i, 0) = 0.125 * (-a[i] + b[i] + c[i] - d[i] - e[i] + f[i] + g[i] - h[i]); - m_coefficients(i, 1) = 0.125 * (-a[i] - b[i] + c[i] + d[i] - e[i] - f[i] + g[i] + h[i]); - m_coefficients(i, 2) = 0.125 * (-a[i] - b[i] - c[i] - d[i] + e[i] + f[i] + g[i] + h[i]); - m_coefficients(i, 3) = 0.125 * (+a[i] - b[i] + c[i] - d[i] + e[i] - f[i] + g[i] - h[i]); - m_coefficients(i, 4) = 0.125 * (+a[i] + b[i] - c[i] - d[i] - e[i] - f[i] + g[i] + h[i]); - m_coefficients(i, 5) = 0.125 * (+a[i] - b[i] - c[i] + d[i] - e[i] + f[i] + g[i] - h[i]); - m_coefficients(i, 6) = 0.125 * (-a[i] + b[i] - c[i] + d[i] + e[i] - f[i] + g[i] - h[i]); - - m_shift[i] = 0.125 * (a[i] + b[i] + c[i] + d[i] + e[i] + f[i] + g[i] + h[i]); - } - } - } - - ~Q1Transformation() = default; -}; - -#endif // Q1_TRANSFORMATION_HPP diff --git a/src/geometry/SquareTransformation.hpp b/src/geometry/SquareTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d2906bb514fe90137f7270404c2f5b5f54d24a2 --- /dev/null +++ b/src/geometry/SquareTransformation.hpp @@ -0,0 +1,61 @@ +#ifndef SQUARE_TRANSFORMATION_HPP +#define SQUARE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <array> + +class SquareTransformation +{ + public: + constexpr static size_t Dimension = 2; + constexpr static size_t NumberOfPoints = 4; + + private: + TinyMatrix<Dimension, NumberOfPoints - 1> m_coefficients; + TinyVector<Dimension> m_shift; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + const TinyVector<NumberOfPoints - 1> X = {x[0], x[1], x[0] * x[1]}; + return m_coefficients * X + m_shift; + } + + PUGS_INLINE double + jacobianDeterminant(const TinyVector<Dimension>& X) const + { + const auto& T = m_coefficients; + const double& x = X[0]; + const double& y = X[1]; + + const TinyMatrix<Dimension, Dimension> J = {T(0, 0) + T(0, 2) * y, // + T(0, 1) + T(0, 2) * x, + // + T(1, 0) + T(1, 2) * y, // + T(1, 1) + T(1, 2) * x}; + return det(J); + } + + PUGS_INLINE + SquareTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d) + { + for (size_t i = 0; i < Dimension; ++i) { + m_coefficients(i, 0) = 0.25 * (-a[i] + b[i] + c[i] - d[i]); + m_coefficients(i, 1) = 0.25 * (-a[i] - b[i] + c[i] + d[i]); + m_coefficients(i, 2) = 0.25 * (+a[i] - b[i] + c[i] - d[i]); + + m_shift[i] = 0.25 * (a[i] + b[i] + c[i] + d[i]); + } + } + + ~SquareTransformation() = default; +}; + +#endif // SQUARE_TRANSFORMATION_HPP diff --git a/src/geometry/TetrahedronTransformation.hpp b/src/geometry/TetrahedronTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..64244266957a350e8be8f78c2eab3d5fead629e1 --- /dev/null +++ b/src/geometry/TetrahedronTransformation.hpp @@ -0,0 +1,53 @@ +#ifndef TETRAHEDRON_TRANSFORMATION_HPP +#define TETRAHEDRON_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class TetrahedronTransformation +{ + public: + constexpr static size_t Dimension = 3; + + private: + constexpr static size_t NumberOfPoints = Dimension + 1; + + TinyMatrix<Dimension> m_jacobian; + TinyVector<Dimension> m_shift; + double m_jacobian_determinant; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<Dimension>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian_determinant; + } + + PUGS_INLINE + TetrahedronTransformation(const TinyVector<Dimension>& a, + const TinyVector<Dimension>& b, + const TinyVector<Dimension>& c, + const TinyVector<Dimension>& d) + { + for (size_t i = 0; i < Dimension; ++i) { + m_jacobian(i, 0) = b[i] - a[i]; + m_jacobian(i, 1) = c[i] - a[i]; + m_jacobian(i, 2) = d[i] - a[i]; + } + + m_shift = a; + + m_jacobian_determinant = det(m_jacobian); + } + + ~TetrahedronTransformation() = default; +}; + +#endif // TETRAHEDRON_TRANSFORMATION_HPP diff --git a/src/geometry/TriangleTransformation.hpp b/src/geometry/TriangleTransformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9053912b8057c6d1c2e0ba8227a9f889bb1fc8f4 --- /dev/null +++ b/src/geometry/TriangleTransformation.hpp @@ -0,0 +1,47 @@ +#ifndef TRIANGLE_TRANSFORMATION_HPP +#define TRIANGLE_TRANSFORMATION_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +class TriangleTransformation +{ + public: + constexpr static size_t Dimension = 2; + + private: + TinyMatrix<Dimension> m_jacobian; + TinyVector<Dimension> m_shift; + double m_jacobian_determinant; + + public: + PUGS_INLINE + TinyVector<Dimension> + operator()(const TinyVector<2>& x) const + { + return m_jacobian * x + m_shift; + } + + double + jacobianDeterminant() const + { + return m_jacobian_determinant; + } + + PUGS_INLINE + TriangleTransformation(const TinyVector<Dimension>& a, const TinyVector<Dimension>& b, const TinyVector<Dimension>& c) + { + for (size_t i = 0; i < Dimension; ++i) { + m_jacobian(i, 0) = b[i] - a[i]; + m_jacobian(i, 1) = c[i] - a[i]; + } + + m_shift = a; + + m_jacobian_determinant = det(m_jacobian); + } + + ~TriangleTransformation() = default; +}; + +#endif // TRIANGLE_TRANSFORMATION_HPP diff --git a/src/language/utils/IntegrateOnCells.hpp b/src/language/utils/IntegrateOnCells.hpp index d4463da9647efc1877ba6df38e4042d17a76f168..7145c662bb5e294f4f1235bc51665f020fd8bd04 100644 --- a/src/language/utils/IntegrateOnCells.hpp +++ b/src/language/utils/IntegrateOnCells.hpp @@ -3,10 +3,13 @@ #include <analysis/IQuadratureDescriptor.hpp> #include <analysis/QuadratureManager.hpp> -#include <geometry/AffineTransformation.hpp> +#include <geometry/CubeTransformation.hpp> +#include <geometry/LineTransformation.hpp> #include <geometry/PrismTransformation.hpp> #include <geometry/PyramidTransformation.hpp> -#include <geometry/Q1Transformation.hpp> +#include <geometry/SquareTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> #include <language/utils/PugsFunctionAdapter.hpp> #include <mesh/CellType.hpp> #include <mesh/Connectivity.hpp> @@ -137,7 +140,7 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu if constexpr (Dimension == 1) { switch (cell_type[cell_id]) { case CellType::Line: { - const AffineTransformation<1> T({xr[cell_to_node[0]], xr[cell_to_node[1]]}); + const LineTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -155,8 +158,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } else if constexpr (Dimension == 2) { switch (cell_type[cell_id]) { case CellType::Triangle: { - const Q1Transformation<2> T( - {xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[2]]}); + const SquareTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -167,8 +170,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Quadrangle: { - const Q1Transformation<2> T( - {xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]]}); + const SquareTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -188,10 +191,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu switch (cell_type[cell_id]) { case CellType::Tetrahedron: { - const Q1Transformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], - xr[cell_to_node[2]], // - xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[3]], - xr[cell_to_node[3]]}); + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[3]], + xr[cell_to_node[3]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -203,10 +206,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } case CellType::Pyramid: { if (cell_to_node.size() == 5) { - const Q1Transformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // - xr[cell_to_node[3]], // - xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], - xr[cell_to_node[4]]}); + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -223,10 +226,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu case CellType::Diamond: { if (cell_to_node.size() == 5) { { // top tetrahedron - const Q1Transformation<3> T0({xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], - xr[cell_to_node[3]], // - xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], - xr[cell_to_node[4]]}); + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[3]], // + xr[cell_to_node[4]], xr[cell_to_node[4]], xr[cell_to_node[4]], + xr[cell_to_node[4]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -236,10 +239,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } } { // bottom tetrahedron - const Q1Transformation<3> T1({xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[2]], - xr[cell_to_node[1]], // - xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], - xr[cell_to_node[0]]}); + const CubeTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -250,10 +253,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } } else if (cell_to_node.size() == 6) { { // top pyramid - const Q1Transformation<3> T0({xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], - xr[cell_to_node[4]], // - xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], - xr[cell_to_node[5]]}); + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], + xr[cell_to_node[5]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -263,10 +266,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } } { // bottom pyramid - const Q1Transformation<3> T1({xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], - xr[cell_to_node[1]], // - xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], - xr[cell_to_node[0]]}); + const CubeTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -282,10 +285,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Prism: { - const Q1Transformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], // - xr[cell_to_node[2]], xr[cell_to_node[2]], // - xr[cell_to_node[3]], xr[cell_to_node[4]], // - xr[cell_to_node[5]], xr[cell_to_node[5]]}); + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -296,9 +299,9 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Hexahedron: { - const Q1Transformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], - xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]], - xr[cell_to_node[6]], xr[cell_to_node[7]]}); + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -377,7 +380,7 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu if constexpr (Dimension == 1) { switch (cell_type[cell_id]) { case CellType::Line: { - const AffineTransformation<1> T({xr[cell_to_node[0]], xr[cell_to_node[1]]}); + const LineTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]]); const auto qf = QuadratureManager::instance().getLineFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -396,7 +399,7 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } else if constexpr (Dimension == 2) { switch (cell_type[cell_id]) { case CellType::Triangle: { - const AffineTransformation<2> T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]]}); + const TriangleTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]]); const auto qf = QuadratureManager::instance().getTriangleFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -408,8 +411,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Quadrangle: { - const Q1Transformation<2> T( - {xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]]}); + const SquareTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]]); const auto qf = QuadratureManager::instance().getSquareFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -430,8 +433,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu switch (cell_type[cell_id]) { case CellType::Tetrahedron: { - const AffineTransformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], // - xr[cell_to_node[2]], xr[cell_to_node[3]]}); + const TetrahedronTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], // + xr[cell_to_node[2]], xr[cell_to_node[3]]); const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -444,8 +447,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } case CellType::Pyramid: { if (cell_to_node.size() == 5) { - const PyramidTransformation T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // - xr[cell_to_node[3]], xr[cell_to_node[4]]}); + const PyramidTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], // + xr[cell_to_node[3]], xr[cell_to_node[4]]); const auto qf = QuadratureManager::instance().getPyramidFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -463,8 +466,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu if (cell_to_node.size() == 5) { const auto qf = QuadratureManager::instance().getTetrahedronFormula(quadrature_descriptor); { // top tetrahedron - const AffineTransformation<3> T0({xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], // - xr[cell_to_node[4]]}); + const TetrahedronTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], // + xr[cell_to_node[4]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -474,8 +477,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } } { // bottom tetrahedron - const AffineTransformation<3> T1({xr[cell_to_node[3]], xr[cell_to_node[2]], xr[cell_to_node[1]], // - xr[cell_to_node[0]]}); + const TetrahedronTransformation T1(xr[cell_to_node[3]], xr[cell_to_node[2]], xr[cell_to_node[1]], // + xr[cell_to_node[0]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -487,10 +490,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } else if (cell_to_node.size() == 6) { const auto qf = QuadratureManager::instance().getCubeFormula(quadrature_descriptor); { // top pyramid - const Q1Transformation<3> T0({xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], - xr[cell_to_node[4]], // - xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], - xr[cell_to_node[5]]}); + const CubeTransformation T0(xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], // + xr[cell_to_node[5]], xr[cell_to_node[5]], xr[cell_to_node[5]], + xr[cell_to_node[5]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -500,10 +503,10 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu } } { // bottom pyramid - const Q1Transformation<3> T1({xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], - xr[cell_to_node[1]], // - xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], - xr[cell_to_node[0]]}); + const CubeTransformation T1(xr[cell_to_node[4]], xr[cell_to_node[3]], xr[cell_to_node[2]], + xr[cell_to_node[1]], // + xr[cell_to_node[0]], xr[cell_to_node[0]], xr[cell_to_node[0]], + xr[cell_to_node[0]]); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { const auto xi = qf.point(i_point); @@ -519,8 +522,8 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Prism: { - const PrismTransformation T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], - xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]]}); + const PrismTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], + xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]]); const auto qf = QuadratureManager::instance().getPrismFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { @@ -532,9 +535,9 @@ class IntegrateOnCells<OutputType(InputType)> : public PugsFunctionAdapter<Outpu break; } case CellType::Hexahedron: { - const Q1Transformation<3> T({xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], - xr[cell_to_node[3]], xr[cell_to_node[4]], xr[cell_to_node[5]], - xr[cell_to_node[6]], xr[cell_to_node[7]]}); + const CubeTransformation T(xr[cell_to_node[0]], xr[cell_to_node[1]], xr[cell_to_node[2]], xr[cell_to_node[3]], + xr[cell_to_node[4]], xr[cell_to_node[5]], xr[cell_to_node[6]], + xr[cell_to_node[7]]); const auto qf = QuadratureManager::instance().getCubeFormula(quadrature_descriptor); for (size_t i_point = 0; i_point < qf.numberOfPoints(); ++i_point) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index edd77f19444d13ec9024241d686eaa66085f6ada..0994985c3e5fa5e30198e1374aee1c0f8713025c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable (unit_tests test_AffectationProcessor.cpp test_AffectationToStringProcessor.cpp test_AffectationToTupleProcessor.cpp - test_AffineTransformation.cpp test_Array.cpp test_ArraySubscriptProcessor.cpp test_ASTBuilder.cpp @@ -62,6 +61,7 @@ add_executable (unit_tests test_CRSMatrix.cpp test_CRSMatrixDescriptor.cpp test_CubeGaussQuadrature.cpp + test_CubeTransformation.cpp test_DataVariant.cpp test_Demangle.cpp test_DiscreteFunctionDescriptorP0.cpp @@ -87,6 +87,7 @@ add_executable (unit_tests test_ItemType.cpp test_LinearSolver.cpp test_LinearSolverOptions.cpp + test_LineTransformation.cpp test_ListAffectationProcessor.cpp test_MathModule.cpp test_NameProcessor.cpp @@ -101,20 +102,22 @@ add_executable (unit_tests test_PugsUtils.cpp test_PyramidGaussQuadrature.cpp test_PyramidTransformation.cpp - test_Q1Transformation.cpp test_RevisionInfo.cpp test_SmallArray.cpp test_SmallVector.cpp test_SquareGaussQuadrature.cpp + test_SquareTransformation.cpp test_SymbolTable.cpp test_Table.cpp test_TetrahedronGaussQuadrature.cpp + test_TetrahedronTransformation.cpp test_TensorialGaussLegendreQuadrature.cpp test_TensorialGaussLobattoQuadrature.cpp test_Timer.cpp test_TinyMatrix.cpp test_TinyVector.cpp test_TriangleGaussQuadrature.cpp + test_TriangleTransformation.cpp test_TupleToVectorProcessor.cpp test_UnaryExpressionProcessor.cpp test_UnaryOperatorMangler.cpp diff --git a/tests/test_AffineTransformation.cpp b/tests/test_AffineTransformation.cpp deleted file mode 100644 index ec1dfa482434694f39c895ec3e9bf2e00fbba28e..0000000000000000000000000000000000000000 --- a/tests/test_AffineTransformation.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include <catch2/catch_approx.hpp> -#include <catch2/catch_test_macros.hpp> - -#include <geometry/AffineTransformation.hpp> - -// clazy:excludeall=non-pod-global-static - -TEST_CASE("AffineTransformation", "[geometry]") -{ - SECTION("1D") - { - using R1 = TinyVector<1>; - - const R1 a = 0.3; - const R1 b = 2.7; - - const std::array points = {a, b}; - - const AffineTransformation<1> t(points); - - REQUIRE(t(-1)[0] == Catch::Approx(0.3)); - REQUIRE(t(0)[0] == Catch::Approx(1.5)); - REQUIRE(t(1)[0] == Catch::Approx(2.7)); - - REQUIRE(t.jacobianDeterminant() == Catch::Approx(1.2)); - } - - SECTION("2D") - { - using R2 = TinyVector<2>; - - const R2 a = {1, 2}; - const R2 b = {3, 1}; - const R2 c = {2, 5}; - - const std::array points = {a, b, c}; - const AffineTransformation<2> t(points); - - REQUIRE(t({0, 0})[0] == Catch::Approx(1)); - REQUIRE(t({0, 0})[1] == Catch::Approx(2)); - - REQUIRE(t({1, 0})[0] == Catch::Approx(3)); - REQUIRE(t({1, 0})[1] == Catch::Approx(1)); - - REQUIRE(t({0, 1})[0] == Catch::Approx(2)); - REQUIRE(t({0, 1})[1] == Catch::Approx(5)); - - REQUIRE(t({1. / 3, 1. / 3})[0] == Catch::Approx(2)); - REQUIRE(t({1. / 3, 1. / 3})[1] == Catch::Approx(8. / 3)); - - REQUIRE(t.jacobianDeterminant() == Catch::Approx(7)); - } - - SECTION("3D") - { - using R3 = TinyVector<3>; - - const R3 a = {1, 2, 1}; - const R3 b = {3, 1, 3}; - const R3 c = {2, 5, 2}; - const R3 d = {2, 3, 4}; - - const std::array points = {a, b, c, d}; - const AffineTransformation<3> t(points); - - REQUIRE(t({0, 0, 0})[0] == Catch::Approx(1)); - REQUIRE(t({0, 0, 0})[1] == Catch::Approx(2)); - REQUIRE(t({0, 0, 0})[2] == Catch::Approx(1)); - - REQUIRE(t({1, 0, 0})[0] == Catch::Approx(3)); - REQUIRE(t({1, 0, 0})[1] == Catch::Approx(1)); - REQUIRE(t({1, 0, 0})[2] == Catch::Approx(3)); - - REQUIRE(t({0, 1, 0})[0] == Catch::Approx(2)); - REQUIRE(t({0, 1, 0})[1] == Catch::Approx(5)); - REQUIRE(t({0, 1, 0})[2] == Catch::Approx(2)); - - REQUIRE(t({0, 0, 1})[0] == Catch::Approx(2)); - REQUIRE(t({0, 0, 1})[1] == Catch::Approx(3)); - REQUIRE(t({0, 0, 1})[2] == Catch::Approx(4)); - - REQUIRE(t({0.25, 0.25, 0.25})[0] == Catch::Approx(2)); - REQUIRE(t({0.25, 0.25, 0.25})[1] == Catch::Approx(11. / 4)); - REQUIRE(t({0.25, 0.25, 0.25})[2] == Catch::Approx(2.5)); - - REQUIRE(t.jacobianDeterminant() == Catch::Approx(14)); - } -} diff --git a/tests/test_CubeTransformation.cpp b/tests/test_CubeTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2de108f9c96c5c3659c20b4c3e7d314d5342280c --- /dev/null +++ b/tests/test_CubeTransformation.cpp @@ -0,0 +1,117 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/CubeTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("CubeTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + const R3 a_hat = {-1, -1, -1}; + const R3 b_hat = {+1, -1, -1}; + const R3 c_hat = {+1, +1, -1}; + const R3 d_hat = {-1, +1, -1}; + const R3 e_hat = {-1, -1, +1}; + const R3 f_hat = {+1, -1, +1}; + const R3 g_hat = {+1, +1, +1}; + const R3 h_hat = {-1, +1, +1}; + + const R3 m_hat = zero; + + const R3 a = {0, 0, 0}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {0, 3, 1}; + const R3 e = {1, 2, 5}; + const R3 f = {3, 1, 7}; + const R3 g = {2, 5, 5}; + const R3 h = {0, 3, 6}; + + const R3 m = 0.125 * (a + b + c + d + e + f + g + h); + + const CubeTransformation t(a, b, c, d, e, f, g, h); + + SECTION("values") + { + REQUIRE(l2Norm(t(a_hat) - a) == Catch::Approx(0)); + REQUIRE(l2Norm(t(b_hat) - b) == Catch::Approx(0)); + REQUIRE(l2Norm(t(c_hat) - c) == Catch::Approx(0)); + REQUIRE(l2Norm(t(d_hat) - d) == Catch::Approx(0)); + REQUIRE(l2Norm(t(e_hat) - e) == Catch::Approx(0)); + REQUIRE(l2Norm(t(f_hat) - f) == Catch::Approx(0)); + REQUIRE(l2Norm(t(g_hat) - g) == Catch::Approx(0)); + REQUIRE(l2Norm(t(h_hat) - h) == Catch::Approx(0)); + + REQUIRE(l2Norm(t(m_hat) - m) == Catch::Approx(0)); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R3& X) { + const double x = X[0]; + const double y = X[1]; + const double z = X[2]; + + return -(3 * x * y * y * z + 9 * y * y * z - 6 * x * x * y * z + 6 * x * y * z - 96 * y * z + 14 * x * x * z - + 49 * x * z + 119 * z - 21 * x * y * y + 21 * y * y + 90 * x * y - 10 * y + 40 * x * x - 109 * x - + 491) / + 128; + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + REQUIRE(t.jacobianDeterminant(e_hat) == Catch::Approx(detJ(e_hat))); + REQUIRE(t.jacobianDeterminant(f_hat) == Catch::Approx(detJ(f_hat))); + REQUIRE(t.jacobianDeterminant(g_hat) == Catch::Approx(detJ(g_hat))); + REQUIRE(t.jacobianDeterminant(h_hat) == Catch::Approx(detJ(h_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("Gauss order 3") + { + // The jacobian determinant is of maximal degree 2 in each variable + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(2)); + + double volume = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + volume += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 353. / 12 is actually the volume of the hexahedron + REQUIRE(volume == Catch::Approx(353. / 12)); + } + + SECTION("Gauss order 4") + { + auto p = [](const R3& X) { + const double& x = X[0]; + const double& y = X[1]; + const double& z = X[2]; + + return 2 * x * x + 3 * y * z + z * z + 2 * x - 3 * y + 0.5 * z + 3; + }; + + // Jacbian determinant is a degree 2 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<3>& gauss = + QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(gauss.point(i)); + } + + REQUIRE(integral == Catch::Approx(8795. / 72)); + } + } +} diff --git a/tests/test_LineTransformation.cpp b/tests/test_LineTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9c9620af26851da7fd3724a6d4f8c39436d301f --- /dev/null +++ b/tests/test_LineTransformation.cpp @@ -0,0 +1,22 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <geometry/LineTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("LineTransformation", "[geometry]") +{ + using R1 = TinyVector<1>; + + const R1 a = 0.3; + const R1 b = 2.7; + + const LineTransformation t(a, b); + + REQUIRE(t(-1)[0] == Catch::Approx(0.3)); + REQUIRE(t(0)[0] == Catch::Approx(1.5)); + REQUIRE(t(1)[0] == Catch::Approx(2.7)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(1.2)); +} diff --git a/tests/test_PrismGaussQuadrature.cpp b/tests/test_PrismGaussQuadrature.cpp index e1956601c591922fcc4e57acedb12b7bc351f903..ceff287e5ac5c823c9f427ba6801babfeaa47481 100644 --- a/tests/test_PrismGaussQuadrature.cpp +++ b/tests/test_PrismGaussQuadrature.cpp @@ -5,7 +5,7 @@ #include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/PrismGaussQuadrature.hpp> #include <analysis/QuadratureManager.hpp> -#include <geometry/AffineTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> #include <utils/Exceptions.hpp> // clazy:excludeall=non-pod-global-static diff --git a/tests/test_PrismTransformation.cpp b/tests/test_PrismTransformation.cpp index 5b19f9b08ca5631370eed4a4787e9c521a8f7ccf..e170da3c05cf2643ab22958509b2cf62039f3fa1 100644 --- a/tests/test_PrismTransformation.cpp +++ b/tests/test_PrismTransformation.cpp @@ -27,8 +27,7 @@ TEST_CASE("PrismTransformation", "[geometry]") const R3 e = {1, 2, 5}; const R3 f = {3, 1, 7}; - const std::array points = {a, b, c, d, e, f}; - const PrismTransformation t(points); + const PrismTransformation t(a, b, c, d, e, f); SECTION("points") { diff --git a/tests/test_PyramidGaussQuadrature.cpp b/tests/test_PyramidGaussQuadrature.cpp index 9c8bfc9cc301d64d486fa617b7630ff88f012df2..e648c96fb13df144945e7c73cdf381545ff1169b 100644 --- a/tests/test_PyramidGaussQuadrature.cpp +++ b/tests/test_PyramidGaussQuadrature.cpp @@ -5,7 +5,7 @@ #include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/PyramidGaussQuadrature.hpp> #include <analysis/QuadratureManager.hpp> -#include <geometry/AffineTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> #include <utils/Exceptions.hpp> // clazy:excludeall=non-pod-global-static diff --git a/tests/test_PyramidTransformation.cpp b/tests/test_PyramidTransformation.cpp index 80933bd44d2b9e9f1ff357d6e2969aa7e082abbb..ca51bf080045e0df06d706b60bc5fd1dca497d44 100644 --- a/tests/test_PyramidTransformation.cpp +++ b/tests/test_PyramidTransformation.cpp @@ -25,8 +25,7 @@ TEST_CASE("PyramidTransformation", "[geometry]") const R3 d = {0, 3, 1}; const R3 e = {1, 2, 5}; - const std::array points = {a, b, c, d, e}; - const PyramidTransformation t(points); + const PyramidTransformation t(a, b, c, d, e); SECTION("points") { diff --git a/tests/test_Q1Transformation.cpp b/tests/test_Q1Transformation.cpp deleted file mode 100644 index caa46f5bf003ad503b620fb02fe6662cc027a27d..0000000000000000000000000000000000000000 --- a/tests/test_Q1Transformation.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include <catch2/catch_approx.hpp> -#include <catch2/catch_test_macros.hpp> - -#include <analysis/GaussLegendreQuadratureDescriptor.hpp> -#include <analysis/QuadratureManager.hpp> -#include <geometry/Q1Transformation.hpp> - -// clazy:excludeall=non-pod-global-static - -TEST_CASE("Q1Transformation", "[geometry]") -{ - SECTION("1D") - { - using R1 = TinyVector<1>; - - const R1 a = 0.3; - const R1 b = 2.7; - - const std::array points = {a, b}; - - const Q1Transformation<1> t(points); - - REQUIRE(t(-1)[0] == Catch::Approx(0.3)); - REQUIRE(t(0)[0] == Catch::Approx(1.5)); - REQUIRE(t(1)[0] == Catch::Approx(2.7)); - - REQUIRE(t.jacobianDeterminant(R1{-1}) == Catch::Approx(1.2)); - REQUIRE(t.jacobianDeterminant(R1{0}) == Catch::Approx(1.2)); - REQUIRE(t.jacobianDeterminant(R1{3}) == Catch::Approx(1.2)); - } - - SECTION("2D") - { - using R2 = TinyVector<2>; - - const R2 a_hat = {-1, -1}; - const R2 b_hat = {+1, -1}; - const R2 c_hat = {+1, +1}; - const R2 d_hat = {-1, +1}; - - const R2 m_hat = zero; - - const R2 a = {0, 0}; - const R2 b = {8, -2}; - const R2 c = {12, 7}; - const R2 d = {3, 7}; - - const R2 m = 0.25 * (a + b + c + d); - - const std::array points = {a, b, c, d}; - const Q1Transformation<2> t(points); - - SECTION("values") - { - REQUIRE(t(a_hat)[0] == Catch::Approx(a[0])); - REQUIRE(t(a_hat)[1] == Catch::Approx(a[1])); - - REQUIRE(t(b_hat)[0] == Catch::Approx(b[0])); - REQUIRE(t(b_hat)[1] == Catch::Approx(b[1])); - - REQUIRE(t(c_hat)[0] == Catch::Approx(c[0])); - REQUIRE(t(c_hat)[1] == Catch::Approx(c[1])); - - REQUIRE(t(d_hat)[0] == Catch::Approx(d[0])); - REQUIRE(t(d_hat)[1] == Catch::Approx(d[1])); - - REQUIRE(t(m_hat)[0] == Catch::Approx(m[0])); - REQUIRE(t(m_hat)[1] == Catch::Approx(m[1])); - } - - SECTION("Jacobian determinant") - { - SECTION("at points") - { - auto detJ = [](const R2& X) { - const double x = X[0]; - const double y = X[1]; - - return 0.25 * ((0.5 * x + 4) * (y + 17) - 0.5 * (x + 7) * (y - 1)); - }; - - REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); - REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); - REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); - REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); - - REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); - } - - SECTION("Gauss order 1") - { - // One point is enough in 2d - const QuadratureFormula<2>& gauss = - QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(1)); - - double surface = 0; - for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { - surface += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); - } - - // 71.5 is actually the surface of the quadrangle - REQUIRE(surface == Catch::Approx(71.5)); - } - - SECTION("Gauss order 3") - { - auto p = [](const R2& X) { - const double& x = X[0]; - const double& y = X[1]; - - return (2 * x + 3 * y + 2) * (x - 2 * y - 1); - }; - - // Jacbian determinant is a degree 1 polynomial, so the - // following formula is required to reach exactness - const QuadratureFormula<2>& gauss = - QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(3)); - - double integral = 0; - for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { - integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(gauss.point(i)); - } - - REQUIRE(integral == Catch::Approx(-479. / 2)); - } - } - } - - SECTION("3D") - { - using R3 = TinyVector<3>; - - const R3 a_hat = {-1, -1, -1}; - const R3 b_hat = {+1, -1, -1}; - const R3 c_hat = {+1, +1, -1}; - const R3 d_hat = {-1, +1, -1}; - const R3 e_hat = {-1, -1, +1}; - const R3 f_hat = {+1, -1, +1}; - const R3 g_hat = {+1, +1, +1}; - const R3 h_hat = {-1, +1, +1}; - - const R3 m_hat = zero; - - const R3 a = {0, 0, 0}; - const R3 b = {3, 1, 3}; - const R3 c = {2, 5, 2}; - const R3 d = {0, 3, 1}; - const R3 e = {1, 2, 5}; - const R3 f = {3, 1, 7}; - const R3 g = {2, 5, 5}; - const R3 h = {0, 3, 6}; - - const R3 m = 0.125 * (a + b + c + d + e + f + g + h); - - const std::array points = {a, b, c, d, e, f, g, h}; - const Q1Transformation<3> t(points); - - SECTION("values") - { - REQUIRE(l2Norm(t(a_hat) - a) == Catch::Approx(0)); - REQUIRE(l2Norm(t(b_hat) - b) == Catch::Approx(0)); - REQUIRE(l2Norm(t(c_hat) - c) == Catch::Approx(0)); - REQUIRE(l2Norm(t(d_hat) - d) == Catch::Approx(0)); - REQUIRE(l2Norm(t(e_hat) - e) == Catch::Approx(0)); - REQUIRE(l2Norm(t(f_hat) - f) == Catch::Approx(0)); - REQUIRE(l2Norm(t(g_hat) - g) == Catch::Approx(0)); - REQUIRE(l2Norm(t(h_hat) - h) == Catch::Approx(0)); - - REQUIRE(l2Norm(t(m_hat) - m) == Catch::Approx(0)); - } - - SECTION("Jacobian determinant") - { - SECTION("at points") - { - auto detJ = [](const R3& X) { - const double x = X[0]; - const double y = X[1]; - const double z = X[2]; - - return -(3 * x * y * y * z + 9 * y * y * z - 6 * x * x * y * z + 6 * x * y * z - 96 * y * z + 14 * x * x * z - - 49 * x * z + 119 * z - 21 * x * y * y + 21 * y * y + 90 * x * y - 10 * y + 40 * x * x - 109 * x - - 491) / - 128; - }; - - REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); - REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); - REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); - REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); - REQUIRE(t.jacobianDeterminant(e_hat) == Catch::Approx(detJ(e_hat))); - REQUIRE(t.jacobianDeterminant(f_hat) == Catch::Approx(detJ(f_hat))); - REQUIRE(t.jacobianDeterminant(g_hat) == Catch::Approx(detJ(g_hat))); - REQUIRE(t.jacobianDeterminant(h_hat) == Catch::Approx(detJ(h_hat))); - - REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); - } - - SECTION("Gauss order 3") - { - // The jacobian determinant is of maximal degree 2 in each variable - const QuadratureFormula<3>& gauss = - QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(2)); - - double volume = 0; - for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { - volume += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); - } - - // 353. / 12 is actually the volume of the hexahedron - REQUIRE(volume == Catch::Approx(353. / 12)); - } - - SECTION("Gauss order 4") - { - auto p = [](const R3& X) { - const double& x = X[0]; - const double& y = X[1]; - const double& z = X[2]; - - return 2 * x * x + 3 * y * z + z * z + 2 * x - 3 * y + 0.5 * z + 3; - }; - - // Jacbian determinant is a degree 2 polynomial, so the - // following formula is required to reach exactness - const QuadratureFormula<3>& gauss = - QuadratureManager::instance().getCubeFormula(GaussLegendreQuadratureDescriptor(4)); - - double integral = 0; - for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { - integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(gauss.point(i)); - } - - REQUIRE(integral == Catch::Approx(8795. / 72)); - } - } - } -} diff --git a/tests/test_SquareTransformation.cpp b/tests/test_SquareTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19523959948a9ae3980e5df9f6efb4dcb0e12734 --- /dev/null +++ b/tests/test_SquareTransformation.cpp @@ -0,0 +1,104 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <analysis/GaussLegendreQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <geometry/SquareTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SquareTransformation", "[geometry]") +{ + using R2 = TinyVector<2>; + + const R2 a_hat = {-1, -1}; + const R2 b_hat = {+1, -1}; + const R2 c_hat = {+1, +1}; + const R2 d_hat = {-1, +1}; + + const R2 m_hat = zero; + + const R2 a = {0, 0}; + const R2 b = {8, -2}; + const R2 c = {12, 7}; + const R2 d = {3, 7}; + + const R2 m = 0.25 * (a + b + c + d); + + const SquareTransformation t(a, b, c, d); + + SECTION("values") + { + REQUIRE(t(a_hat)[0] == Catch::Approx(a[0])); + REQUIRE(t(a_hat)[1] == Catch::Approx(a[1])); + + REQUIRE(t(b_hat)[0] == Catch::Approx(b[0])); + REQUIRE(t(b_hat)[1] == Catch::Approx(b[1])); + + REQUIRE(t(c_hat)[0] == Catch::Approx(c[0])); + REQUIRE(t(c_hat)[1] == Catch::Approx(c[1])); + + REQUIRE(t(d_hat)[0] == Catch::Approx(d[0])); + REQUIRE(t(d_hat)[1] == Catch::Approx(d[1])); + + REQUIRE(t(m_hat)[0] == Catch::Approx(m[0])); + REQUIRE(t(m_hat)[1] == Catch::Approx(m[1])); + } + + SECTION("Jacobian determinant") + { + SECTION("at points") + { + auto detJ = [](const R2& X) { + const double x = X[0]; + const double y = X[1]; + + return 0.25 * ((0.5 * x + 4) * (y + 17) - 0.5 * (x + 7) * (y - 1)); + }; + + REQUIRE(t.jacobianDeterminant(a_hat) == Catch::Approx(detJ(a_hat))); + REQUIRE(t.jacobianDeterminant(b_hat) == Catch::Approx(detJ(b_hat))); + REQUIRE(t.jacobianDeterminant(c_hat) == Catch::Approx(detJ(c_hat))); + REQUIRE(t.jacobianDeterminant(d_hat) == Catch::Approx(detJ(d_hat))); + + REQUIRE(t.jacobianDeterminant(m_hat) == Catch::Approx(detJ(m_hat))); + } + + SECTION("Gauss order 1") + { + // One point is enough in 2d + const QuadratureFormula<2>& gauss = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(1)); + + double surface = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + surface += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)); + } + + // 71.5 is actually the surface of the quadrangle + REQUIRE(surface == Catch::Approx(71.5)); + } + + SECTION("Gauss order 3") + { + auto p = [](const R2& X) { + const double& x = X[0]; + const double& y = X[1]; + + return (2 * x + 3 * y + 2) * (x - 2 * y - 1); + }; + + // Jacbian determinant is a degree 1 polynomial, so the + // following formula is required to reach exactness + const QuadratureFormula<2>& gauss = + QuadratureManager::instance().getSquareFormula(GaussLegendreQuadratureDescriptor(3)); + + double integral = 0; + for (size_t i = 0; i < gauss.numberOfPoints(); ++i) { + integral += gauss.weight(i) * t.jacobianDeterminant(gauss.point(i)) * p(gauss.point(i)); + } + + REQUIRE(integral == Catch::Approx(-479. / 2)); + } + } +} diff --git a/tests/test_TetrahedronGaussQuadrature.cpp b/tests/test_TetrahedronGaussQuadrature.cpp index 00f3eecf101e6e9bbc45ba3866cc06237f922569..605d1dc1fa7476719fe16ac595ff55491f5bd8e8 100644 --- a/tests/test_TetrahedronGaussQuadrature.cpp +++ b/tests/test_TetrahedronGaussQuadrature.cpp @@ -5,7 +5,7 @@ #include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/QuadratureManager.hpp> #include <analysis/TetrahedronGaussQuadrature.hpp> -#include <geometry/AffineTransformation.hpp> +#include <geometry/TetrahedronTransformation.hpp> #include <utils/Exceptions.hpp> // clazy:excludeall=non-pod-global-static @@ -20,7 +20,7 @@ TEST_CASE("TetrahedronGaussQuadrature", "[analysis]") const R3 C{-1, +1, -1}; const R3 D{-1, -1, +1}; - AffineTransformation<3> t{{A, B, C, D}}; + TetrahedronTransformation t{A, B, C, D}; auto point_list = quadrature_formula.pointList(); auto weight_list = quadrature_formula.weightList(); @@ -33,8 +33,9 @@ TEST_CASE("TetrahedronGaussQuadrature", "[analysis]") return t.jacobianDeterminant() * value; }; - auto integrate_on_tetra = [](auto f, auto quadrature_formula, const std::array<TinyVector<3>, 4>& tetrahedron) { - AffineTransformation<3> t{tetrahedron}; + auto integrate_on_tetra = [](auto f, auto quadrature_formula, const TinyVector<3>& a, const TinyVector<3>& b, + const TinyVector<3>& c, const TinyVector<3>& d) { + TetrahedronTransformation t{a, b, c, d}; auto point_list = quadrature_formula.pointList(); auto weight_list = quadrature_formula.weightList(); @@ -64,14 +65,14 @@ TEST_CASE("TetrahedronGaussQuadrature", "[analysis]") const double int_T_hat = integrate(f, quadrature_formula); const double int_refined // - = integrate_on_tetra(f, quadrature_formula, {A, M_AB, M_AC, M_AD}) + - integrate_on_tetra(f, quadrature_formula, {B, M_AB, M_BD, M_BC}) + - integrate_on_tetra(f, quadrature_formula, {C, M_AC, M_BC, M_CD}) + - integrate_on_tetra(f, quadrature_formula, {D, M_AD, M_CD, M_BD}) + - integrate_on_tetra(f, quadrature_formula, {M_BD, M_AC, M_AD, M_CD}) + - integrate_on_tetra(f, quadrature_formula, {M_AB, M_AC, M_AD, M_BD}) + - integrate_on_tetra(f, quadrature_formula, {M_BC, M_AB, M_BD, M_AC}) + - integrate_on_tetra(f, quadrature_formula, {M_BC, M_AC, M_BD, M_CD}); + = integrate_on_tetra(f, quadrature_formula, A, M_AB, M_AC, M_AD) + + integrate_on_tetra(f, quadrature_formula, B, M_AB, M_BD, M_BC) + + integrate_on_tetra(f, quadrature_formula, C, M_AC, M_BC, M_CD) + + integrate_on_tetra(f, quadrature_formula, D, M_AD, M_CD, M_BD) + + integrate_on_tetra(f, quadrature_formula, M_BD, M_AC, M_AD, M_CD) + + integrate_on_tetra(f, quadrature_formula, M_AB, M_AC, M_AD, M_BD) + + integrate_on_tetra(f, quadrature_formula, M_BC, M_AB, M_BD, M_AC) + + integrate_on_tetra(f, quadrature_formula, M_BC, M_AC, M_BD, M_CD); return -std::log(std::abs(int_refined - exact_value) / std::abs(int_T_hat - exact_value)) / std::log(2); }; diff --git a/tests/test_TetrahedronTransformation.cpp b/tests/test_TetrahedronTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a9d20275fd1df42db4e5ea723b585c2872e69c4 --- /dev/null +++ b/tests/test_TetrahedronTransformation.cpp @@ -0,0 +1,40 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <geometry/TetrahedronTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TetrahedronTransformation", "[geometry]") +{ + using R3 = TinyVector<3>; + + const R3 a = {1, 2, 1}; + const R3 b = {3, 1, 3}; + const R3 c = {2, 5, 2}; + const R3 d = {2, 3, 4}; + + const TetrahedronTransformation t(a, b, c, d); + + REQUIRE(t({0, 0, 0})[0] == Catch::Approx(1)); + REQUIRE(t({0, 0, 0})[1] == Catch::Approx(2)); + REQUIRE(t({0, 0, 0})[2] == Catch::Approx(1)); + + REQUIRE(t({1, 0, 0})[0] == Catch::Approx(3)); + REQUIRE(t({1, 0, 0})[1] == Catch::Approx(1)); + REQUIRE(t({1, 0, 0})[2] == Catch::Approx(3)); + + REQUIRE(t({0, 1, 0})[0] == Catch::Approx(2)); + REQUIRE(t({0, 1, 0})[1] == Catch::Approx(5)); + REQUIRE(t({0, 1, 0})[2] == Catch::Approx(2)); + + REQUIRE(t({0, 0, 1})[0] == Catch::Approx(2)); + REQUIRE(t({0, 0, 1})[1] == Catch::Approx(3)); + REQUIRE(t({0, 0, 1})[2] == Catch::Approx(4)); + + REQUIRE(t({0.25, 0.25, 0.25})[0] == Catch::Approx(2)); + REQUIRE(t({0.25, 0.25, 0.25})[1] == Catch::Approx(11. / 4)); + REQUIRE(t({0.25, 0.25, 0.25})[2] == Catch::Approx(2.5)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(14)); +} diff --git a/tests/test_TriangleGaussQuadrature.cpp b/tests/test_TriangleGaussQuadrature.cpp index 879c47b94b3326e96bbefecc40047ea50fb49b71..0bb7f34ec3cdc057249f9fa2c0f3d9eaf6dc81c5 100644 --- a/tests/test_TriangleGaussQuadrature.cpp +++ b/tests/test_TriangleGaussQuadrature.cpp @@ -5,7 +5,7 @@ #include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/QuadratureManager.hpp> #include <analysis/TriangleGaussQuadrature.hpp> -#include <geometry/AffineTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> #include <utils/Exceptions.hpp> // clazy:excludeall=non-pod-global-static @@ -19,7 +19,7 @@ TEST_CASE("TriangleGaussQuadrature", "[analysis]") const R2 B{+1, -1}; const R2 C{-1, +1}; - AffineTransformation<2> t{{A, B, C}}; + TriangleTransformation t{A, B, C}; auto point_list = quadrature_formula.pointList(); auto weight_list = quadrature_formula.weightList(); @@ -32,8 +32,9 @@ TEST_CASE("TriangleGaussQuadrature", "[analysis]") return t.jacobianDeterminant() * value; }; - auto integrate_on_triangle = [](auto f, auto quadrature_formula, const std::array<TinyVector<2>, 3>& triangle) { - AffineTransformation<2> t{triangle}; + auto integrate_on_triangle = [](auto f, auto quadrature_formula, const TinyVector<2>& a, const TinyVector<2>& b, + const TinyVector<2>& c) { + TriangleTransformation t(a, b, c); auto point_list = quadrature_formula.pointList(); auto weight_list = quadrature_formula.weightList(); @@ -50,10 +51,10 @@ TEST_CASE("TriangleGaussQuadrature", "[analysis]") using R2 = TinyVector<2>; const double int_T_hat = integrate(f, quadrature_formula); const double int_refined // - = integrate_on_triangle(f, quadrature_formula, {R2{-1, -1}, R2{0, -1}, R2{-1, 0}}) + - integrate_on_triangle(f, quadrature_formula, {R2{0, -1}, R2{0, 0}, R2{-1, 0}}) + - integrate_on_triangle(f, quadrature_formula, {R2{0, -1}, R2{1, -1}, R2{0, 0}}) + - integrate_on_triangle(f, quadrature_formula, {R2{-1, 0}, R2{0, 0}, R2{-1, 1}}); + = integrate_on_triangle(f, quadrature_formula, R2{-1, -1}, R2{0, -1}, R2{-1, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{0, -1}, R2{0, 0}, R2{-1, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{0, -1}, R2{1, -1}, R2{0, 0}) + + integrate_on_triangle(f, quadrature_formula, R2{-1, 0}, R2{0, 0}, R2{-1, 1}); return -std::log(std::abs(int_refined - exact_value) / std::abs(int_T_hat - exact_value)) / std::log(2); }; diff --git a/tests/test_TriangleTransformation.cpp b/tests/test_TriangleTransformation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1c05aabc7be130e9b36bc4b52a3ebe0733e8456 --- /dev/null +++ b/tests/test_TriangleTransformation.cpp @@ -0,0 +1,31 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> + +#include <geometry/TriangleTransformation.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("TriangleTransformation", "[geometry]") +{ + using R2 = TinyVector<2>; + + const R2 a = {1, 2}; + const R2 b = {3, 1}; + const R2 c = {2, 5}; + + const TriangleTransformation t(a, b, c); + + REQUIRE(t({0, 0})[0] == Catch::Approx(1)); + REQUIRE(t({0, 0})[1] == Catch::Approx(2)); + + REQUIRE(t({1, 0})[0] == Catch::Approx(3)); + REQUIRE(t({1, 0})[1] == Catch::Approx(1)); + + REQUIRE(t({0, 1})[0] == Catch::Approx(2)); + REQUIRE(t({0, 1})[1] == Catch::Approx(5)); + + REQUIRE(t({1. / 3, 1. / 3})[0] == Catch::Approx(2)); + REQUIRE(t({1. / 3, 1. / 3})[1] == Catch::Approx(8. / 3)); + + REQUIRE(t.jacobianDeterminant() == Catch::Approx(7)); +}