Skip to content
Snippets Groups Projects
Commit 6b2d417a authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Add `gnuplot_1d_writer`

The aim of this variant is to provide a more classic version of the
output: one value per cell or per node.

It can only be used for 1d data.

It remains to make it work in parallel.
parent 734473b3
No related branches found
No related tags found
1 merge request!80Feature/writers improvement
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <mesh/GmshReader.hpp> #include <mesh/GmshReader.hpp>
#include <mesh/Mesh.hpp> #include <mesh/Mesh.hpp>
#include <output/GnuplotWriter.hpp> #include <output/GnuplotWriter.hpp>
#include <output/GnuplotWriter1D.hpp>
#include <output/IWriter.hpp> #include <output/IWriter.hpp>
#include <output/NamedDiscreteFunction.hpp> #include <output/NamedDiscreteFunction.hpp>
#include <output/VTKWriter.hpp> #include <output/VTKWriter.hpp>
...@@ -39,6 +40,16 @@ WriterModule::WriterModule() ...@@ -39,6 +40,16 @@ WriterModule::WriterModule()
)); ));
this->_addBuiltinFunction("gnuplot_1d_writer",
std::make_shared<BuiltinFunctionEmbedder<std::shared_ptr<const IWriter>(const std::string&,
const double&)>>(
[](const std::string& filename, const double& period) {
return std::make_shared<GnuplotWriter1D>(filename, period);
}
));
this->_addBuiltinFunction("name_output", this->_addBuiltinFunction("name_output",
std::make_shared<BuiltinFunctionEmbedder< std::make_shared<BuiltinFunctionEmbedder<
std::shared_ptr<const NamedDiscreteFunction>(std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const NamedDiscreteFunction>(std::shared_ptr<const IDiscreteFunction>,
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
add_library( add_library(
PugsOutput PugsOutput
GnuplotWriter.cpp GnuplotWriter.cpp
GnuplotWriter1D.cpp
VTKWriter.cpp VTKWriter.cpp
WriterBase.cpp) WriterBase.cpp)
......
...@@ -177,7 +177,7 @@ GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh, ...@@ -177,7 +177,7 @@ GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set, const OutputNamedItemValueSet& output_named_item_value_set,
double time) const double time) const
{ {
if (parallel::rank() == 0) { if (parallel::size() == 1) {
std::ofstream fout{_getFilename()}; std::ofstream fout{_getFilename()};
fout.precision(15); fout.precision(15);
fout.setf(std::ios_base::scientific); fout.setf(std::ios_base::scientific);
...@@ -186,17 +186,13 @@ GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh, ...@@ -186,17 +186,13 @@ GnuplotWriter::_write(const std::shared_ptr<const MeshType>& mesh,
fout << "\n# time = " << time << "\n\n"; fout << "\n# time = " << time << "\n\n";
this->_writePreamble<MeshType::Dimension>(output_named_item_value_set, fout); this->_writePreamble<MeshType::Dimension>(output_named_item_value_set, fout);
}
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (i_rank == parallel::rank()) {
std::ofstream fout{_getFilename(), std::ios_base::app};
fout.precision(15); fout.precision(15);
fout.setf(std::ios_base::scientific); fout.setf(std::ios_base::scientific);
this->_writeValues(mesh, output_named_item_value_set, fout); this->_writeValues(mesh, output_named_item_value_set, fout);
} } else {
parallel::barrier(); throw NotImplementedError("not implemented in parallel");
} }
} }
......
#include <output/GnuplotWriter1D.hpp>
#include <mesh/Connectivity.hpp>
#include <mesh/ItemValue.hpp>
#include <mesh/Mesh.hpp>
#include <mesh/MeshData.hpp>
#include <mesh/MeshDataManager.hpp>
#include <utils/Messenger.hpp>
#include <utils/PugsTraits.hpp>
#include <utils/RevisionInfo.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;
sout << '.' << std::setfill('0') << std::setw(4) << m_saved_times.size() << ".gnu";
return sout.str();
}
template <typename DataType>
bool
GnuplotWriter1D::_is_cell_value(const CellValue<const DataType>&) const
{
return true;
}
template <typename DataType>
bool
GnuplotWriter1D::_is_cell_value(const NodeValue<const DataType>&) const
{
return false;
}
template <typename DataType>
bool
GnuplotWriter1D::_is_node_value(const CellValue<const DataType>&) const
{
return false;
}
template <typename DataType>
bool
GnuplotWriter1D::_is_node_value(const NodeValue<const DataType>&) const
{
return true;
}
template <size_t Dimension>
void
GnuplotWriter1D::_writePreamble(const OutputNamedItemValueSet& output_named_item_value_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_value : output_named_item_value_set) {
const std::string name = i_named_item_value.first;
const auto& item_value_variant = i_named_item_value.second;
std::visit(
[&](auto&& item_value) {
using ItemValueType = std::decay_t<decltype(item_value)>;
using DataType = std::decay_t<typename ItemValueType::data_type>;
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{}.nbRows(); ++j) {
for (size_t k = 0; k < DataType{}.nbColumns(); ++k) {
fout << ' ' << i++ << ':' << name << '(' << j << ',' << k << ')';
}
}
} else {
throw UnexpectedError("invalid data type");
}
},
item_value_variant);
}
fout << "\n\n";
}
template <typename DataType>
void
GnuplotWriter1D::_writeCellValue(const NodeValue<DataType>&, CellId, std::ostream&) const
{}
template <typename DataType>
void
GnuplotWriter1D::_writeCellValue(const CellValue<DataType>& cell_value, CellId cell_id, std::ostream& fout) const
{
const auto& value = cell_value[cell_id];
if constexpr (std::is_arithmetic_v<DataType>) {
fout << ' ' << value;
} else if constexpr (is_tiny_vector_v<std::decay_t<DataType>>) {
for (size_t i = 0; i < value.dimension(); ++i) {
fout << ' ' << value[i];
}
} else if constexpr (is_tiny_matrix_v<std::decay_t<DataType>>) {
for (size_t i = 0; i < value.nbRows(); ++i) {
for (size_t j = 0; j < value.nbColumns(); ++j) {
fout << ' ' << value(i, j);
}
}
} else {
throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>());
}
}
template <typename MeshType>
void
GnuplotWriter1D::_writeCellValues(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
std::ostream& fout) const
{
if constexpr (MeshType::Dimension == 1) {
auto& mesh_data = MeshDataManager::instance().getMeshData(*mesh);
const auto& cell_center = mesh_data.xj();
for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
fout << cell_center[cell_id][0];
for (auto [name, item_value] : output_named_item_value_set) {
std::visit([&](auto&& cell_value) { _writeCellValue(cell_value, cell_id, fout); }, item_value);
}
fout << '\n';
}
} else if constexpr (MeshType::Dimension == 2) {
auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix();
for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
std::ostringstream os;
os.precision(15);
os.setf(std::ios_base::scientific);
for (auto [name, item_value] : output_named_item_value_set) {
std::visit([&](auto&& cell_value) { _writeCellValue(cell_value, cell_id, os); }, item_value);
}
const auto& cell_nodes = cell_to_node_matrix[cell_id];
for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) {
const NodeId& node_id = cell_nodes[i_node];
const TinyVector<2>& xr = mesh->xr()[node_id];
fout << xr[0] << ' ' << xr[1] << ' ' << os.str() << '\n';
}
fout << '\n';
}
} else {
throw UnexpectedError("invalid mesh dimension");
}
}
template <typename ValueType>
void
GnuplotWriter1D::_writeNodeValue(const NodeValue<ValueType>& node_value, NodeId node_id, std::ostream& fout) const
{
const auto& value = node_value[node_id];
if constexpr (std::is_arithmetic_v<ValueType>) {
fout << ' ' << value;
} else if constexpr (is_tiny_vector_v<std::decay_t<ValueType>>) {
for (size_t i = 0; i < value.dimension(); ++i) {
fout << ' ' << value[i];
}
} else if constexpr (is_tiny_matrix_v<std::decay_t<ValueType>>) {
for (size_t i = 0; i < value.nbRows(); ++i) {
for (size_t j = 0; j < value.nbColumns(); ++j) {
fout << ' ' << value(i, j);
}
}
} else {
throw UnexpectedError("invalid data type for cell value output: " + demangle<ValueType>());
}
}
template <typename ValueType>
void
GnuplotWriter1D::_writeNodeValue(const CellValue<ValueType>&, NodeId, std::ostream&) const
{}
template <typename MeshType>
void
GnuplotWriter1D::_writeNodeValues(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
std::ostream& fout) const
{
if constexpr (MeshType::Dimension == 1) {
const auto& xr = mesh->xr();
for (NodeId node_id = 0; node_id < mesh->numberOfNodes(); ++node_id) {
fout << xr[node_id][0];
for (auto [name, item_value] : output_named_item_value_set) {
std::visit([&](auto&& node_value) { _writeNodeValue(node_value, node_id, fout); }, item_value);
}
fout << '\n';
}
} else if constexpr (MeshType::Dimension == 2) {
auto cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix();
for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
std::ostringstream os;
os.precision(15);
os.setf(std::ios_base::scientific);
const auto& cell_nodes = cell_to_node_matrix[cell_id];
for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) {
const NodeId& node_id = cell_nodes[i_node];
const TinyVector<2>& xr = mesh->xr()[node_id];
fout << xr[0] << ' ' << xr[1] << ' ' << os.str();
for (auto [name, item_value] : output_named_item_value_set) {
std::visit([&](auto&& node_value) { _writeNodeValue(node_value, node_id, os); }, item_value);
}
fout << '\n';
}
fout << '\n';
}
} else {
throw UnexpectedError("invalid mesh dimension");
}
}
template <typename MeshType>
void
GnuplotWriter1D::_write(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
double time) const
{
bool has_cell_value = false;
for (const auto& [name, item_value_variant] : output_named_item_value_set) {
has_cell_value |=
std::visit([&](auto&& item_value) { return this->_is_cell_value(item_value); }, item_value_variant);
}
bool has_node_value = false;
for (const auto& [name, item_value_variant] : output_named_item_value_set) {
has_node_value |=
std::visit([&](auto&& item_value) { return this->_is_node_value(item_value); }, item_value_variant);
}
if (has_cell_value and has_node_value) {
throw NormalError("cannot store both node and cell values in a gnuplot file");
}
std::ofstream fout(_getFilename());
fout.precision(15);
fout.setf(std::ios_base::scientific);
fout << _getDateAndVersionComment();
fout << "\n# time = " << time << "\n\n";
_writePreamble<MeshType::Dimension>(output_named_item_value_set, fout);
if (has_cell_value) {
this->_writeCellValues(mesh, output_named_item_value_set, fout);
} else { // has_node_value
this->_writeNodeValues(mesh, output_named_item_value_set, fout);
}
}
void
GnuplotWriter1D::writeMesh(const std::shared_ptr<const IMesh>&) const
{
throw UnexpectedError("This function should not be called");
}
void
GnuplotWriter1D::write(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);
OutputNamedItemValueSet output_named_item_value_set = this->_getOutputNamedItemValueSet(named_discrete_function_list);
switch (mesh->dimension()) {
case 1: {
this->_write(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), output_named_item_value_set, time);
break;
}
case 2: {
std::ostringstream errorMsg;
errorMsg << "gnuplot_1d_writer is not available in dimension " << std::to_string(mesh->dimension()) << '\n'
<< rang::style::bold << "note:" << rang::style::reset << " one can use " << rang::fgB::blue
<< "gnuplot_writer" << rang::style::reset << " in dimension 2";
throw NormalError(errorMsg.str());
}
default: {
throw NormalError("gnuplot format is not available in dimension " + std::to_string(mesh->dimension()));
}
}
}
#ifndef GNUPLOT_WRITER_1D_HPP
#define GNUPLOT_WRITER_1D_HPP
#include <output/WriterBase.hpp>
#include <algebra/TinyMatrix.hpp>
#include <algebra/TinyVector.hpp>
#include <output/OutputNamedItemValueSet.hpp>
class IMesh;
#include <string>
class GnuplotWriter1D : public WriterBase
{
private:
std::string _getDateAndVersionComment() const;
std::string _getFilename() const;
template <typename DataType>
bool _is_cell_value(const CellValue<const DataType>&) const;
template <typename DataType>
bool _is_cell_value(const NodeValue<const DataType>&) const;
template <typename DataType>
bool _is_node_value(const CellValue<const DataType>&) const;
template <typename DataType>
bool _is_node_value(const NodeValue<const DataType>&) const;
template <typename DataType>
void _writeCellValue(const CellValue<DataType>& cell_value, CellId cell_id, std::ostream& fout) const;
template <typename DataType>
void _writeCellValue(const NodeValue<DataType>& node_value, CellId cell_id, std::ostream& fout) const;
template <typename MeshType>
void _writeCellValues(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
std::ostream& fout) const;
template <typename DataType>
void _writeNodeValue(const CellValue<DataType>& cell_value, NodeId cell_id, std::ostream& fout) const;
template <typename DataType>
void _writeNodeValue(const NodeValue<DataType>& node_value, NodeId cell_id, std::ostream& fout) const;
template <typename MeshType>
void _writeNodeValues(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
std::ostream& fout) const;
template <size_t Dimension>
void _writePreamble(const OutputNamedItemValueSet& output_named_item_value_set, std::ostream& fout) const;
template <typename MeshType>
void _write(const std::shared_ptr<const MeshType>& mesh,
const OutputNamedItemValueSet& output_named_item_value_set,
double time) const;
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,
double time) const final;
GnuplotWriter1D(const std::string& base_filename, const double time_period) : WriterBase(base_filename, time_period)
{}
~GnuplotWriter1D() = default;
};
#endif // GNUPLOT_WRITER_1D_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment