From 61cc252b6668cdf013abb5f49f319c9993d78463 Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Sat, 16 Jul 2022 16:20:10 +0200 Subject: [PATCH] Allow output without time specifier Related to #27 Now one can set two types of writers. Writers with a specified output time period (the was the previous behavior) and writers without time info. The output filenames are simpler in the second case since they do not include the output step number in their names. To these writers are now associated two `write` functions. The first one (legacy one) specifies the time of the output. The second one (new one) does not expect time value. --- src/language/modules/WriterModule.cpp | 36 +++++++++++++++ src/output/GnuplotWriter.cpp | 50 ++++++++++++++------ src/output/GnuplotWriter.hpp | 16 +++++-- src/output/GnuplotWriter1D.cpp | 37 ++++++++++++--- src/output/GnuplotWriter1D.hpp | 16 +++++-- src/output/IWriter.hpp | 3 ++ src/output/VTKWriter.cpp | 66 +++++++++++++++++++-------- src/output/VTKWriter.hpp | 16 ++++--- src/output/WriterBase.cpp | 24 +++++++++- src/output/WriterBase.hpp | 9 ++++ 10 files changed, 216 insertions(+), 57 deletions(-) diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp index fcb3beb61..a1eebb3ed 100644 --- a/src/language/modules/WriterModule.cpp +++ b/src/language/modules/WriterModule.cpp @@ -20,6 +20,14 @@ WriterModule::WriterModule() this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IWriter>>); + this + ->_addBuiltinFunction("vtk_writer", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>( + + [](const std::string& filename) { return std::make_shared<VTKWriter>(filename); } + + )); + this->_addBuiltinFunction("vtk_writer", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&, const double&)>>( @@ -30,6 +38,14 @@ WriterModule::WriterModule() )); + this + ->_addBuiltinFunction("gnuplot_writer", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>( + + [](const std::string& filename) { return std::make_shared<GnuplotWriter>(filename); } + + )); + this->_addBuiltinFunction("gnuplot_writer", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&, const double&)>>( @@ -40,6 +56,14 @@ WriterModule::WriterModule() )); + this + ->_addBuiltinFunction("gnuplot_1d_writer", + std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&)>>( + + [](const std::string& filename) { return std::make_shared<GnuplotWriter1D>(filename); } + + )); + this->_addBuiltinFunction("gnuplot_1d_writer", std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&, const double&)>>( @@ -72,6 +96,18 @@ WriterModule::WriterModule() )); + this->_addBuiltinFunction("write", std::make_shared<BuiltinFunctionEmbedder< + void(std::shared_ptr<const IWriter>, + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>&)>>( + + [](std::shared_ptr<const IWriter> writer, + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& + named_discrete_function_list) -> void { + writer->write(named_discrete_function_list); + } + + )); + this->_addBuiltinFunction("write", std::make_shared<BuiltinFunctionEmbedder< void(std::shared_ptr<const IWriter>, diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp index 4f98d0f23..ae0ba69af 100644 --- a/src/output/GnuplotWriter.cpp +++ b/src/output/GnuplotWriter.cpp @@ -239,9 +239,9 @@ GnuplotWriter::_writeNodeData(const NodeArray<DataType>& node_array, NodeId node template <typename MeshType> void -GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& output_named_item_data_set, - double time) const +GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::optional<double> time) const { if (parallel::rank() == 0) { std::ofstream fout{_getFilename()}; @@ -249,8 +249,9 @@ GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, fout.setf(std::ios_base::scientific); fout << this->_getDateAndVersionComment(); - fout << "# time = " << time << "\n\n"; - + if (time.has_value()) { + fout << "# time = " << *time << "\n\n"; + } this->_writePreamble<MeshType::Dimension>(output_named_item_data_set, fout); } @@ -267,17 +268,41 @@ GnuplotWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, } void -GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const +GnuplotWriter::_writeAtTime( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, + double time) const +{ + std::shared_ptr mesh = this->_getMesh(named_discrete_function_list); + + OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list); + + switch (mesh->dimension()) { + case 1: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); + break; + } + case 2: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time); + break; + } + default: { + throw NormalError("gnuplot format is not available in dimension " + stringify(mesh->dimension())); + } + } +} + +void +GnuplotWriter::_writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const { OutputNamedItemDataSet output_named_item_data_set{}; switch (p_mesh->dimension()) { case 1: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, 0); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(p_mesh), output_named_item_data_set, {}); break; } case 2: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, 0); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(p_mesh), output_named_item_data_set, {}); break; } default: { @@ -287,9 +312,8 @@ GnuplotWriter::writeMesh(const std::shared_ptr<const IMesh>& p_mesh) const } void -GnuplotWriter::_writeAtTime( - const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, - double time) const +GnuplotWriter::_write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const { std::shared_ptr mesh = this->_getMesh(named_discrete_function_list); @@ -297,11 +321,11 @@ GnuplotWriter::_writeAtTime( switch (mesh->dimension()) { case 1: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {}); break; } case 2: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {}); break; } default: { diff --git a/src/output/GnuplotWriter.hpp b/src/output/GnuplotWriter.hpp index 312e4886c..112b46062 100644 --- a/src/output/GnuplotWriter.hpp +++ b/src/output/GnuplotWriter.hpp @@ -9,9 +9,10 @@ class IMesh; +#include <optional> #include <string> -class GnuplotWriter : public WriterBase +class GnuplotWriter final : public WriterBase { private: std::string _getDateAndVersionComment() const; @@ -45,15 +46,20 @@ class GnuplotWriter : public WriterBase std::ostream& fout) const; template <typename MeshType> - void _writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& output_named_item_data_set, - double time) const; + void _write(const std::shared_ptr<const MeshType>& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::optional<double> time) const; void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const final; + void _write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final; + + void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + public: - void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + GnuplotWriter(const std::string& base_filename) : WriterBase(base_filename) {} GnuplotWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {} diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp index 7fbd6612a..73e5a4e64 100644 --- a/src/output/GnuplotWriter1D.cpp +++ b/src/output/GnuplotWriter1D.cpp @@ -260,9 +260,9 @@ GnuplotWriter1D::_writeItemDatas(const std::shared_ptr<const MeshType>& mesh, template <typename MeshType> void -GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& output_named_item_data_set, - double time) const +GnuplotWriter1D::_write(const std::shared_ptr<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) { @@ -286,7 +286,9 @@ GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, fout.setf(std::ios_base::scientific); fout << _getDateAndVersionComment(); - fout << "# time = " << time << "\n\n"; + if (time.has_value()) { + fout << "# time = " << *time << "\n\n"; + } _writePreamble(output_named_item_data_set, fout); } @@ -299,7 +301,7 @@ GnuplotWriter1D::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, } void -GnuplotWriter1D::writeMesh(const std::shared_ptr<const IMesh>&) const +GnuplotWriter1D::_writeMesh(const std::shared_ptr<const IMesh>&) const { std::ostringstream errorMsg; errorMsg << "gnuplot_1d_writer does not write meshes\n" @@ -319,7 +321,7 @@ GnuplotWriter1D::_writeAtTime( switch (mesh->dimension()) { case 1: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); break; } case 2: { @@ -334,3 +336,26 @@ GnuplotWriter1D::_writeAtTime( } } } + +void +GnuplotWriter1D::_write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const +{ + std::shared_ptr mesh = this->_getMesh(named_discrete_function_list); + + OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list); + + switch (mesh->dimension()) { + case 1: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {}); + break; + } + case 2: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {}); + break; + } + default: { + throw NormalError("gnuplot format is not available in dimension " + stringify(mesh->dimension())); + } + } +} diff --git a/src/output/GnuplotWriter1D.hpp b/src/output/GnuplotWriter1D.hpp index f1e7b23c8..fad94c136 100644 --- a/src/output/GnuplotWriter1D.hpp +++ b/src/output/GnuplotWriter1D.hpp @@ -9,9 +9,10 @@ class IMesh; +#include <optional> #include <string> -class GnuplotWriter1D : public WriterBase +class GnuplotWriter1D final : public WriterBase { private: std::string _getDateAndVersionComment() const; @@ -38,15 +39,20 @@ class GnuplotWriter1D : public WriterBase void _writePreamble(const OutputNamedItemDataSet& output_named_item_value_set, std::ostream& fout) const; template <typename MeshType> - void _writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& output_named_item_value_set, - double time) const; + void _write(const std::shared_ptr<const MeshType>& mesh, + const OutputNamedItemDataSet& output_named_item_value_set, + std::optional<double> time) const; void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const final; + void _write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final; + + void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + public: - void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + GnuplotWriter1D(const std::string& base_filename) : WriterBase(base_filename) {} GnuplotWriter1D(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {} diff --git a/src/output/IWriter.hpp b/src/output/IWriter.hpp index 02317ad98..dab629604 100644 --- a/src/output/IWriter.hpp +++ b/src/output/IWriter.hpp @@ -13,6 +13,9 @@ class IWriter public: virtual void writeMesh(const std::shared_ptr<const IMesh>& mesh) const = 0; + virtual void write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const = 0; + virtual void writeIfNeeded( const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const = 0; diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp index 55a2e90d9..8295c351f 100644 --- a/src/output/VTKWriter.cpp +++ b/src/output/VTKWriter.cpp @@ -355,14 +355,10 @@ VTKWriter::_write_node_data(std::ofstream& os, template <typename MeshType> void -VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& given_output_named_item_data_set, - double time) const +VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, + const OutputNamedItemDataSet& given_output_named_item_data_set, + std::optional<double> time) const { - if (not m_period_manager.has_value()) { - throw NormalError("Writer has no period defined"); - } - OutputNamedItemDataSet output_named_item_data_set{given_output_named_item_data_set}; // Adding basic mesh information output_named_item_data_set.add(NamedItemData{"cell_number", mesh->connectivity().cellNumber()}); @@ -622,14 +618,18 @@ VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, fout << "<VTKFile type=\"Collection\" version=\"0.1\">\n"; fout << "<Collection>\n"; - for (size_t i_time = 0; i_time < m_period_manager->nbSavedTimes(); ++i_time) { - std::ostringstream sout; - sout << m_base_filename; - sout << '.' << std::setfill('0') << std::setw(4) << i_time << ".pvtu"; + if (time.has_value()) { + for (size_t i_time = 0; i_time < m_period_manager->nbSavedTimes(); ++i_time) { + std::ostringstream sout; + sout << m_base_filename; + sout << '.' << std::setfill('0') << std::setw(4) << i_time << ".pvtu"; - fout << "<DataSet timestep=\"" << m_period_manager->savedTime(i_time) << "\" file=\"" << sout.str() << "\"/>\n"; + fout << "<DataSet timestep=\"" << m_period_manager->savedTime(i_time) << "\" file=\"" << sout.str() << "\"/>\n"; + } + fout << "<DataSet timestep=\"" << *time << "\" file=\"" << _getFilenamePVTU() << "\"/>\n"; + } else { + fout << "<DataSet file=\"" << _getFilenamePVTU() << "\"/>\n"; } - fout << "<DataSet timestep=\"" << time << "\" file=\"" << _getFilenamePVTU() << "\"/>\n"; fout << "</Collection>\n"; fout << "</VTKFile>\n"; @@ -637,21 +637,21 @@ VTKWriter::_writeAtTime(const std::shared_ptr<const MeshType>& mesh, } void -VTKWriter::writeMesh(const std::shared_ptr<const IMesh>& mesh) const +VTKWriter::_writeMesh(const std::shared_ptr<const IMesh>& mesh) const { OutputNamedItemDataSet output_named_item_data_set; switch (mesh->dimension()) { case 1: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, 0); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {}); break; } case 2: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, 0); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {}); break; } case 3: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, 0); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, {}); break; } default: { @@ -670,15 +670,41 @@ VTKWriter::_writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFun switch (mesh->dimension()) { case 1: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, time); + break; + } + case 2: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time); + break; + } + case 3: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time); + break; + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} + +void +VTKWriter::_write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const +{ + std::shared_ptr mesh = this->_getMesh(named_discrete_function_list); + + OutputNamedItemDataSet output_named_item_data_set = this->_getOutputNamedItemDataSet(named_discrete_function_list); + + switch (mesh->dimension()) { + case 1: { + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_data_set, {}); break; } case 2: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), output_named_item_data_set, {}); break; } case 3: { - this->_writeAtTime(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, time); + this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), output_named_item_data_set, {}); break; } default: { diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp index eb0f70d92..c0adbd6c4 100644 --- a/src/output/VTKWriter.hpp +++ b/src/output/VTKWriter.hpp @@ -9,9 +9,10 @@ class IMesh; +#include <optional> #include <string> -class VTKWriter : public WriterBase +class VTKWriter final : public WriterBase { private: class SerializedDataList; @@ -95,16 +96,19 @@ class VTKWriter : public WriterBase SerializedDataList& serialized_data_list) const; template <typename MeshType> - void _writeAtTime(const std::shared_ptr<const MeshType>& mesh, - const OutputNamedItemDataSet& output_named_item_data_set, - double time) const; + void _write(const std::shared_ptr<const MeshType>& mesh, + const OutputNamedItemDataSet& output_named_item_data_set, + std::optional<double> time) const; void _writeAtTime(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const final; - public: - void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + void _write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final; + + void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + public: VTKWriter(const std::string& base_filename) : WriterBase(base_filename) {} VTKWriter(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period) {} diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp index 7ae28e9e8..2fe733d54 100644 --- a/src/output/WriterBase.cpp +++ b/src/output/WriterBase.cpp @@ -214,7 +214,7 @@ WriterBase::writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteF m_period_manager->setSaveTime(time); } } else { - throw NormalError("Writer has no period defined"); + throw NormalError("this writer does not allow time value"); } } @@ -229,6 +229,26 @@ WriterBase::writeForced(const std::vector<std::shared_ptr<const NamedDiscreteFun this->_writeAtTime(named_discrete_function_list, time); m_period_manager->setSaveTime(time); } else { - throw NormalError("Writer has no period defined"); + throw NormalError("this writer does not allow time value"); + } +} + +void +WriterBase::write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const +{ + if (m_period_manager.has_value()) { + throw NormalError("this writer requires time value"); + } else { + this->_write(named_discrete_function_list); + } +} + +void +WriterBase::writeMesh(const std::shared_ptr<const IMesh>& mesh) const +{ + if (m_period_manager.has_value()) { + throw NormalError("write_mesh requires a writer without time period"); + } else { + this->_writeMesh(mesh); } } diff --git a/src/output/WriterBase.hpp b/src/output/WriterBase.hpp index 6d96ee410..2f29120b5 100644 --- a/src/output/WriterBase.hpp +++ b/src/output/WriterBase.hpp @@ -105,13 +105,22 @@ class WriterBase : public IWriter const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const = 0; + virtual void _write( + const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const = 0; + + virtual void _writeMesh(const std::shared_ptr<const IMesh>& mesh) const = 0; + public: + void write(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list) const final; + void writeIfNeeded(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const final; void writeForced(const std::vector<std::shared_ptr<const NamedDiscreteFunction>>& named_discrete_function_list, double time) const final; + void writeMesh(const std::shared_ptr<const IMesh>& mesh) const final; + WriterBase() = delete; WriterBase(const std::string& base_filename, const double& time_period); -- GitLab