diff --git a/doc/userdoc.org b/doc/userdoc.org index eaac7da46edb913aff2df4d527d7c9ac20456cfe..8270c6076e9ef1f65e217c06da6722f0d8a0c02c 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -4740,11 +4740,14 @@ Running this code produces the gnuplot file displayed in Figure ***** ~gnuplot~ writers <<gnuplot-writers>> -There are two ~gnuplot~ writers. One is dedicated to output of dimension -1 results (~gnuplot_1d_writer~) and the other allows post processing in -dimension 1 and 2 (~gnuplot_writer~). - -Both of these writers can be used for single output or time series +There are three ~gnuplot~ writers. One is dedicated to output of +dimension 1 results (~gnuplot_1d_writer~), the second allows post +processing in dimension 1 and 2 (~gnuplot_writer~) and the third can be +used to write arbitrary data in the ~gnuplot~ format, whichever the +space dimension is (~gnuplot_raw_writer~). The last one is useful to +create scatter plots for instance. + +All of these writers can be used for single output or time series outputs. In the case of single output, the filename is completed by adding the extension ~.gnu~, in the case of time series, the filename is extending by adding ~.abcd.gnu~, where ~abcd~ is the number in the output @@ -5006,6 +5009,58 @@ The gnuplot result is displayed on Figure [[fig:writer-gp-2d-cos-sin]]. This is the time series function in the case of the ~gnuplot_writer~. It behaves similarly to [[gnuplot-1d-series]]. +****** ~gnuplot_raw_writer~ functions <<gnuplot-raw-writer-function>> + +These writers are used to store raw data to the ~gnuplot~ format. Doing +so, it is the user responsibility to store coordinates in the file if +needed. Therefore it can be used in any space dimension. + +******* ~gnuplot_raw_writer: string -> writer~ + +Here is an illustrating example in dimension 3, see the result on +Figure [[fig:writer-raw-sin]]. +#+BEGIN_SRC pugs :exports both :results none + import mesh; + import scheme; + import writer; + import math; + + let m:mesh, m = cartesianMesh([0,0,0], [2,2,2], (10,10,10)); + + let pi:R, pi = acos(-1); + let sin_pi_x:R^3 -> R, x -> sin(pi*dot(x,x)); + + let fh:Vh, fh = interpolate(m, P0(), sin_pi_x); + + let r:Vh, r = sqrt(dot(cell_center(m),cell_center(m))); + + write(gnuplot_raw_writer("raw_sin"), (name_output(r,"r"), name_output(fh, "f"))); +#+END_SRC + +#+NAME: writer-raw-sin-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/raw-sin.png") + reset + set grid + set border + unset key + set xtics + set ytics + set square + set terminal png truecolor enhanced size 628,400 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/raw_sin.gnu)' lw 2 w lp +#+END_SRC + +#+CAPTION: Example of produced gnuplot results from the ~gnuplot_raw_writer~. +#+NAME: fig:writer-raw-sin +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: writer-raw-sin-img + +******* ~gnuplot_raw_writer: string*R -> writer~ + +This is the time series function in the case of the ~gnuplot_raw_writer~. It +behaves similarly to [[gnuplot-1d-series]]. + ***** ~vtk~ writers For more complex post processing (including 3d), ~pugs~ can generate ~vtk~ 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 afb9dbe0cf16f100e1367c9843325aa5bdec80ad..5f5199af2d850edc93dc961e00dbe4a4ead58116 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/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index f0c1b03df96cf1db239bb300cae2fbf797a17fd5..8481a1ed20958162866820c139983971e35f373b 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -665,6 +665,27 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("cell_center", + std::function( + + [](const std::shared_ptr<const MeshVariant>& mesh_v) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return std::visit( + [&](auto&& mesh) { + using MeshType = mesh_type_t<decltype(mesh)>; + if constexpr (is_polygonal_mesh_v<MeshType>) { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0(mesh_v, + MeshDataManager::instance().getMeshData(*mesh).xj())); + } else { + throw NormalError("unexpected mesh type"); + } + }, + mesh_v->variant()); + } + + )); + this->_addBuiltinFunction("hyperelastic_dt", std::function( [](const std::shared_ptr<const DiscreteFunctionVariant>& c) -> double { diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp index 837bc1252d64c5c851ac65561c049b79403ce980..6d84506501de277f1970c13a7c24cd587ed79f20 100644 --- a/src/language/modules/WriterModule.cpp +++ b/src/language/modules/WriterModule.cpp @@ -12,6 +12,7 @@ #include <mesh/Mesh.hpp> #include <output/GnuplotWriter.hpp> #include <output/GnuplotWriter1D.hpp> +#include <output/GnuplotWriterRaw.hpp> #include <output/IWriter.hpp> #include <output/NamedDiscreteFunction.hpp> #include <output/NamedItemArrayVariant.hpp> @@ -81,6 +82,23 @@ WriterModule::WriterModule() )); + this->_addBuiltinFunction("gnuplot_raw_writer", std::function( + + [](const std::string& filename) -> std::shared_ptr<const IWriter> { + return std::make_shared<GnuplotWriterRaw>(filename); + } + + )); + + this->_addBuiltinFunction("gnuplot_raw_writer", + std::function( + + [](const std::string& filename, const double& period) -> std::shared_ptr<const IWriter> { + return std::make_shared<GnuplotWriterRaw>(filename, period); + } + + )); + this->_addBuiltinFunction("name_output", std::function( [](std::shared_ptr<const DiscreteFunctionVariant> discrete_function, 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/output/CMakeLists.txt b/src/output/CMakeLists.txt index 051e96480431aaa733059e2cf9c9518b29216812..fc975ba9b8234d8f70bd850a39bef58360e64108 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -4,6 +4,8 @@ add_library( PugsOutput GnuplotWriter.cpp GnuplotWriter1D.cpp + GnuplotWriterBase.cpp + GnuplotWriterRaw.cpp VTKWriter.cpp WriterBase.cpp) diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp index 9e73b449adc517ba80379b413a606f4ef71b807a..4b249aa2e5f8bd11a6251f9edac463d69b8562df 100644 --- a/src/output/GnuplotWriter.cpp +++ b/src/output/GnuplotWriter.cpp @@ -7,94 +7,14 @@ #include <mesh/MeshDataManager.hpp> #include <mesh/MeshTraits.hpp> #include <mesh/MeshVariant.hpp> +#include <utils/Demangle.hpp> #include <utils/Filesystem.hpp> #include <utils/Messenger.hpp> #include <utils/PugsTraits.hpp> #include <utils/RevisionInfo.hpp> #include <utils/Stringify.hpp> -#include <utils/Demangle.hpp> - #include <fstream> -#include <iomanip> - -std::string -GnuplotWriter::_getDateAndVersionComment() const -{ - std::ostringstream os; - - std::time_t now = std::time(nullptr); - os << "# Generated by pugs: " << std::ctime(&now); - os << "# version: " << RevisionInfo::version() << '\n'; - os << "# tag: " << RevisionInfo::gitTag() << '\n'; - os << "# HEAD: " << RevisionInfo::gitHead() << '\n'; - os << "# hash: " << RevisionInfo::gitHash() << " (" << ((RevisionInfo::gitIsClean()) ? "clean" : "dirty") << ")\n"; - os << '\n'; - - return os.str(); -} - -std::string -GnuplotWriter::_getFilename() const -{ - std::ostringstream sout; - sout << m_base_filename; - if (m_period_manager.has_value()) { - sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes(); - } - sout << ".gnu"; - return sout.str(); -} - -template <size_t Dimension> -void -GnuplotWriter::_writePreamble(const OutputNamedItemDataSet& output_named_item_data_set, std::ostream& fout) const -{ - fout << "# list of data\n"; - fout << "# 1:x"; - if constexpr (Dimension > 1) { - fout << " 2:y"; - } - uint64_t i = Dimension + 1; - for (const auto& i_named_item_data : output_named_item_data_set) { - const std::string name = i_named_item_data.first; - const auto& item_data_variant = i_named_item_data.second; - std::visit( - [&](auto&& item_data) { - using ItemDataType = std::decay_t<decltype(item_data)>; - using DataType = std::decay_t<typename ItemDataType::data_type>; - if constexpr (is_item_value_v<ItemDataType>) { - if constexpr (std::is_arithmetic_v<DataType>) { - fout << ' ' << i++ << ':' << name; - } else if constexpr (is_tiny_vector_v<DataType>) { - for (size_t j = 0; j < DataType{}.dimension(); ++j) { - fout << ' ' << i++ << ':' << name << '[' << j << ']'; - } - } else if constexpr (is_tiny_matrix_v<DataType>) { - for (size_t j = 0; j < DataType{}.numberOfRows(); ++j) { - for (size_t k = 0; k < DataType{}.numberOfColumns(); ++k) { - fout << ' ' << i++ << ':' << name << '(' << j << ',' << k << ')'; - } - } - } else { - throw UnexpectedError("invalid data type"); - } - } else if constexpr (is_item_array_v<ItemDataType>) { - if constexpr (std::is_arithmetic_v<DataType>) { - for (size_t j = 0; j < item_data.sizeOfArrays(); ++j) { - fout << ' ' << i++ << ':' << name << '[' << j << ']'; - } - } else { - throw UnexpectedError("invalid data type"); - } - } else { - throw UnexpectedError("invalid ItemData type"); - } - }, - item_data_variant); - } - fout << "\n\n"; -} template <typename DataType> void @@ -263,7 +183,7 @@ GnuplotWriter::_write(const MeshType& mesh, if (time.has_value()) { fout << "# time = " << *time << "\n\n"; } - this->_writePreamble<MeshType::Dimension>(output_named_item_data_set, fout); + this->_writePreamble(MeshType::Dimension, output_named_item_data_set, true /*store coordinates*/, fout); } for (const auto& [name, item_data_variant] : output_named_item_data_set) { diff --git a/src/output/GnuplotWriter.hpp b/src/output/GnuplotWriter.hpp index 7bfc671601b5a442619354d3c989572fa0d7cc2b..f1a1f030315c2991c814c8af2212a6d34bc609ab 100644 --- a/src/output/GnuplotWriter.hpp +++ b/src/output/GnuplotWriter.hpp @@ -1,7 +1,7 @@ #ifndef GNUPLOT_WRITER_HPP #define GNUPLOT_WRITER_HPP -#include <output/WriterBase.hpp> +#include <output/GnuplotWriterBase.hpp> #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> @@ -13,13 +13,9 @@ class MeshVariant; #include <optional> #include <string> -class GnuplotWriter final : public WriterBase +class GnuplotWriter final : public GnuplotWriterBase { private: - std::string _getDateAndVersionComment() const; - - std::string _getFilename() const; - template <typename DataType> void _writeCellData(const CellValue<DataType>& cell_value, CellId cell_id, std::ostream& fout) const; @@ -32,9 +28,6 @@ class GnuplotWriter final : public WriterBase template <typename DataType> void _writeNodeData(const NodeArray<DataType>& node_value, NodeId cell_id, std::ostream& fout) const; - template <size_t Dimension> - void _writePreamble(const OutputNamedItemDataSet& output_named_item_data_set, std::ostream& fout) const; - template <typename ItemDataT> void _writeData(const ItemDataT& item_data, [[maybe_unused]] CellId cell_id, @@ -67,9 +60,11 @@ class GnuplotWriter final : public WriterBase return Type::gnuplot; } - GnuplotWriter(const std::string& base_filename) : WriterBase(base_filename) {} + GnuplotWriter(const std::string& base_filename) : GnuplotWriterBase(base_filename) {} - GnuplotWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {} + GnuplotWriter(const std::string& base_filename, const double time_period) + : GnuplotWriterBase(base_filename, time_period) + {} ~GnuplotWriter() = default; }; diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp index f5d6dd7b2c0cd35696b21457194f72c3a4289c9a..10aafe1f5fbd478a8aa0d39b86ecd5f76b8aa64f 100644 --- a/src/output/GnuplotWriter1D.cpp +++ b/src/output/GnuplotWriter1D.cpp @@ -7,118 +7,13 @@ #include <mesh/MeshDataManager.hpp> #include <mesh/MeshTraits.hpp> #include <mesh/MeshVariant.hpp> +#include <utils/Demangle.hpp> #include <utils/Filesystem.hpp> #include <utils/Messenger.hpp> #include <utils/PugsTraits.hpp> -#include <utils/RevisionInfo.hpp> #include <utils/Stringify.hpp> -#include <utils/Demangle.hpp> - #include <fstream> -#include <iomanip> - -std::string -GnuplotWriter1D::_getDateAndVersionComment() const -{ - std::ostringstream os; - - std::time_t now = std::time(nullptr); - os << "# Generated by pugs: " << std::ctime(&now); - os << "# version: " << RevisionInfo::version() << '\n'; - os << "# tag: " << RevisionInfo::gitTag() << '\n'; - os << "# HEAD: " << RevisionInfo::gitHead() << '\n'; - os << "# hash: " << RevisionInfo::gitHash() << " (" << ((RevisionInfo::gitIsClean()) ? "clean" : "dirty") << ")\n"; - os << '\n'; - - return os.str(); -} - -std::string -GnuplotWriter1D::_getFilename() const -{ - std::ostringstream sout; - sout << m_base_filename; - if (m_period_manager.has_value()) { - sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes(); - } - sout << ".gnu"; - return sout.str(); -} - -template <typename ItemDataType> -bool -GnuplotWriter1D::_is_cell_data(const ItemDataType&) const -{ - return ItemDataType::item_t == ItemType::cell; -} - -template <typename ItemDataType> -bool -GnuplotWriter1D::_is_face_data(const ItemDataType&) const -{ - return ItemDataType::item_t == ItemType::face; -} - -template <typename ItemDataType> -bool -GnuplotWriter1D::_is_edge_data(const ItemDataType&) const -{ - return ItemDataType::item_t == ItemType::edge; -} - -template <typename ItemDataType> -bool -GnuplotWriter1D::_is_node_data(const ItemDataType&) const -{ - return ItemDataType::item_t == ItemType::node; -} - -void -GnuplotWriter1D::_writePreamble(const OutputNamedItemDataSet& output_named_item_data_set, std::ostream& fout) const -{ - fout << "# list of data\n"; - fout << "# 1:x"; - uint64_t i = 2; - for (const auto& i_named_item_data : output_named_item_data_set) { - const std::string name = i_named_item_data.first; - const auto& item_data_variant = i_named_item_data.second; - std::visit( - [&](auto&& item_data) { - using ItemDataType = std::decay_t<decltype(item_data)>; - using DataType = std::decay_t<typename ItemDataType::data_type>; - if constexpr (is_item_value_v<ItemDataType>) { - if constexpr (std::is_arithmetic_v<DataType>) { - fout << ' ' << i++ << ':' << name; - } else if constexpr (is_tiny_vector_v<DataType>) { - for (size_t j = 0; j < DataType{}.dimension(); ++j) { - fout << ' ' << i++ << ':' << name << '[' << j << ']'; - } - } else if constexpr (is_tiny_matrix_v<DataType>) { - for (size_t j = 0; j < DataType{}.numberOfRows(); ++j) { - for (size_t k = 0; k < DataType{}.numberOfColumns(); ++k) { - fout << ' ' << i++ << ':' << name << '(' << j << ',' << k << ')'; - } - } - } else { - throw UnexpectedError("invalid data type"); - } - } else if constexpr (is_item_array_v<ItemDataType>) { - if constexpr (std::is_arithmetic_v<DataType>) { - for (size_t j = 0; j < item_data.sizeOfArrays(); ++j) { - fout << ' ' << i++ << ':' << name << '[' << j << ']'; - } - } else { - throw UnexpectedError("invalid data type"); - } - } else { - throw UnexpectedError("invalid ItemData type"); - } - }, - item_data_variant); - } - fout << "\n\n"; -} template <typename DataType, ItemType item_type> size_t @@ -341,7 +236,7 @@ GnuplotWriter1D::_write(const MeshType& mesh, fout << "# time = " << *time << "\n\n"; } - _writePreamble(output_named_item_data_set, fout); + _writePreamble(MeshType::Dimension, output_named_item_data_set, true /*store coordinates*/, fout); } if (has_cell_data) { @@ -357,7 +252,7 @@ GnuplotWriter1D::_writeMesh(const MeshVariant&) const std::ostringstream errorMsg; errorMsg << "gnuplot_1d_writer does not write meshes\n" << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue - << "gnuplot_writer" << rang::fg::reset << " instead"; + << "gnuplot_writer" << rang::fg::reset << " instead"; throw NormalError(errorMsg.str()); } diff --git a/src/output/GnuplotWriter1D.hpp b/src/output/GnuplotWriter1D.hpp index 8b49e1935f5526603960e6995613cb3481eabd30..d105fdf05e52ef81bf37e76ecfa61eac8ed38edf 100644 --- a/src/output/GnuplotWriter1D.hpp +++ b/src/output/GnuplotWriter1D.hpp @@ -1,7 +1,7 @@ #ifndef GNUPLOT_WRITER_1D_HPP #define GNUPLOT_WRITER_1D_HPP -#include <output/WriterBase.hpp> +#include <output/GnuplotWriterBase.hpp> #include <algebra/TinyMatrix.hpp> #include <algebra/TinyVector.hpp> @@ -13,25 +13,9 @@ class MeshVariant; #include <optional> #include <string> -class GnuplotWriter1D final : public WriterBase +class GnuplotWriter1D final : public GnuplotWriterBase { private: - std::string _getDateAndVersionComment() const; - - std::string _getFilename() const; - - template <typename ItemDataType> - bool _is_cell_data(const ItemDataType&) const; - - template <typename ItemDataType> - bool _is_face_data(const ItemDataType&) const; - - template <typename ItemDataType> - bool _is_edge_data(const ItemDataType&) const; - - template <typename ItemDataType> - bool _is_node_data(const ItemDataType&) const; - template <typename DataType, ItemType item_type> size_t _itemDataNbRow(const ItemValue<DataType, item_type>&) const; @@ -43,8 +27,6 @@ class GnuplotWriter1D final : public WriterBase const OutputNamedItemDataSet& output_named_item_data_set, std::ostream& fout) const; - void _writePreamble(const OutputNamedItemDataSet& output_named_item_value_set, std::ostream& fout) const; - template <MeshConcept MeshType> void _write(const MeshType& mesh, const OutputNamedItemDataSet& output_named_item_value_set, @@ -66,9 +48,10 @@ class GnuplotWriter1D final : public WriterBase return Type::gnuplot_1d; } - GnuplotWriter1D(const std::string& base_filename) : WriterBase(base_filename) {} + GnuplotWriter1D(const std::string& base_filename) : GnuplotWriterBase(base_filename) {} - GnuplotWriter1D(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) + GnuplotWriter1D(const std::string& base_filename, const double time_period) + : GnuplotWriterBase(base_filename, time_period) {} ~GnuplotWriter1D() = default; diff --git a/src/output/GnuplotWriterBase.cpp b/src/output/GnuplotWriterBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..110c03f77406c3e68e0ffb35b8528c5639948a94 --- /dev/null +++ b/src/output/GnuplotWriterBase.cpp @@ -0,0 +1,94 @@ +#include <output/GnuplotWriterBase.hpp> + +#include <output/OutputNamedItemValueSet.hpp> +#include <utils/RevisionInfo.hpp> + +#include <ctime> +#include <iomanip> +#include <sstream> + +std::string +GnuplotWriterBase::_getDateAndVersionComment() const +{ + std::ostringstream os; + + std::time_t now = std::time(nullptr); + os << "# Generated by pugs: " << std::ctime(&now); + os << "# version: " << RevisionInfo::version() << '\n'; + os << "# tag: " << RevisionInfo::gitTag() << '\n'; + os << "# HEAD: " << RevisionInfo::gitHead() << '\n'; + os << "# hash: " << RevisionInfo::gitHash() << " (" << ((RevisionInfo::gitIsClean()) ? "clean" : "dirty") << ")\n"; + os << '\n'; + + return os.str(); +} + +std::string +GnuplotWriterBase::_getFilename() const +{ + std::ostringstream sout; + sout << m_base_filename; + if (m_period_manager.has_value()) { + sout << '.' << std::setfill('0') << std::setw(4) << m_period_manager->nbSavedTimes(); + } + sout << ".gnu"; + return sout.str(); +} + +void +GnuplotWriterBase::_writePreamble(const size_t& dimension, + const OutputNamedItemDataSet& output_named_item_data_set, + const bool& store_coordinates, + std::ostream& fout) const +{ + fout << "# list of data\n"; + uint64_t i = 0; + + fout << "#"; + if (store_coordinates) { + fout << " 1:x"; + if (dimension > 1) { + fout << " 2:y"; + } + i = dimension; + } + + for (const auto& i_named_item_data : output_named_item_data_set) { + const std::string name = i_named_item_data.first; + const auto& item_data_variant = i_named_item_data.second; + std::visit( + [&](auto&& item_data) { + using ItemDataType = std::decay_t<decltype(item_data)>; + using DataType = std::decay_t<typename ItemDataType::data_type>; + if constexpr (is_item_value_v<ItemDataType>) { + if constexpr (std::is_arithmetic_v<DataType>) { + fout << ' ' << i++ << ':' << name; + } else if constexpr (is_tiny_vector_v<DataType>) { + for (size_t j = 0; j < DataType{}.dimension(); ++j) { + fout << ' ' << i++ << ':' << name << '[' << j << ']'; + } + } else if constexpr (is_tiny_matrix_v<DataType>) { + for (size_t j = 0; j < DataType{}.numberOfRows(); ++j) { + for (size_t k = 0; k < DataType{}.numberOfColumns(); ++k) { + fout << ' ' << i++ << ':' << name << '(' << j << ',' << k << ')'; + } + } + } else { + throw UnexpectedError("invalid data type"); + } + } else if constexpr (is_item_array_v<ItemDataType>) { + if constexpr (std::is_arithmetic_v<DataType>) { + for (size_t j = 0; j < item_data.sizeOfArrays(); ++j) { + fout << ' ' << i++ << ':' << name << '[' << j << ']'; + } + } else { + throw UnexpectedError("invalid data type"); + } + } else { + throw UnexpectedError("invalid ItemData type"); + } + }, + item_data_variant); + } + fout << "\n\n"; +} diff --git a/src/output/GnuplotWriterBase.hpp b/src/output/GnuplotWriterBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a99390facb8d2bd67cc323d676d305f26401dd6e --- /dev/null +++ b/src/output/GnuplotWriterBase.hpp @@ -0,0 +1,58 @@ +#ifndef GNUPLOT_WRITER_BASE_HPP +#define GNUPLOT_WRITER_BASE_HPP + +#include <output/WriterBase.hpp> + +#include <utils/PugsMacros.hpp> + +class GnuplotWriterBase : public WriterBase +{ + protected: + std::string _getDateAndVersionComment() const; + + std::string _getFilename() const; + + void _writePreamble(const size_t& dimension, + const OutputNamedItemDataSet& output_named_item_data_set, + const bool& store_coordinates, + std::ostream& fout) const; + + template <typename ItemDataType> + PUGS_INLINE bool + _is_cell_data(const ItemDataType&) const + { + return ItemDataType::item_t == ItemType::cell; + } + + template <typename ItemDataType> + PUGS_INLINE bool + _is_face_data(const ItemDataType&) const + { + return ItemDataType::item_t == ItemType::face; + } + + template <typename ItemDataType> + PUGS_INLINE bool + _is_edge_data(const ItemDataType&) const + { + return ItemDataType::item_t == ItemType::edge; + } + + template <typename ItemDataType> + PUGS_INLINE bool + _is_node_data(const ItemDataType&) const + { + return ItemDataType::item_t == ItemType::node; + } + + public: + GnuplotWriterBase(const std::string& base_filename, const double& time_period) + : WriterBase(base_filename, time_period) + {} + + GnuplotWriterBase(const std::string& base_filename) : WriterBase(base_filename) {} + + virtual ~GnuplotWriterBase() = default; +}; + +#endif // GNUPLOT_WRITER_BASE_HPP diff --git a/src/output/GnuplotWriterRaw.cpp b/src/output/GnuplotWriterRaw.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac93ba0029f3d73583c98d62c85beb7901f3569f --- /dev/null +++ b/src/output/GnuplotWriterRaw.cpp @@ -0,0 +1,269 @@ +#include <output/GnuplotWriterRaw.hpp> + +#include <mesh/Connectivity.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/MeshData.hpp> +#include <mesh/MeshDataManager.hpp> +#include <mesh/MeshTraits.hpp> +#include <mesh/MeshVariant.hpp> +#include <utils/Filesystem.hpp> +#include <utils/Messenger.hpp> +#include <utils/PugsTraits.hpp> +#include <utils/RevisionInfo.hpp> +#include <utils/Stringify.hpp> + +#include <utils/Demangle.hpp> + +#include <fstream> +#include <iomanip> + +template <typename DataType, ItemType item_type> +size_t +GnuplotWriterRaw::_itemDataNbRow(const ItemValue<DataType, item_type>&) const +{ + if constexpr (std::is_arithmetic_v<DataType>) { + return 1; + } else if constexpr (is_tiny_vector_v<std::decay_t<DataType>>) { + return DataType::Dimension; + } else if constexpr (is_tiny_matrix_v<std::decay_t<DataType>>) { + return DataType{}.dimension(); + } else { + throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>()); + } +} + +template <typename DataType, ItemType item_type> +size_t +GnuplotWriterRaw::_itemDataNbRow(const ItemArray<DataType, item_type>& item_array) const +{ + return item_array.sizeOfArrays(); +} + +template <MeshConcept MeshType, ItemType item_type> +void +GnuplotWriterRaw::_writeItemDatas(const MeshType& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::ostream& fout) const +{ + using ItemId = ItemIdT<item_type>; + + const size_t number_of_columns = [&] { + size_t nb_columns = 0; + for (const auto& [name, item_data] : output_named_item_data_set) { + std::visit([&](auto&& value) { nb_columns += _itemDataNbRow(value); }, item_data); + } + return nb_columns; + }(); + + auto is_owned = mesh.connectivity().template isOwned<item_type>(); + + const size_t& number_of_owned_lines = [&]() { + if (parallel::size() > 1) { + size_t number_of_owned_items = 0; + for (ItemId item_id = 0; item_id < mesh.template numberOf<item_type>(); ++item_id) { + if (is_owned[item_id]) { + ++number_of_owned_items; + } + } + + return number_of_owned_items; + } else { + return mesh.template numberOf<item_type>(); + } + }(); + + Array<double> values{number_of_columns * number_of_owned_lines}; + + size_t column_number = 0; + for (const auto& [name, output_item_data] : output_named_item_data_set) { + std::visit( + [&](auto&& item_data) { + using ItemDataT = std::decay_t<decltype(item_data)>; + if constexpr (ItemDataT::item_t == item_type) { + if constexpr (is_item_value_v<ItemDataT>) { + using DataT = std::decay_t<typename ItemDataT::data_type>; + size_t index = 0; + for (ItemId item_id = 0; item_id < item_data.numberOfItems(); ++item_id) { + if (is_owned[item_id]) { + if constexpr (std::is_arithmetic_v<DataT>) { + values[number_of_columns * index + column_number] = item_data[item_id]; + } else if constexpr (is_tiny_vector_v<DataT>) { + const size_t k = number_of_columns * index + column_number; + for (size_t j = 0; j < DataT::Dimension; ++j) { + values[k + j] = item_data[item_id][j]; + } + } else if constexpr (is_tiny_matrix_v<DataT>) { + size_t k = number_of_columns * index + column_number; + for (size_t i = 0; i < DataT{}.numberOfRows(); ++i) { + for (size_t j = 0; j < DataT{}.numberOfColumns(); ++j) { + values[k++] = item_data[item_id](i, j); + } + } + } + ++index; + } + } + } else { + using DataT = std::decay_t<typename ItemDataT::data_type>; + size_t index = 0; + for (ItemId item_id = 0; item_id < item_data.numberOfItems(); ++item_id) { + if (is_owned[item_id]) { + if constexpr (std::is_arithmetic_v<DataT>) { + const size_t k = number_of_columns * index + column_number; + for (size_t j = 0; j < item_data.sizeOfArrays(); ++j) { + values[k + j] = item_data[item_id][j]; + } + } + ++index; + } + } + } + } + column_number += _itemDataNbRow(item_data); + }, + output_item_data); + } + + if (parallel::size() > 1) { + values = parallel::gatherVariable(values, 0); + } + + if (parallel::rank() == 0) { + Assert(values.size() % number_of_columns == 0); + + std::vector<size_t> line_numbers(values.size() / number_of_columns); + for (size_t i = 0; i < line_numbers.size(); ++i) { + line_numbers[i] = i; + } + + std::sort(line_numbers.begin(), line_numbers.end(), + [&](size_t i, size_t j) { return values[i * number_of_columns] < values[j * number_of_columns]; }); + + for (auto i_line : line_numbers) { + fout << values[i_line * number_of_columns]; + for (size_t j = 1; j < number_of_columns; ++j) { + fout << ' ' << values[i_line * number_of_columns + j]; + } + fout << '\n'; + } + } +} + +template <MeshConcept MeshType> +void +GnuplotWriterRaw::_write(const MeshType& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::optional<double> time) const +{ + bool has_cell_data = false; + for (const auto& [name, item_data_variant] : output_named_item_data_set) { + has_cell_data |= std::visit([&](auto&& item_data) { return this->_is_cell_data(item_data); }, item_data_variant); + } + + for (const auto& [name, item_data_variant] : output_named_item_data_set) { + std::visit( + [&, name = name](auto&& item_data) { + if (this->_is_face_data(item_data)) { + std::ostringstream error_msg; + error_msg << "gnuplot_raw_writer does not support face data, cannot save variable \"" << rang::fgB::yellow + << name << rang::fg::reset << '"'; + throw NormalError(error_msg.str()); + } + }, + item_data_variant); + } + + for (const auto& [name, item_data_variant] : output_named_item_data_set) { + std::visit( + [&, name = name](auto&& item_data) { + if (this->_is_edge_data(item_data)) { + std::ostringstream error_msg; + error_msg << "gnuplot_1d_writer does not support edge data, cannot save variable \"" << rang::fgB::yellow + << name << rang::fg::reset << '"'; + throw NormalError(error_msg.str()); + } + }, + item_data_variant); + } + + bool has_node_data = false; + for (const auto& [name, item_data_variant] : output_named_item_data_set) { + has_node_data |= std::visit([&](auto&& item_data) { return this->_is_node_data(item_data); }, item_data_variant); + } + + if (has_cell_data and has_node_data) { + throw NormalError("cannot store both node and cell data in the same gnuplot file"); + } + + std::ofstream fout; + + if (parallel::rank() == 0) { + fout.open(_getFilename()); + if (not fout) { + std::ostringstream error_msg; + error_msg << "cannot create file \"" << rang::fgB::yellow << _getFilename() << rang::fg::reset << '"'; + throw NormalError(error_msg.str()); + } + + fout.precision(15); + fout.setf(std::ios_base::scientific); + fout << _getDateAndVersionComment(); + + if (time.has_value()) { + fout << "# time = " << *time << "\n\n"; + } + + _writePreamble(MeshType::Dimension, output_named_item_data_set, false /*do not store coordinates*/, fout); + } + + if (has_cell_data) { + this->_writeItemDatas<MeshType, ItemType::cell>(mesh, output_named_item_data_set, fout); + } else { // has_node_value + this->_writeItemDatas<MeshType, ItemType::node>(mesh, output_named_item_data_set, fout); + } +} + +void +GnuplotWriterRaw::_writeMesh(const MeshVariant&) const +{ + std::ostringstream errorMsg; + errorMsg << "gnuplot_raw_writer does not write meshes\n" + << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue + << "gnuplot_writer" << rang::fg::reset << " instead"; + throw NormalError(errorMsg.str()); +} + +void +GnuplotWriterRaw::_writeAtTime(const MeshVariant& mesh_v, + const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list, + double time) const +{ + OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list); + + std::visit( + [&](auto&& p_mesh) { + using MeshType = mesh_type_t<decltype(p_mesh)>; + if constexpr (MeshType::Dimension == 1) { + this->_write(*p_mesh, output_named_item_data_set, time); + } else if constexpr (MeshType::Dimension == 2) { + std::ostringstream errorMsg; + errorMsg << "gnuplot_raw_writer is not available in dimension " << stringify(MeshType::Dimension) << '\n' + << rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue + << "gnuplot_writer" << rang::fg::reset << " in dimension 2"; + throw NormalError(errorMsg.str()); + } else { + throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension)); + } + }, + mesh_v.variant()); +} + +void +GnuplotWriterRaw::_write(const MeshVariant& mesh_v, + const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const +{ + OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_data_list); + + std::visit([&](auto&& p_mesh) { this->_write(*p_mesh, output_named_item_data_set, {}); }, mesh_v.variant()); +} diff --git a/src/output/GnuplotWriterRaw.hpp b/src/output/GnuplotWriterRaw.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d72b77162f65b2500d89313f3a0005ce9aaa8182 --- /dev/null +++ b/src/output/GnuplotWriterRaw.hpp @@ -0,0 +1,60 @@ +#ifndef GNUPLOT_WRITER_RAW_HPP +#define GNUPLOT_WRITER_RAW_HPP + +#include <output/GnuplotWriterBase.hpp> + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> +#include <mesh/MeshTraits.hpp> +#include <output/OutputNamedItemValueSet.hpp> + +class MeshVariant; + +#include <optional> +#include <string> + +class GnuplotWriterRaw final : public GnuplotWriterBase +{ + private: + template <typename DataType, ItemType item_type> + size_t _itemDataNbRow(const ItemValue<DataType, item_type>&) const; + + template <typename DataType, ItemType item_type> + size_t _itemDataNbRow(const ItemArray<DataType, item_type>&) const; + + template <MeshConcept MeshType, ItemType item_type> + void _writeItemDatas(const MeshType& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::ostream& fout) const; + + template <MeshConcept MeshType> + void _write(const MeshType& mesh, + const OutputNamedItemDataSet& output_named_item_value_set, + std::optional<double> time) const; + + void _writeAtTime(const MeshVariant& mesh_v, + const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list, + double time) const final; + + void _write(const MeshVariant& mesh_v, + const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const final; + + void _writeMesh(const MeshVariant& mesh_v) const final; + + public: + Type + type() const final + { + return Type::gnuplot_raw; + } + + GnuplotWriterRaw(const std::string& base_filename) : GnuplotWriterBase(base_filename) {} + + GnuplotWriterRaw(const std::string& base_filename, const double time_period) + : GnuplotWriterBase(base_filename, time_period) + {} + + ~GnuplotWriterRaw() = default; +}; + +#endif // GNUPLOT_WRITER_RAW_HPP diff --git a/src/output/IWriter.hpp b/src/output/IWriter.hpp index 742d0cf349a6d64356cc6021ec0a380247c1d50b..85060e37e8abbc46c06fe70933c3a032721dd01c 100644 --- a/src/output/IWriter.hpp +++ b/src/output/IWriter.hpp @@ -15,6 +15,7 @@ class IWriter { gnuplot, gnuplot_1d, + gnuplot_raw, vtk }; diff --git a/src/scheme/AxisBoundaryConditionDescriptor.hpp b/src/scheme/AxisBoundaryConditionDescriptor.hpp index 07ab3be487f30af021fb51ceae84892091e3ae8b..1dbbf98997a380e05d2681e17962ab4181ce5d47 100644 --- a/src/scheme/AxisBoundaryConditionDescriptor.hpp +++ b/src/scheme/AxisBoundaryConditionDescriptor.hpp @@ -2,11 +2,11 @@ #define AXIS_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class AxisBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class AxisBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -16,23 +16,15 @@ class AxisBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return os; } - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; - public: - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { return Type::axis; } - AxisBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) + AxisBoundaryConditionDescriptor(const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor) + : BoundaryConditionDescriptorBase{boundary_descriptor} { ; } diff --git a/src/scheme/BoundaryConditionDescriptorBase.hpp b/src/scheme/BoundaryConditionDescriptorBase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d05dfd6713e1f8026254567c9859dba8dc287785 --- /dev/null +++ b/src/scheme/BoundaryConditionDescriptorBase.hpp @@ -0,0 +1,34 @@ +#ifndef BOUNDARY_CONDITION_DESCRIPTOR_BASE_HPP +#define BOUNDARY_CONDITION_DESCRIPTOR_BASE_HPP + +#include <scheme/IBoundaryConditionDescriptor.hpp> + +class BoundaryConditionDescriptorBase : public IBoundaryConditionDescriptor +{ + protected: + std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; + + public: + const std::shared_ptr<const IBoundaryDescriptor>& + boundaryDescriptor_shared() const final + { + return m_boundary_descriptor; + } + + const IBoundaryDescriptor& + boundaryDescriptor() const final + { + return *m_boundary_descriptor; + } + + BoundaryConditionDescriptorBase(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) + : m_boundary_descriptor{boundary_descriptor} + {} + + BoundaryConditionDescriptorBase(const BoundaryConditionDescriptorBase&) = delete; + BoundaryConditionDescriptorBase(BoundaryConditionDescriptorBase&&) = delete; + + virtual ~BoundaryConditionDescriptorBase() = default; +}; + +#endif // BOUNDARY_CONDITION_DESCRIPTOR_BASE_HPP diff --git a/src/scheme/DirichletBoundaryConditionDescriptor.hpp b/src/scheme/DirichletBoundaryConditionDescriptor.hpp index 32e34081002989cb0d6164332b070c5ad712d1bb..2ddfa649cd151dec643984becae7ae5718ef000a 100644 --- a/src/scheme/DirichletBoundaryConditionDescriptor.hpp +++ b/src/scheme/DirichletBoundaryConditionDescriptor.hpp @@ -3,11 +3,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class DirichletBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class DirichletBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -19,7 +19,6 @@ class DirichletBoundaryConditionDescriptor : public IBoundaryConditionDescriptor const std::string m_name; - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; const FunctionSymbolId m_rhs_symbol_id; public: @@ -35,12 +34,6 @@ class DirichletBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return m_rhs_symbol_id; } - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { @@ -48,9 +41,9 @@ class DirichletBoundaryConditionDescriptor : public IBoundaryConditionDescriptor } DirichletBoundaryConditionDescriptor(const std::string& name, - std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor, const FunctionSymbolId& rhs_symbol_id) - : m_name{name}, m_boundary_descriptor(boundary_descriptor), m_rhs_symbol_id{rhs_symbol_id} + : BoundaryConditionDescriptorBase{boundary_descriptor}, m_name{name}, m_rhs_symbol_id{rhs_symbol_id} { ; } 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/src/scheme/ExternalBoundaryConditionDescriptor.hpp b/src/scheme/ExternalBoundaryConditionDescriptor.hpp index 05fa10eb13822de06bead5c17a674f6b7f94d24c..d015547f88862f7d16825f3888e1814a7702a7cd 100644 --- a/src/scheme/ExternalBoundaryConditionDescriptor.hpp +++ b/src/scheme/ExternalBoundaryConditionDescriptor.hpp @@ -2,12 +2,12 @@ #define EXTERNAL_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <utils/Socket.hpp> #include <memory> -class ExternalBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class ExternalBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -19,7 +19,6 @@ class ExternalBoundaryConditionDescriptor : public IBoundaryConditionDescriptor const std::string m_name; - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; const std::shared_ptr<const Socket> m_socket; public: @@ -35,12 +34,6 @@ class ExternalBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return m_socket; } - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { @@ -48,9 +41,9 @@ class ExternalBoundaryConditionDescriptor : public IBoundaryConditionDescriptor } ExternalBoundaryConditionDescriptor(const std::string& name, - std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor, const std::shared_ptr<const Socket>& socket) - : m_name{name}, m_boundary_descriptor(boundary_descriptor), m_socket{socket} + : BoundaryConditionDescriptorBase{boundary_descriptor}, m_name{name}, m_socket{socket} {} ExternalBoundaryConditionDescriptor(const ExternalBoundaryConditionDescriptor&) = delete; diff --git a/src/scheme/FixedBoundaryConditionDescriptor.hpp b/src/scheme/FixedBoundaryConditionDescriptor.hpp index bc7ca9cca66f393a0458982fd0d169cff49b4a10..b8b5446248f040505d8a8f3653142076ae4d3d97 100644 --- a/src/scheme/FixedBoundaryConditionDescriptor.hpp +++ b/src/scheme/FixedBoundaryConditionDescriptor.hpp @@ -3,11 +3,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class FixedBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class FixedBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -20,20 +20,14 @@ class FixedBoundaryConditionDescriptor : public IBoundaryConditionDescriptor std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; public: - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { return Type::fixed; } - FixedBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) + FixedBoundaryConditionDescriptor(const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor) + : BoundaryConditionDescriptorBase{boundary_descriptor} {} FixedBoundaryConditionDescriptor(const FixedBoundaryConditionDescriptor&) = delete; diff --git a/src/scheme/FourierBoundaryConditionDescriptor.hpp b/src/scheme/FourierBoundaryConditionDescriptor.hpp index 327a98438e1dbab2e5b141f0856525fadb3eeeba..c04995634691554ce3174b7a6b23f0cf086ebed8 100644 --- a/src/scheme/FourierBoundaryConditionDescriptor.hpp +++ b/src/scheme/FourierBoundaryConditionDescriptor.hpp @@ -3,11 +3,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class FourierBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class FourierBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -19,7 +19,6 @@ class FourierBoundaryConditionDescriptor : public IBoundaryConditionDescriptor const std::string m_name; - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; const FunctionSymbolId m_mass_symbol_id; const FunctionSymbolId m_rhs_symbol_id; @@ -42,12 +41,6 @@ class FourierBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return m_rhs_symbol_id; } - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { @@ -55,11 +48,11 @@ class FourierBoundaryConditionDescriptor : public IBoundaryConditionDescriptor } FourierBoundaryConditionDescriptor(const std::string& name, - std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor, const FunctionSymbolId& mass_symbol_id, const FunctionSymbolId& rhs_symbol_id) - : m_name{name}, - m_boundary_descriptor(boundary_descriptor), + : BoundaryConditionDescriptorBase{boundary_descriptor}, + m_name{name}, m_mass_symbol_id{mass_symbol_id}, m_rhs_symbol_id{rhs_symbol_id} { diff --git a/src/scheme/FreeBoundaryConditionDescriptor.hpp b/src/scheme/FreeBoundaryConditionDescriptor.hpp index 2d46f2a36a04cbaca0abc5b83c9ad1983e844841..8b6df26f7bbd155d610cf6bb5de0a47817a86830 100644 --- a/src/scheme/FreeBoundaryConditionDescriptor.hpp +++ b/src/scheme/FreeBoundaryConditionDescriptor.hpp @@ -2,11 +2,11 @@ #define FREE_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class FreeBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class FreeBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -16,15 +16,7 @@ class FreeBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return os; } - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; - public: - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { @@ -32,7 +24,7 @@ class FreeBoundaryConditionDescriptor : public IBoundaryConditionDescriptor } FreeBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) + : BoundaryConditionDescriptorBase{boundary_descriptor} { ; } diff --git a/src/scheme/IBoundaryConditionDescriptor.hpp b/src/scheme/IBoundaryConditionDescriptor.hpp index 1350aa4dba4f7f6739b7de6689c10554ceec6971..58e8b6076ff2c363049de6f107e6a949966d6c72 100644 --- a/src/scheme/IBoundaryConditionDescriptor.hpp +++ b/src/scheme/IBoundaryConditionDescriptor.hpp @@ -2,6 +2,7 @@ #define I_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <iostream> +#include <memory> class IBoundaryDescriptor; @@ -32,7 +33,8 @@ class IBoundaryConditionDescriptor return bcd._write(os); } - virtual const IBoundaryDescriptor& boundaryDescriptor() const = 0; + virtual const std::shared_ptr<const IBoundaryDescriptor>& boundaryDescriptor_shared() const = 0; + virtual const IBoundaryDescriptor& boundaryDescriptor() const = 0; virtual Type type() const = 0; diff --git a/src/scheme/InflowBoundaryConditionDescriptor.hpp b/src/scheme/InflowBoundaryConditionDescriptor.hpp index e648c1593cb4316f0cc77a4f18946b0457d65b5e..0b460846983946468d4161672fbc1e9aeb3912be 100644 --- a/src/scheme/InflowBoundaryConditionDescriptor.hpp +++ b/src/scheme/InflowBoundaryConditionDescriptor.hpp @@ -3,11 +3,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class InflowBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class InflowBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -17,7 +17,6 @@ class InflowBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return os; } - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; const FunctionSymbolId m_function_symbol_id; public: @@ -27,21 +26,15 @@ class InflowBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return m_function_symbol_id; } - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { return Type::inflow; } - InflowBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + InflowBoundaryConditionDescriptor(const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor, const FunctionSymbolId& function_symbol_id) - : m_boundary_descriptor(boundary_descriptor), m_function_symbol_id{function_symbol_id} + : BoundaryConditionDescriptorBase{boundary_descriptor}, m_function_symbol_id{function_symbol_id} { ; } diff --git a/src/scheme/NeumannBoundaryConditionDescriptor.hpp b/src/scheme/NeumannBoundaryConditionDescriptor.hpp index d318d2842212e5b03816b2e63d6328127d15cf23..2d63df7451dba2a7a0cb222665757d1b6f692b09 100644 --- a/src/scheme/NeumannBoundaryConditionDescriptor.hpp +++ b/src/scheme/NeumannBoundaryConditionDescriptor.hpp @@ -3,11 +3,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class NeumannBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class NeumannBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -19,7 +19,6 @@ class NeumannBoundaryConditionDescriptor : public IBoundaryConditionDescriptor const std::string m_name; - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; const FunctionSymbolId m_rhs_symbol_id; public: @@ -35,12 +34,6 @@ class NeumannBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return m_rhs_symbol_id; } - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { @@ -48,9 +41,9 @@ class NeumannBoundaryConditionDescriptor : public IBoundaryConditionDescriptor } NeumannBoundaryConditionDescriptor(const std::string& name, - std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor, + const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor, const FunctionSymbolId& rhs_symbol_id) - : m_name{name}, m_boundary_descriptor(boundary_descriptor), m_rhs_symbol_id{rhs_symbol_id} + : BoundaryConditionDescriptorBase{boundary_descriptor}, m_name{name}, m_rhs_symbol_id{rhs_symbol_id} { ; } diff --git a/src/scheme/OutflowBoundaryConditionDescriptor.hpp b/src/scheme/OutflowBoundaryConditionDescriptor.hpp index 83ef7a775a81269a5d3930ed2e07d5634d99959a..bc999c501f1e4d539736e06a6ac59c76e39a170e 100644 --- a/src/scheme/OutflowBoundaryConditionDescriptor.hpp +++ b/src/scheme/OutflowBoundaryConditionDescriptor.hpp @@ -2,11 +2,11 @@ #define OUTFLOW_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class OutflowBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class OutflowBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -16,23 +16,15 @@ class OutflowBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return os; } - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; - public: - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { return Type::outflow; } - OutflowBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) + OutflowBoundaryConditionDescriptor(const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor) + : BoundaryConditionDescriptorBase{boundary_descriptor} { ; } diff --git a/src/scheme/SymmetryBoundaryConditionDescriptor.hpp b/src/scheme/SymmetryBoundaryConditionDescriptor.hpp index 9364090dde18490a4803662c7eb770d9f6354b1c..1172bf7e40c5b2565dd82f216617298addda1e34 100644 --- a/src/scheme/SymmetryBoundaryConditionDescriptor.hpp +++ b/src/scheme/SymmetryBoundaryConditionDescriptor.hpp @@ -2,11 +2,11 @@ #define SYMMETRY_BOUNDARY_CONDITION_DESCRIPTOR_HPP #include <mesh/IBoundaryDescriptor.hpp> -#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/BoundaryConditionDescriptorBase.hpp> #include <memory> -class SymmetryBoundaryConditionDescriptor : public IBoundaryConditionDescriptor +class SymmetryBoundaryConditionDescriptor : public BoundaryConditionDescriptorBase { private: std::ostream& @@ -16,23 +16,15 @@ class SymmetryBoundaryConditionDescriptor : public IBoundaryConditionDescriptor return os; } - std::shared_ptr<const IBoundaryDescriptor> m_boundary_descriptor; - public: - const IBoundaryDescriptor& - boundaryDescriptor() const final - { - return *m_boundary_descriptor; - } - Type type() const final { return Type::symmetry; } - SymmetryBoundaryConditionDescriptor(std::shared_ptr<const IBoundaryDescriptor> boundary_descriptor) - : m_boundary_descriptor(boundary_descriptor) + SymmetryBoundaryConditionDescriptor(const std::shared_ptr<const IBoundaryDescriptor>& boundary_descriptor) + : BoundaryConditionDescriptorBase{boundary_descriptor} { ; } diff --git a/src/utils/Messenger.cpp b/src/utils/Messenger.cpp index 05dfa43e5a22f5223fd6c1e8291302c5366f5015..14891477a2b804c4f0c8698fdfa51a8ea2470c8b 100644 --- a/src/utils/Messenger.cpp +++ b/src/utils/Messenger.cpp @@ -9,10 +9,10 @@ namespace parallel Messenger* Messenger::m_instance = nullptr; void -Messenger::create(int& argc, char* argv[]) +Messenger::create(int& argc, char* argv[], bool parallel_output) { if (Messenger::m_instance == nullptr) { - Messenger::m_instance = new Messenger(argc, argv); + Messenger::m_instance = new Messenger(argc, argv, parallel_output); } else { throw UnexpectedError("Messenger already created"); } @@ -28,7 +28,7 @@ Messenger::destroy() } } -Messenger::Messenger([[maybe_unused]] int& argc, [[maybe_unused]] char* argv[]) +Messenger::Messenger([[maybe_unused]] int& argc, [[maybe_unused]] char* argv[], bool parallel_output) { #ifdef PUGS_HAS_MPI MPI_Init(&argc, &argv); @@ -66,7 +66,7 @@ Messenger::Messenger([[maybe_unused]] int& argc, [[maybe_unused]] char* argv[]) return size; }(); - if (m_rank != 0) { + if ((not parallel_output) and (m_rank != 0)) { // LCOV_EXCL_START std::cout.setstate(std::ios::badbit); std::cerr.setstate(std::ios::badbit); diff --git a/src/utils/Messenger.hpp b/src/utils/Messenger.hpp index ac79ee8490882a1bac8a9fd74db58b6cd8dccdb7..a04c664d7dcbe36817d2748a6f27e0b8d8dc3481 100644 --- a/src/utils/Messenger.hpp +++ b/src/utils/Messenger.hpp @@ -85,7 +85,7 @@ class Messenger }; static Messenger* m_instance; - Messenger(int& argc, char* argv[]); + Messenger(int& argc, char* argv[], bool parallel_output); #ifdef PUGS_HAS_MPI MPI_Comm m_pugs_comm_world = MPI_COMM_WORLD; @@ -406,7 +406,7 @@ class Messenger } public: - static void create(int& argc, char* argv[]); + static void create(int& argc, char* argv[], bool parallel_output = false); static void destroy(); PUGS_INLINE diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp index f9b6c94985d4e273aa409c7e6aa50e27ef58d01d..b3d7d6c9a941f3b6e1c03e6d9cc0fb1bec24a1a7 100644 --- a/src/utils/PugsUtils.cpp +++ b/src/utils/PugsUtils.cpp @@ -86,9 +86,10 @@ setDefaultOMPEnvironment() std::string initialize(int& argc, char* argv[]) { - bool enable_fpe = true; - bool enable_signals = true; - int nb_threads = -1; + bool enable_fpe = true; + bool enable_signals = true; + int nb_threads = -1; + bool parallel_output = false; ParallelChecker::Mode pc_mode = ParallelChecker::Mode::automatic; std::string pc_filename = ParallelChecker::instance().filename(); @@ -133,9 +134,11 @@ initialize(int& argc, char* argv[]) app.add_flag("-p,--pause-on-error", pause_on_error, "Pause for debugging on unexpected error [default: false]"); bool reproducible_sums = true; - app.add_flag("--reproducible-sums,!--no-reproducible-sums", show_preamble, + app.add_flag("--reproducible-sums,!--no-reproducible-sums", reproducible_sums, "Special treatment of array sums to ensure reproducibility [default: true]"); + app.add_flag("--parallel-output", parallel_output, "All MPI processes output to console [default: false]"); + std::map<std::string, ParallelChecker::Mode> pc_mode_map{{"auto", ParallelChecker::Mode::automatic}, {"write", ParallelChecker::Mode::write}, {"read", ParallelChecker::Mode::read}}; @@ -176,7 +179,8 @@ initialize(int& argc, char* argv[]) SignalManager::setPauseForDebug(pause_on_error); ReproducibleSumManager::setReproducibleSums(reproducible_sums); } - parallel::Messenger::create(argc, argv); + + parallel::Messenger::create(argc, argv, parallel_output); PETScWrapper::initialize(argc, argv); SLEPcWrapper::initialize(argc, argv); diff --git a/src/utils/checkpointing/IWriterHFType.hpp b/src/utils/checkpointing/IWriterHFType.hpp index 124cb2ee53f6bf477361cd381e98af366e626231..046998283e0c4a8567e1624741ddd920108413e7 100644 --- a/src/utils/checkpointing/IWriterHFType.hpp +++ b/src/utils/checkpointing/IWriterHFType.hpp @@ -8,7 +8,10 @@ HighFive::EnumType<IWriter::Type> PUGS_INLINE create_enum_i_writer_type() { - return {{"gnuplot", IWriter::Type::gnuplot}, {"gnuplot_1d", IWriter::Type::gnuplot_1d}, {"vtk", IWriter::Type::vtk}}; + return {{"gnuplot", IWriter::Type::gnuplot}, + {"gnuplot_1d", IWriter::Type::gnuplot_1d}, + {"gnuplot_raw", IWriter::Type::gnuplot_raw}, + {"vtk", IWriter::Type::vtk}}; } HIGHFIVE_REGISTER_TYPE(IWriter::Type, create_enum_i_writer_type) diff --git a/src/utils/checkpointing/ReadIWriter.cpp b/src/utils/checkpointing/ReadIWriter.cpp index 1f4dc1a55c4cefc0eaa9b8de05209b764448b3d0..d7037808859bd8916530e98ce1705214ef1c5972 100644 --- a/src/utils/checkpointing/ReadIWriter.cpp +++ b/src/utils/checkpointing/ReadIWriter.cpp @@ -4,6 +4,7 @@ #include <language/utils/EmbeddedData.hpp> #include <output/GnuplotWriter.hpp> #include <output/GnuplotWriter1D.hpp> +#include <output/GnuplotWriterRaw.hpp> #include <output/VTKWriter.hpp> #include <utils/checkpointing/IWriterHFType.hpp> @@ -30,6 +31,10 @@ readIWriter(const std::string& symbol_name, const HighFive::Group& symbol_table_ p_writer = std::make_shared<GnuplotWriter1D>(base_filename); break; } + case IWriter::Type::gnuplot_raw: { + p_writer = std::make_shared<GnuplotWriterRaw>(base_filename); + break; + } case IWriter::Type::vtk: { p_writer = std::make_shared<VTKWriter>(base_filename); break; diff --git a/src/utils/checkpointing/WriteIWriter.cpp b/src/utils/checkpointing/WriteIWriter.cpp index f05c8e77c424856561ee9d579392390bd384650b..b04b6b6cd3c2cff62762285c1fbd64e466be1182 100644 --- a/src/utils/checkpointing/WriteIWriter.cpp +++ b/src/utils/checkpointing/WriteIWriter.cpp @@ -29,6 +29,7 @@ writeIWriter(const std::string& symbol_name, switch (iwriter_p->type()) { case IWriter::Type::gnuplot: case IWriter::Type::gnuplot_1d: + case IWriter::Type::gnuplot_raw: case IWriter::Type::vtk: { const WriterBase& writer = dynamic_cast<const WriterBase&>(*iwriter_p); diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp index 36b444e58f014f39f8d752b4be129a568a661fa8..014c7b123e182402002f97e44c8d3115274367d8 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") diff --git a/tests/test_checkpointing_IWriter.cpp b/tests/test_checkpointing_IWriter.cpp index 33d00bd90660280159e90a3ae73b92cd76f04d95..f14156544e9896c3a59d0b8691fee8f78f475253 100644 --- a/tests/test_checkpointing_IWriter.cpp +++ b/tests/test_checkpointing_IWriter.cpp @@ -7,6 +7,7 @@ #include <language/utils/EmbeddedData.hpp> #include <output/GnuplotWriter.hpp> #include <output/GnuplotWriter1D.hpp> +#include <output/GnuplotWriterRaw.hpp> #include <output/NamedDiscreteFunction.hpp> #include <output/VTKWriter.hpp> #include <scheme/DiscreteFunctionP0.hpp> @@ -51,12 +52,18 @@ TEST_CASE("checkpointing_IWriter", "[utils/checkpointing]") EmbeddedData{std::make_shared<DataHandler<const IWriter>>(p_gnuplot_writer)}, file, useless_group, symbol_table_group); - auto p_gnuplot_writer_1d = std::make_shared<const GnuplotWriter1D>("gnuplot_1d_basename", 1.12); + auto p_gnuplot_writer_1d = std::make_shared<const GnuplotWriter1D>("gnuplot_1d_basename", 1.21); p_gnuplot_writer_1d->periodManager().value().setSaveTime(2); checkpointing::writeIWriter("gnuplot_1d", EmbeddedData{std::make_shared<DataHandler<const IWriter>>(p_gnuplot_writer_1d)}, file, useless_group, symbol_table_group); + auto p_gnuplot_writer_raw = std::make_shared<const GnuplotWriterRaw>("gnuplot_raw_basename", 1.18); + p_gnuplot_writer_raw->periodManager().value().setSaveTime(2.3); + checkpointing::writeIWriter("gnuplot_raw", + EmbeddedData{std::make_shared<DataHandler<const IWriter>>(p_gnuplot_writer_raw)}, + file, useless_group, symbol_table_group); + const std::string vtk_filename = path / "vtk_example"; auto mesh_v = MeshDataBaseForTests::get().cartesian1DMesh(); @@ -77,9 +84,10 @@ TEST_CASE("checkpointing_IWriter", "[utils/checkpointing]") file.flush(); - EmbeddedData read_gnuplot_writer = checkpointing::readIWriter("gnuplot", symbol_table_group); - EmbeddedData read_gnuplot_writer_1d = checkpointing::readIWriter("gnuplot_1d", symbol_table_group); - EmbeddedData read_vtk_writer = checkpointing::readIWriter("vtk", symbol_table_group); + EmbeddedData read_gnuplot_writer = checkpointing::readIWriter("gnuplot", symbol_table_group); + EmbeddedData read_gnuplot_writer_1d = checkpointing::readIWriter("gnuplot_1d", symbol_table_group); + EmbeddedData read_gnuplot_writer_raw = checkpointing::readIWriter("gnuplot_raw", symbol_table_group); + EmbeddedData read_vtk_writer = checkpointing::readIWriter("vtk", symbol_table_group); auto get_value = [](const EmbeddedData& embedded_data) -> const IWriter& { return *dynamic_cast<const DataHandler<const IWriter>&>(embedded_data.get()).data_ptr(); @@ -100,10 +108,21 @@ TEST_CASE("checkpointing_IWriter", "[utils/checkpointing]") REQUIRE(read_gp_writer_1d.type() == IWriter::Type::gnuplot_1d); REQUIRE(read_gp_writer_1d.baseFilename() == "gnuplot_1d_basename"); REQUIRE(read_gp_writer_1d.periodManager().has_value()); - REQUIRE(read_gp_writer_1d.periodManager().value().timePeriod() == 1.12); - REQUIRE(read_gp_writer_1d.periodManager().value().nextTime() == 3.12); + REQUIRE(read_gp_writer_1d.periodManager().value().timePeriod() == 1.21); + REQUIRE(read_gp_writer_1d.periodManager().value().nextTime() == Catch::Approx(3.21)); REQUIRE(not read_gp_writer_1d.signature().has_value()); + REQUIRE_NOTHROW(get_value(read_gnuplot_writer_raw)); + REQUIRE_NOTHROW(dynamic_cast<const GnuplotWriterRaw&>(get_value(read_gnuplot_writer_raw))); + const GnuplotWriterRaw& read_gp_writer_raw = + dynamic_cast<const GnuplotWriterRaw&>(get_value(read_gnuplot_writer_raw)); + REQUIRE(read_gp_writer_raw.type() == IWriter::Type::gnuplot_raw); + REQUIRE(read_gp_writer_raw.baseFilename() == "gnuplot_raw_basename"); + REQUIRE(read_gp_writer_raw.periodManager().has_value()); + REQUIRE(read_gp_writer_raw.periodManager().value().timePeriod() == 1.18); + REQUIRE(read_gp_writer_raw.periodManager().value().nextTime() == Catch::Approx(3.48)); + REQUIRE(not read_gp_writer_raw.signature().has_value()); + REQUIRE_NOTHROW(get_value(read_vtk_writer)); REQUIRE_NOTHROW(dynamic_cast<const VTKWriter&>(get_value(read_vtk_writer))); const VTKWriter& read_vtk = dynamic_cast<const VTKWriter&>(get_value(read_vtk_writer)); @@ -111,7 +130,7 @@ TEST_CASE("checkpointing_IWriter", "[utils/checkpointing]") REQUIRE(read_vtk.baseFilename() == vtk_filename); REQUIRE(read_vtk.periodManager().has_value()); REQUIRE(read_vtk.periodManager().value().timePeriod() == 0.02); - REQUIRE(read_vtk.periodManager().value().nextTime() == 1.02); + REQUIRE(read_vtk.periodManager().value().nextTime() == Catch::Approx(1.02)); REQUIRE(read_vtk.signature().has_value()); REQUIRE(read_vtk.signature().value() == p_vtk_writer->signature().value()); }