Select Git revision
GnuplotWriter1D.cpp
-
Stéphane Del Pino authored
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.
Stéphane Del Pino authoredThe 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.
GnuplotWriter1D.cpp 10.24 KiB
#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()));
}
}
}