diff --git a/src/language/modules/MathFunctionRegisterForVh.cpp b/src/language/modules/MathFunctionRegisterForVh.cpp index 38dc08b6e4bec82be8cab2666080563bd7cb9736..b31fe47d0eba87ff2e7f0823a530bf170e410d6c 100644 --- a/src/language/modules/MathFunctionRegisterForVh.cpp +++ b/src/language/modules/MathFunctionRegisterForVh.cpp @@ -212,6 +212,76 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module )); + scheme_module._addBuiltinFunction("tensorProduct", std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a, + const TinyVector<1> b) -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a, + const TinyVector<2> b) -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a, + const TinyVector<3>& b) -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](const TinyVector<1> a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](const TinyVector<2> a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + + scheme_module._addBuiltinFunction("tensorProduct", + std::function( + + [](const TinyVector<3>& a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return tensorProduct(a, b); + } + + )); + scheme_module._addBuiltinFunction("det", std::function( [](std::shared_ptr<const DiscreteFunctionVariant> A) diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp index 4a1e7b35b76a4d9b8b05ebb1355f3cdca4f751d9..af1dfeafb4ac2bdd22894cb3ad1fde26b1ed0d8c 100644 --- a/src/language/modules/MathModule.cpp +++ b/src/language/modules/MathModule.cpp @@ -71,6 +71,21 @@ MathModule::MathModule() return dot(x, y); })); + this->_addBuiltinFunction("tensorProduct", + std::function([](const TinyVector<1> x, const TinyVector<1> y) -> TinyMatrix<1> { + return tensorProduct(x, y); + })); + + this->_addBuiltinFunction("tensorProduct", + std::function([](const TinyVector<2> x, const TinyVector<2> y) -> TinyMatrix<2> { + return tensorProduct(x, y); + })); + + this->_addBuiltinFunction("tensorProduct", + std::function([](const TinyVector<3>& x, const TinyVector<3>& y) -> TinyMatrix<3> { + return tensorProduct(x, y); + })); + this->_addBuiltinFunction("det", std::function([](const TinyMatrix<1> A) -> double { return det(A); })); this->_addBuiltinFunction("det", std::function([](const TinyMatrix<2>& A) -> double { return det(A); })); diff --git a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp index 715de1be2019070e517cb30639c199f721258cd2..961cc0e4092ba57c001866a52d7aed113e6b0f5d 100644 --- a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp +++ b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp @@ -315,6 +315,110 @@ template std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<2>& template std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<3>&, const std::shared_ptr<const DiscreteFunctionVariant>&); +std::shared_ptr<const DiscreteFunctionVariant> +tensorProduct(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (not std::is_same_v<TypeOfF, TypeOfG>) { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } else { + using DataType = std::decay_t<typename TypeOfF::data_type>; + if constexpr (is_discrete_function_P0_v<TypeOfF>) { + if constexpr (is_tiny_vector_v<DataType>) { + return std::make_shared<DiscreteFunctionVariant>(tensorProduct(f, g)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> +tensorProduct(const std::shared_ptr<const DiscreteFunctionVariant>& f, const TinyVector<VectorDimension>& a) +{ + return std::visit( + [&](auto&& discrete_function0) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunction0Type = std::decay_t<decltype(discrete_function0)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunction0Type>) { + using DataType = std::decay_t<typename DiscreteFunction0Type::data_type>; + if constexpr (is_tiny_vector_v<DataType>) { + if constexpr (std::is_same_v<DataType, TinyVector<VectorDimension>>) { + return std::make_shared<DiscreteFunctionVariant>(tensorProduct<DataType>(discrete_function0, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + }, + f->discreteFunction()); +} + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> +tensorProduct(const TinyVector<VectorDimension>& a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + return std::visit( + [&](auto&& discrete_function0) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunction0Type = std::decay_t<decltype(discrete_function0)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunction0Type>) { + using DataType = std::decay_t<typename DiscreteFunction0Type::data_type>; + if constexpr (is_tiny_vector_v<DataType>) { + if constexpr (std::is_same_v<DataType, TinyVector<VectorDimension>>) { + return std::make_shared<DiscreteFunctionVariant>(tensorProduct<DataType>(a, discrete_function0)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + }, + f->discreteFunction()); +} + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<1>&); + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<2>&); + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<3>&); + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const TinyVector<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const TinyVector<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template std::shared_ptr<const DiscreteFunctionVariant> tensorProduct( + const TinyVector<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + std::shared_ptr<const DiscreteFunctionVariant> det(const std::shared_ptr<const DiscreteFunctionVariant>& A) { diff --git a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp index 66b784921da372cc7dfa2d616b94d6fbfe403ee3..bcda26113a4fac6d72e7b54edfe0f0e8d8d74b2d 100644 --- a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp +++ b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp @@ -69,6 +69,17 @@ template <size_t VectorDimension> std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<VectorDimension>&, const std::shared_ptr<const DiscreteFunctionVariant>&); +std::shared_ptr<const DiscreteFunctionVariant> tensorProduct(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> tensorProduct(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<VectorDimension>&); + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> tensorProduct(const TinyVector<VectorDimension>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + std::shared_ptr<const DiscreteFunctionVariant> det(const std::shared_ptr<const DiscreteFunctionVariant>&); std::shared_ptr<const DiscreteFunctionVariant> trace(const std::shared_ptr<const DiscreteFunctionVariant>&); diff --git a/src/scheme/DiscreteFunctionP0.hpp b/src/scheme/DiscreteFunctionP0.hpp index df43f52905837036d0ef843fbc5635f0d1274c6d..ea0ec56aeeebb28e4af381ae352a20c9abd43bd4 100644 --- a/src/scheme/DiscreteFunctionP0.hpp +++ b/src/scheme/DiscreteFunctionP0.hpp @@ -606,6 +606,51 @@ class DiscreteFunctionP0 return result; } + template <typename LHSDataType> + PUGS_INLINE friend DiscreteFunctionP0<decltype(tensorProduct(LHSDataType{}, DataType{}))> + tensorProduct(const LHSDataType& u, const DiscreteFunctionP0& v) + { + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); + static_assert(is_tiny_vector_v<std::decay_t<LHSDataType>>); + Assert(v.m_cell_values.isBuilt()); + DiscreteFunctionP0<decltype(tensorProduct(LHSDataType{}, DataType{}))> result{v.m_mesh_v}; + parallel_for( + v.m_mesh_v->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = tensorProduct(u, v[cell_id]); }); + + return result; + } + + template <typename RHSDataType> + PUGS_INLINE friend DiscreteFunctionP0<decltype(tensorProduct(DataType{}, RHSDataType{}))> + tensorProduct(const DiscreteFunctionP0& u, const RHSDataType& v) + { + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); + static_assert(is_tiny_vector_v<std::decay_t<RHSDataType>>); + Assert(u.m_cell_values.isBuilt()); + DiscreteFunctionP0<decltype(tensorProduct(DataType{}, RHSDataType{}))> result{u.m_mesh_v}; + parallel_for( + u.m_mesh_v->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = tensorProduct(u[cell_id], v); }); + + return result; + } + + template <typename DataType2> + PUGS_INLINE friend DiscreteFunctionP0<decltype(tensorProduct(DataType{}, DataType2{}))> + tensorProduct(const DiscreteFunctionP0& u, const DiscreteFunctionP0<DataType2>& v) + { + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); + static_assert(is_tiny_vector_v<std::decay_t<DataType2>>); + Assert(u.m_cell_values.isBuilt()); + Assert(v.m_cell_values.isBuilt()); + Assert(u.m_mesh_v->id() == v.m_mesh_v->id()); + DiscreteFunctionP0<decltype(tensorProduct(DataType{}, DataType2{}))> result{u.m_mesh_v}; + parallel_for( + u.m_mesh_v->numberOfCells(), + PUGS_LAMBDA(CellId cell_id) { result[cell_id] = tensorProduct(u[cell_id], v[cell_id]); }); + + return result; + } + PUGS_INLINE friend double min(const DiscreteFunctionP0& f) { diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp index b678612fe2c338b641b1e66c6ccce9ae65454b8f..f600bfa4408c81cf447a8665880fb3040ea81e75 100644 --- a/tests/test_BuiltinFunctionProcessor.cpp +++ b/tests/test_BuiltinFunctionProcessor.cpp @@ -362,6 +362,40 @@ let s:R, s = dot(x,y); CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "s", dot(TinyVector<3>{-2, 3, 4}, TinyVector<3>{4, 3, 5})); } + { // dot + tested_function_set.insert("tensorProduct:R^1*R^1"); + std::string_view data = R"( +import math; +let x:R^1, x = -2; +let y:R^1, y = 4; +let s:R^1x1, s = tensorProduct(x,y); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "s", TinyMatrix<1>{-2 * 4}); + } + + { // dot + tested_function_set.insert("tensorProduct:R^2*R^2"); + std::string_view data = R"( +import math; +let x:R^2, x = [-2, 3]; +let y:R^2, y = [4, 3]; +let s:R^2x2, s = tensorProduct(x,y); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "s", tensorProduct(TinyVector<2>{-2, 3}, TinyVector<2>{4, 3})); + } + + { // dot + tested_function_set.insert("tensorProduct:R^3*R^3"); + std::string_view data = R"( +import math; +let x:R^3, x = [-2, 3, 4]; +let y:R^3, y = [4, 3, 5]; +let s:R^3x3, s = tensorProduct(x,y); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "s", + tensorProduct(TinyVector<3>{-2, 3, 4}, TinyVector<3>{4, 3, 5})); + } + { // det tested_function_set.insert("det:R^1x1"); std::string_view data = R"( diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index 5b1133b4e6c60290b06aa90e5c68b64a1c1b4973..14c96b0db712daa220951f407e66eb1f774f126e 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -2729,6 +2729,53 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); } + SECTION("tensorProduct(uh,hv)") + { + DiscreteFunctionP0<TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + + DiscreteFunctionP0<TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); + + CHECK_STD_BINARY_MATH_FUNCTION(uh, vh, tensorProduct); + } + + SECTION("tensorProduct(uh,v)") + { + DiscreteFunctionP0<TinyVector<2>> uh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + uh[cell_id] = TinyVector<2>{x + 1, 2 * x - 3}; + }); + + const TinyVector<2> v{1, 2}; + + CHECK_STD_BINARY_MATH_FUNCTION_WITH_RHS_VALUE(uh, v, tensorProduct); + } + + SECTION("tensorProduct(u,hv)") + { + const TinyVector<2> u{3, -2}; + + DiscreteFunctionP0<TinyVector<2>> vh{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + vh[cell_id] = TinyVector<2>{2.3 * x, 1 - x}; + }); + + CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, tensorProduct); + } + SECTION("scalar sum") { const CellValue<const double> cell_value = positive_function.cellValues(); diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp index 5843a8ae766549e0828551bae8d33ff8c595935d..41f3c0d2233b1884051f0eafd5df637ce37ed7e0 100644 --- a/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp @@ -502,6 +502,29 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions1D", "[scheme]") REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); } + SECTION("tensorProduct Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_other_mesh_R1_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, p_other_mesh_R2_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, p_other_mesh_R3_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_R3_u), + "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(tensorProduct(p_u, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1x1_u, p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2x2_u, p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3x3_u, p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + SECTION("det Vh -> Vh") { CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // @@ -675,6 +698,48 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions1D", "[scheme]") REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); } + SECTION("tensorProduct Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_u, TinyVector<2>{1, 2}), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_Vector3_u, TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, (TinyVector<1>{-1})), + "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("tensorProduct Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_Vector3_u), + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<1>{-1}), p_R3_u), + "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + SECTION("sum_of_R* Vh -> R*") { REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp index 11582b9820d9e2f6d910773b2084517a47069b37..919d4f8280e764d263129f70a849064867bb6f2a 100644 --- a/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp @@ -504,6 +504,30 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions2D", "[scheme]") REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); } + SECTION("tensorProduct Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_other_mesh_R1_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, p_other_mesh_R2_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, p_other_mesh_R3_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_R3_u), + "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(tensorProduct(p_u, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1x1_u, p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2x2_u, p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3x3_u, p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(tensorProduct(p_Vector3_u, p_Vector2_w), "error: invalid operand type Vh(P0Vector:R)"); + } + SECTION("det Vh -> Vh") { CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // @@ -677,6 +701,48 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions2D", "[scheme]") REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); } + SECTION("tensorProduct Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_u, TinyVector<2>{1, 2}), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_Vector3_u, TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, (TinyVector<1>{-1})), + "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("tensorProduct Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_Vector3_u), + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<1>{-1}), p_R3_u), + "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + SECTION("sum_of_R* Vh -> R*") { REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp index edca0a4eb9c9e015a7e0ed31fd74ca068d4258c5..99994e9d0a902add718dee6149c3c040765a7106 100644 --- a/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp @@ -502,6 +502,30 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions3D", "[scheme]") REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); } + SECTION("tensorProduct Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_other_mesh_R1_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, p_other_mesh_R2_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, p_other_mesh_R3_u), + "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, p_R3_u), + "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(tensorProduct(p_u, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R1x1_u, p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2x2_u, p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3x3_u, p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(tensorProduct(p_Vector3_u, p_Vector2_w), "error: invalid operand type Vh(P0Vector:R)"); + } + SECTION("det Vh -> Vh") { CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // @@ -675,6 +699,48 @@ TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions3D", "[scheme]") REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); } + SECTION("tensorProduct Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(p_u, TinyVector<2>{1, 2}), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(p_Vector3_u, TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + + REQUIRE_THROWS_WITH(tensorProduct(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(tensorProduct(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(tensorProduct(p_R3_u, (TinyVector<1>{-1})), + "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("tensorProduct Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, tensorProduct, // + DiscreteFunctionR1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, tensorProduct, // + DiscreteFunctionR2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, tensorProduct, // + DiscreteFunctionR3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(tensorProduct(TinyVector<2>{1, 2}, p_Vector3_u), + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(tensorProduct((TinyVector<1>{-1}), p_R3_u), + "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + SECTION("sum_of_R* Vh -> R*") { REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); diff --git a/tests/test_MathModule.cpp b/tests/test_MathModule.cpp index f299d1e3678217d4fc6bcb4c08e417264b22a252..89a480e1ac4993b3cdbbd6702f5e2130a1872ec0 100644 --- a/tests/test_MathModule.cpp +++ b/tests/test_MathModule.cpp @@ -13,7 +13,7 @@ TEST_CASE("MathModule", "[language]") MathModule math_module; const auto& name_builtin_function = math_module.getNameBuiltinFunctionMap(); - REQUIRE(name_builtin_function.size() == 42); + REQUIRE(name_builtin_function.size() == 45); SECTION("Z -> N") { @@ -458,6 +458,63 @@ TEST_CASE("MathModule", "[language]") } } + SECTION("(R^d, R^d) -> R^dxd") + { + SECTION("tensorProduct:R^1*R^1") + { + TinyVector<1> arg0{3}; + TinyVector<1> arg1{2}; + + DataVariant arg0_variant = arg0; + DataVariant arg1_variant = arg1; + + auto i_function = name_builtin_function.find("tensorProduct:R^1*R^1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg0_variant, arg1_variant}); + + const TinyMatrix<1> result = tensorProduct(arg0, arg1); + REQUIRE(std::get<TinyMatrix<1>>(result_variant) == result); + } + + SECTION("tensorProduct:R^2*R^2") + { + TinyVector<2> arg0{3, 2}; + TinyVector<2> arg1{-2, 5}; + + DataVariant arg0_variant = arg0; + DataVariant arg1_variant = arg1; + + auto i_function = name_builtin_function.find("tensorProduct:R^2*R^2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg0_variant, arg1_variant}); + + const TinyMatrix<2> result = tensorProduct(arg0, arg1); + REQUIRE(std::get<TinyMatrix<2>>(result_variant) == result); + } + + SECTION("tensorProduct:R^3*R^3") + { + TinyVector<3> arg0{3, 2, 4}; + TinyVector<3> arg1{-2, 5, 2}; + + DataVariant arg0_variant = arg0; + DataVariant arg1_variant = arg1; + + auto i_function = name_builtin_function.find("tensorProduct:R^3*R^3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg0_variant, arg1_variant}); + + const TinyMatrix<3> result = tensorProduct(arg0, arg1); + REQUIRE(std::get<TinyMatrix<3>>(result_variant) == result); + } + } + SECTION("R^dxd -> double") { SECTION("det:R^1x1")