Skip to content
Snippets Groups Projects
Select Git revision
  • 8985538bac78dc942c4fc2226bc053dfe233ba80
  • develop default protected
  • feature/variational-hydro
  • origin/stage/bouguettaia
  • feature/gmsh-reader
  • feature/reconstruction
  • save_clemence
  • feature/kinetic-schemes
  • feature/local-dt-fsi
  • feature/composite-scheme-sources
  • feature/composite-scheme-other-fluxes
  • feature/serraille
  • feature/composite-scheme
  • hyperplastic
  • feature/polynomials
  • feature/gks
  • feature/implicit-solver-o2
  • feature/coupling_module
  • feature/implicit-solver
  • feature/merge-local-dt-fsi
  • master protected
  • v0.5.0 protected
  • v0.4.1 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0 protected
  • Kidder
  • v0.0.4 protected
  • v0.0.3 protected
  • v0.0.2 protected
  • v0 protected
  • v0.0.1 protected
33 results

DiamondDualMeshBuilder.hpp

Blame
  • GnuplotWriter.cpp 12.87 KiB
    #include <output/GnuplotWriter.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>
    
    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
    GnuplotWriter::_writeCellData(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.numberOfRows(); ++i) {
          for (size_t j = 0; j < value.numberOfColumns(); ++j) {
            fout << ' ' << value(i, j);
          }
        }
      } else {
        throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>());
      }
    }
    
    template <typename DataType>
    void
    GnuplotWriter::_writeCellData(const CellArray<DataType>& cell_array, CellId cell_id, std::ostream& fout) const
    {
      const auto& array = cell_array[cell_id];
      if constexpr (std::is_arithmetic_v<DataType>) {
        for (size_t i = 0; i < array.size(); ++i) {
          fout << ' ' << array[i];
        }
      } else {
        throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>());
      }
    }
    
    template <typename ItemDataT>
    void
    GnuplotWriter::_writeData(const ItemDataT& item_data,
                              [[maybe_unused]] CellId cell_id,
                              [[maybe_unused]] NodeId node_id,
                              std::ostream& fout) const
    {
      if constexpr (ItemDataT::item_t == ItemType::cell) {
        this->_writeCellData(item_data, cell_id, fout);
      } else if constexpr (ItemDataT::item_t == ItemType::node) {
        this->_writeNodeData(item_data, node_id, fout);
      } else {
        throw UnexpectedError{"invalid item type"};
      }
    }
    
    template <MeshConcept MeshType>
    void
    GnuplotWriter::_writeDataAtNodes(const MeshType& mesh,
                                     const OutputNamedItemDataSet& output_named_item_data_set,
                                     std::ostream& fout) const
    {
      if constexpr (MeshType::Dimension == 1) {
        auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix();
        auto cell_is_owned       = mesh.connectivity().cellIsOwned();
    
        for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) {
          if (cell_is_owned[cell_id]) {
            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<MeshType::Dimension>& xr = mesh.xr()[node_id];
              fout << xr[0];
              for (const auto& [name, item_data_variant] : output_named_item_data_set) {
                std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant);
              }
              fout << '\n';
            }
    
            fout << "\n\n";
          }
        }
      } else if constexpr (MeshType::Dimension == 2) {
        auto cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix();
        auto cell_is_owned       = mesh.connectivity().cellIsOwned();
    
        for (CellId cell_id = 0; cell_id < mesh.numberOfCells(); ++cell_id) {
          if (cell_is_owned[cell_id]) {
            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<MeshType::Dimension>& xr = mesh.xr()[node_id];
              fout << xr[0] << ' ' << xr[1];
              for (const auto& [name, item_data_variant] : output_named_item_data_set) {
                std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant);
              }
              fout << '\n';
            }
            const NodeId& node_id                     = cell_nodes[0];
            const TinyVector<MeshType::Dimension>& xr = mesh.xr()[node_id];
            fout << xr[0] << ' ' << xr[1];
            for (const auto& [name, item_data_variant] : output_named_item_data_set) {
              std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant);
            }
            fout << "\n\n\n";
          }
        }
      } else {
        throw UnexpectedError("invalid mesh dimension");
      }
    }
    
    template <typename DataType>
    void
    GnuplotWriter::_writeNodeData(const NodeValue<DataType>& node_value, NodeId node_id, std::ostream& fout) const
    {
      const auto& value = node_value[node_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.numberOfRows(); ++i) {
          for (size_t j = 0; j < value.numberOfColumns(); ++j) {
            fout << ' ' << value(i, j);
          }
        }
      } else {
        throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>());
      }
    }
    
    template <typename DataType>
    void
    GnuplotWriter::_writeNodeData(const NodeArray<DataType>& node_array, NodeId node_id, std::ostream& fout) const
    {
      const auto& array = node_array[node_id];
      if constexpr (std::is_arithmetic_v<DataType>) {
        for (size_t i = 0; i < array.size(); ++i) {
          fout << ' ' << array[i];
        }
      } else {
        throw UnexpectedError("invalid data type for cell value output: " + demangle<DataType>());
      }
    }
    
    template <MeshConcept MeshType>
    void
    GnuplotWriter::_write(const MeshType& mesh,
                          const OutputNamedItemDataSet& output_named_item_data_set,
                          std::optional<double> time) const
    {
      createDirectoryIfNeeded(_getFilename());
    
      if (parallel::rank() == 0) {
        std::ofstream fout{_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 << this->_getDateAndVersionComment();
        if (time.has_value()) {
          fout << "# time = " << *time << "\n\n";
        }
        this->_writePreamble<MeshType::Dimension>(output_named_item_data_set, fout);
      }
    
      for (const auto& [name, item_data_variant] : output_named_item_data_set) {
        std::visit(
          [&, name = name](auto&& item_data) {
            using ItemDataType = std::decay_t<decltype(item_data)>;
            if (ItemDataType::item_t == ItemType::face) {
              std::ostringstream error_msg;
              error_msg << "gnuplot_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) {
            using ItemDataType = std::decay_t<decltype(item_data)>;
            if (ItemDataType::item_t == ItemType::edge) {
              std::ostringstream error_msg;
              error_msg << "gnuplot_writer does not support edge data, cannot save variable \"" << rang::fgB::yellow << name
                        << rang::fg::reset << '"';
              throw NormalError(error_msg.str());
            }
          },
          item_data_variant);
      }
    
      createDirectoryIfNeeded(m_base_filename);
    
      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);
          if (not fout) {
            std::ostringstream error_msg;
            error_msg << "cannot open file \"" << rang::fgB::yellow << _getFilename() << rang::fg::reset << '"';
            throw NormalError(error_msg.str());
          }
    
          fout.precision(15);
          fout.setf(std::ios_base::scientific);
    
          this->_writeDataAtNodes(mesh, output_named_item_data_set, fout);
        }
        parallel::barrier();
      }
    }
    
    void
    GnuplotWriter::_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) or (MeshType::Dimension == 2)) {
            this->_write(*p_mesh, output_named_item_data_set, time);
          } else {
            throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
          }
        },
        mesh_v.variant());
    }
    
    void
    GnuplotWriter::_writeMesh(const MeshVariant& mesh_v) const
    {
      OutputNamedItemDataSet output_named_item_data_set{};
    
      std::visit(
        [&](auto&& p_mesh) {
          using MeshType = mesh_type_t<decltype(p_mesh)>;
          if constexpr ((MeshType::Dimension == 1) or (MeshType::Dimension == 2)) {
            this->_write(*p_mesh, output_named_item_data_set, {});
          } else {
            throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
          }
        },
        mesh_v.variant());
    }
    
    void
    GnuplotWriter::_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) {
          using MeshType = mesh_type_t<decltype(p_mesh)>;
          if constexpr ((MeshType::Dimension == 1) or (MeshType::Dimension == 2)) {
            this->_write(*p_mesh, output_named_item_data_set, {});
          } else {
            throw NormalError("gnuplot format is not available in dimension " + stringify(MeshType::Dimension));
          }
        },
        mesh_v.variant());
    }