Select Git revision
WriterBase.cpp
-
Stéphane Del Pino authoredStéphane Del Pino authored
WriterBase.cpp 16.28 KiB
#include <output/WriterBase.hpp>
#include <mesh/IMesh.hpp>
#include <mesh/ItemArrayVariant.hpp>
#include <mesh/ItemValueVariant.hpp>
#include <output/NamedDiscreteFunction.hpp>
#include <output/NamedItemArrayVariant.hpp>
#include <output/NamedItemValueVariant.hpp>
#include <output/OutputNamedItemValueSet.hpp>
#include <scheme/DiscreteFunctionP0.hpp>
#include <scheme/DiscreteFunctionP0Vector.hpp>
#include <scheme/DiscreteFunctionVariant.hpp>
#include <scheme/IDiscreteFunctionDescriptor.hpp>
#include <utils/Exceptions.hpp>
template <typename DiscreteFunctionType>
void
WriterBase::_registerDiscreteFunction(const std::string& name,
const DiscreteFunctionType& discrete_function,
OutputNamedItemDataSet& named_item_data_set)
{
if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) {
named_item_data_set.add(NamedItemData{name, discrete_function.cellValues()});
} else {
static_assert(is_discrete_function_P0_vector_v<DiscreteFunctionType>, "unexpected discrete function type");
named_item_data_set.add(NamedItemData{name, discrete_function.cellArrays()});
}
}
void
WriterBase::_checkConnectivity(
const std::shared_ptr<const IMesh>& mesh,
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
Assert(named_discrete_data_list.size() > 0);
std::shared_ptr<const IConnectivity> connectivity = [&]() -> std::shared_ptr<const IConnectivity> {
switch (mesh->dimension()) {
case 1: {
return dynamic_cast<const Mesh<Connectivity<1>>&>(*mesh).shared_connectivity();
}
case 2: {
return dynamic_cast<const Mesh<Connectivity<2>>&>(*mesh).shared_connectivity();
}
case 3: {
return dynamic_cast<const Mesh<Connectivity<3>>&>(*mesh).shared_connectivity();
}
default: {
throw UnexpectedError("invalid dimension");
}
}
}();
for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
const auto& named_discrete_data = named_discrete_data_list[i];
if (named_discrete_data->type() == INamedDiscreteData::Type::item_value) {
const NamedItemValueVariant& named_item_value_variant =
dynamic_cast<const NamedItemValueVariant&>(*named_discrete_data);
std::visit(
[&](auto&& item_value) {
if (item_value.connectivity_ptr() != connectivity) {
std::ostringstream error_msg;
error_msg << "The variable " << rang::fgB::yellow << named_item_value_variant.name() << rang::fg::reset
<< " is not defined on the provided same connectivity as the mesh\n";
throw NormalError(error_msg.str());
}
},
named_item_value_variant.itemValueVariant()->itemValue());
}
}
}
void
WriterBase::_checkSignature(
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
using NameTypeMap = std::map<std::string, std::string>;
NameTypeMap name_type_map;
for (auto named_discrete_data : named_discrete_data_list) {
switch (named_discrete_data->type()) {
case INamedDiscreteData::Type::item_value: {
const NamedItemValueVariant& named_item_value = dynamic_cast<const NamedItemValueVariant&>(*named_discrete_data);
std::visit(
[&](auto&& item_value) {
using ItemValueT = std::decay_t<decltype(item_value)>;
using DataType = std::decay_t<typename ItemValueT::data_type>;
std::ostringstream type_name;
type_name << "item_value(" << dataTypeName(ast_node_data_type_from<DataType>) << ')';
name_type_map[named_discrete_data->name()] = type_name.str();
},
named_item_value.itemValueVariant()->itemValue());
break;
}
case INamedDiscreteData::Type::item_array: {
const NamedItemArrayVariant& named_item_array = dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
std::visit(
[&](auto&& item_value) {
using ItemValueT = std::decay_t<decltype(item_value)>;
using DataType = std::decay_t<typename ItemValueT::data_type>;
std::ostringstream type_name;
type_name << "item_array(" << dataTypeName(ast_node_data_type_from<DataType>) << ')';
name_type_map[named_discrete_data->name()] = type_name.str();
},
named_item_array.itemArrayVariant()->itemArray());
break;
}
case INamedDiscreteData::Type::discrete_function: {
const NamedDiscreteFunction& named_discrete_function =
dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
std::visit(
[&](auto&& discrete_function) {
std::ostringstream type_name;
type_name << "Vh(" << dataTypeName(discrete_function.dataType()) << ')';
name_type_map[named_discrete_data->name()] = type_name.str();
},
named_discrete_function.discreteFunctionVariant()->discreteFunction());
break;
}
}
}
std::string signature{"|"};
for (auto&& [name, type_name] : name_type_map) {
signature += name + std::string{"-"} + type_name + std::string{"|"};
}
if (m_signature.has_value()) {
if (m_signature.value() != signature) {
throw NormalError("output variable list changed");
}
} else {
m_signature = signature;
}
}
void
WriterBase::_checkMesh(const std::shared_ptr<const IMesh>& mesh,
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
Assert(named_discrete_data_list.size() > 0);
for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
const auto& named_discrete_data = named_discrete_data_list[i];
if (named_discrete_data->type() == INamedDiscreteData::Type::discrete_function) {
const NamedDiscreteFunction& named_discrete_function =
dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
std::shared_ptr<const IMesh> discrete_function_mesh =
std::visit([](auto&& f) { return f.mesh(); },
named_discrete_function.discreteFunctionVariant()->discreteFunction());
if (mesh != discrete_function_mesh) {
std::ostringstream error_msg;
error_msg << "The variable " << rang::fgB::yellow << named_discrete_function.name() << rang::fg::reset
<< " is not defined on the provided mesh\n";
throw NormalError(error_msg.str());
}
}
}
}
std::shared_ptr<const IMesh>
WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
Assert(named_discrete_data_list.size() > 0);
std::map<std::shared_ptr<const IMesh>, std::string> mesh_set;
std::map<std::shared_ptr<const IConnectivity>, std::string> connectivity_set;
for (size_t i = 0; i < named_discrete_data_list.size(); ++i) {
const auto& named_discrete_data = named_discrete_data_list[i];
switch (named_discrete_data->type()) {
case INamedDiscreteData::Type::discrete_function: {
const NamedDiscreteFunction& named_discrete_function =
dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
std::shared_ptr mesh = std::visit([&](auto&& f) { return f.mesh(); },
named_discrete_function.discreteFunctionVariant()->discreteFunction());
mesh_set[mesh] = named_discrete_function.name();
switch (mesh->dimension()) {
case 1: {
connectivity_set[dynamic_cast<const Mesh<Connectivity<1>>&>(*mesh).shared_connectivity()] =
named_discrete_function.name();
break;
}
case 2: {
connectivity_set[dynamic_cast<const Mesh<Connectivity<2>>&>(*mesh).shared_connectivity()] =
named_discrete_function.name();
break;
}
case 3: {
connectivity_set[dynamic_cast<const Mesh<Connectivity<3>>&>(*mesh).shared_connectivity()] =
named_discrete_function.name();
break;
}
default: {
throw UnexpectedError("invalid dimension");
}
}
break;
}
case INamedDiscreteData::Type::item_value: {
const NamedItemValueVariant& named_item_value_variant =
dynamic_cast<const NamedItemValueVariant&>(*named_discrete_data);
std::visit([&](
auto&&
item_value) { connectivity_set[item_value.connectivity_ptr()] = named_item_value_variant.name(); },
named_item_value_variant.itemValueVariant()->itemValue());
break;
}
case INamedDiscreteData::Type::item_array: {
const NamedItemArrayVariant& named_item_array_variant =
dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
std::visit([&](
auto&&
item_array) { connectivity_set[item_array.connectivity_ptr()] = named_item_array_variant.name(); },
named_item_array_variant.itemArrayVariant()->itemArray());
break;
}
}
}
if (mesh_set.size() != 1) {
if (mesh_set.size() == 0) {
throw NormalError("cannot find any mesh associated to output quantities");
} else {
std::ostringstream error_msg;
error_msg << "cannot save data using different " << rang::fgB::red << "meshes" << rang::fg::reset
<< " in the same file!\n";
error_msg << rang::fgB::yellow << "note:" << rang::fg::reset
<< "the following variables are defined on different meshes:";
for (const auto& [mesh, name] : mesh_set) {
error_msg << "\n- " << name;
}
throw NormalError(error_msg.str());
}
}
if (connectivity_set.size() > 1) {
std::ostringstream error_msg;
error_msg << "cannot save data using different " << rang::fgB::red << "connectivities" << rang::fg::reset
<< " in the same file!\n";
error_msg << rang::fgB::yellow << "note:" << rang::fg::reset
<< "the following variables are defined on different connectivities:";
for (const auto& [connectivity, name] : connectivity_set) {
error_msg << "\n- " << name;
}
throw NormalError(error_msg.str());
}
return mesh_set.begin()->first;
}
OutputNamedItemDataSet
WriterBase::_getOutputNamedItemDataSet(
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
OutputNamedItemDataSet named_item_data_set;
for (auto& named_discrete_data : named_discrete_data_list) {
switch (named_discrete_data->type()) {
case INamedDiscreteData::Type::discrete_function: {
const NamedDiscreteFunction& named_discrete_function =
dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
const std::string& name = named_discrete_function.name();
const DiscreteFunctionVariant& discrete_function_variant = *named_discrete_function.discreteFunctionVariant();
std::visit([&](auto&& f) { WriterBase::_registerDiscreteFunction(name, f, named_item_data_set); },
discrete_function_variant.discreteFunction());
break;
}
case INamedDiscreteData::Type::item_value: {
const NamedItemValueVariant& named_item_value_variant =
dynamic_cast<const NamedItemValueVariant&>(*named_discrete_data);
const std::string& name = named_item_value_variant.name();
const ItemValueVariant& item_value_variant = *named_item_value_variant.itemValueVariant();
std::visit([&](auto&& item_value) { named_item_data_set.add(NamedItemData{name, item_value}); },
item_value_variant.itemValue());
break;
}
case INamedDiscreteData::Type::item_array: {
const NamedItemArrayVariant& named_item_array_variant =
dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
const std::string& name = named_item_array_variant.name();
const ItemArrayVariant& item_value_variant = *named_item_array_variant.itemArrayVariant();
std::visit(
[&](auto&& item_array) {
using ItemArrayType = std::decay_t<decltype(item_array)>;
using DataType = std::decay_t<typename ItemArrayType::data_type>;
if constexpr (std::is_arithmetic_v<DataType>) {
named_item_data_set.add(NamedItemData{name, item_array});
} else {
throw NormalError("can only write item_array containing scalar values");
}
},
item_value_variant.itemArray());
break;
}
}
}
return named_item_data_set;
}
WriterBase::WriterBase(const std::string& base_filename, const double& time_period)
: m_base_filename{base_filename}, m_period_manager(time_period), m_signature(std::nullopt)
{}
WriterBase::WriterBase(const std::string& base_filename) : m_base_filename{base_filename}, m_signature(std::nullopt) {}
void
WriterBase::write(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
if (m_period_manager.has_value()) {
throw NormalError("this writer requires time value");
} else {
std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
this->_write(*mesh, named_discrete_data_list);
}
}
void
WriterBase::writeIfNeeded(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
double time) const
{
if (m_period_manager.has_value()) {
const double last_time = m_period_manager->getLastTime();
if (time == last_time)
return; // output already performed
if (time >= m_period_manager->nextTime()) {
std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
this->_checkSignature(named_discrete_data_list);
this->_writeAtTime(*mesh, named_discrete_data_list, time);
m_period_manager->setSaveTime(time);
}
} else {
throw NormalError("this writer does not allow time value");
}
}
void
WriterBase::writeForced(const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
double time) const
{
if (m_period_manager.has_value()) {
if (time == m_period_manager->getLastTime())
return; // output already performed
std::shared_ptr<const IMesh> mesh = _getMesh(named_discrete_data_list);
this->_checkSignature(named_discrete_data_list);
this->_writeAtTime(*mesh, named_discrete_data_list, time);
m_period_manager->setSaveTime(time);
} else {
throw NormalError("this writer does not allow time value");
}
}
void
WriterBase::writeOnMesh(const std::shared_ptr<const IMesh>& mesh,
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const
{
if (m_period_manager.has_value()) {
throw NormalError("this writer requires time value");
} else {
this->_checkMesh(mesh, named_discrete_data_list);
this->_checkConnectivity(mesh, named_discrete_data_list);
this->_write(*mesh, named_discrete_data_list);
}
}
void
WriterBase::writeOnMeshIfNeeded(const std::shared_ptr<const IMesh>& mesh,
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
double time) const
{
if (m_period_manager.has_value()) {
if (time == m_period_manager->getLastTime()) {
return; // output already performed
}
this->_checkMesh(mesh, named_discrete_data_list);
this->_checkConnectivity(mesh, named_discrete_data_list);
this->_writeAtTime(*mesh, named_discrete_data_list, time);
m_period_manager->setSaveTime(time);
} else {
throw NormalError("this writer does not allow time value");
}
}
void
WriterBase::writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list,
double time) const
{
if (m_period_manager.has_value()) {
if (time == m_period_manager->getLastTime()) {
return; // output already performed
}
this->_checkMesh(mesh, named_discrete_data_list);
this->_checkConnectivity(mesh, named_discrete_data_list);
this->_writeAtTime(*mesh, named_discrete_data_list, time);
m_period_manager->setSaveTime(time);
} else {
throw NormalError("this writer does not allow time value");
}
}
void
WriterBase::writeMesh(const std::shared_ptr<const IMesh>& mesh) const
{
writeMesh(*mesh);
}
void
WriterBase::writeMesh(const IMesh& mesh) const
{
if (m_period_manager.has_value()) {
throw NormalError("write_mesh requires a writer without time period");
} else {
this->_writeMesh(mesh);
}
}