diff --git a/CMakeLists.txt b/CMakeLists.txt index 95f96478b331b3790fb57946a031cea15fe73d67..a4aa863b266890293cb48ceaf21990120f4d303b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,16 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() endif() +#------------------------------------------------------ + +include (TestBigEndian) +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) +if(IS_BIG_ENDIAN) + set(PUGS_LITTLE_ENDIAN FALSE) +else() + set(PUGS_LITTLE_ENDIAN TRUE) +endif() + #------------------------------------------------------ # defaults use of MPI set(PUGS_ENABLE_MPI AUTO CACHE STRING diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp index f1f87e9cd5969b576d68f3e98551fcc72c12e847..f65a4acfa89830c54e131539252e80a08de67ff3 100644 --- a/src/output/VTKWriter.cpp +++ b/src/output/VTKWriter.cpp @@ -6,6 +6,7 @@ #include <mesh/MeshDataManager.hpp> #include <utils/Messenger.hpp> #include <utils/RevisionInfo.hpp> +#include <utils/pugs_config.hpp> #include <ctime> #include <fstream> @@ -13,6 +14,99 @@ #include <sstream> #include <unordered_map> +class ICharArrayEmbedder +{ + public: + ICharArrayEmbedder() = default; + ICharArrayEmbedder(const ICharArrayEmbedder&) = default; + ICharArrayEmbedder(ICharArrayEmbedder&&) = default; + + virtual size_t size() const = 0; + virtual void write(std::ostream&) const = 0; + + virtual ~ICharArrayEmbedder() = default; +}; + +template <typename InputDataT> +class CharArrayEmbedder : public ICharArrayEmbedder +{ + CastArray<InputDataT, char> m_char_cast_array; + + public: + size_t + size() const final + { + return m_char_cast_array.size(); + } + + void + write(std::ostream& os) const final + { + os.write(&(m_char_cast_array[0]), m_char_cast_array.size()); + } + + CharArrayEmbedder(Array<InputDataT> array) : m_char_cast_array{array} {} + + CharArrayEmbedder() = default; + CharArrayEmbedder(const CharArrayEmbedder&) = default; + CharArrayEmbedder(CharArrayEmbedder&&) = default; + + ~CharArrayEmbedder() = default; +}; + +class VTKWriter::SerializedDataList +{ + private: + std::vector<std::shared_ptr<ICharArrayEmbedder>> m_serialized_data_list; + size_t m_offset = 0; + + public: + size_t + offset() const + { + return m_offset; + } + + template <typename DataT> + void + add(Array<DataT> array) + { + auto array_data = std::make_shared<CharArrayEmbedder<DataT>>(array); + auto size_data = std::make_shared<CharArrayEmbedder<int>>([&] { + Array<int> size_array(1); + size_array[0] = array_data->size(); + return size_array; + }()); + + m_serialized_data_list.push_back(size_data); + m_serialized_data_list.push_back(array_data); + + m_offset += size_data->size() + array_data->size(); + } + + template <typename DataT, ItemType item_type, typename ConnectivityT> + void + add(const ItemValue<DataT, item_type, ConnectivityT>& item_value) + { + Array<std::remove_const_t<DataT>> array(item_value.numberOfItems()); + parallel_for( + item_value.numberOfItems(), PUGS_LAMBDA(ItemIdT<item_type> item_id) { array[item_id] = item_value[item_id]; }); + + this->add(array); + } + + void + write(std::ostream& os) const + { + for (auto serialized_data : m_serialized_data_list) { + serialized_data->write(os); + } + } + + SerializedDataList() = default; + ~SerializedDataList() = default; +}; + std::string VTKWriter::_getFilenamePVTU() const { @@ -134,141 +228,114 @@ struct VTKWriter::VTKType template <typename DataType> void -VTKWriter::_write_array(std::ofstream& os, const std::string& name, const Array<DataType>& item_value) const +VTKWriter::_write_array(std::ofstream& os, + const std::string& name, + const Array<DataType>& item_value, + SerializedDataList& serialized_data_list) const { - os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\">\n"; - for (typename Array<DataType>::index_type i = 0; i < item_value.size(); ++i) { - // The following '+' enforces integer output for char types - os << +item_value[i] << ' '; - } - os << "\n</DataArray>\n"; + os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" offset=\"" + << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <size_t N, typename DataType> void VTKWriter::_write_array(std::ofstream& os, const std::string& name, - const Array<TinyVector<N, DataType>>& item_value) const + const Array<TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N - << "\">\n"; - for (typename Array<DataType>::index_type i = 0; i < item_value.size(); ++i) { - for (size_t j = 0; j < N; ++j) { - // The following '+' enforces integer output for char types - os << +item_value[i][j] << ' '; - } - } - os << "\n</DataArray>\n"; + << "\" offset=\"" << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <typename DataType> void VTKWriter::_write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const DataType>& item_value) const + const NodeValue<const DataType>& item_value, + SerializedDataList& serialized_data_list) const { - os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\">\n"; - for (NodeId i = 0; i < item_value.size(); ++i) { - // The following '+' enforces integer output for char types - os << +item_value[i] << ' '; - } - os << "\n</DataArray>\n"; + os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" offset=\"" + << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <size_t N, typename DataType> void VTKWriter::_write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyVector<N, DataType>>& item_value) const + const NodeValue<const TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N - << "\">\n"; - for (NodeId i = 0; i < item_value.size(); ++i) { - for (size_t j = 0; j < N; ++j) { - // The following '+' enforces integer output for char types - os << +item_value[i][j] << ' '; - } - } - os << "\n</DataArray>\n"; + << "\" offset=\"" << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <size_t N, typename DataType> void VTKWriter::_write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyMatrix<N, DataType>>& item_value) const + const NodeValue<const TinyMatrix<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N * N - << "\">\n"; - for (NodeId i = 0; i < item_value.size(); ++i) { - for (size_t j = 0; j < N; ++j) { - for (size_t k = 0; k < N; ++k) { - // The following '+' enforces integer output for char types - os << +item_value[i](j, k) << ' '; - } - } - } - os << "\n</DataArray>\n"; + << "\" offset=\"" << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <typename DataType> void -VTKWriter::_write_node_value(std::ofstream&, const std::string&, const CellValue<const DataType>&) const +VTKWriter::_write_node_value(std::ofstream&, + const std::string&, + const CellValue<const DataType>&, + SerializedDataList&) const {} template <typename DataType> void VTKWriter::_write_cell_value(std::ofstream& os, const std::string& name, - const CellValue<const DataType>& item_value) const + const CellValue<const DataType>& item_value, + SerializedDataList& serialized_data_list) const { - os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\">\n"; - for (CellId i = 0; i < item_value.size(); ++i) { - // The following '+' enforces integer output for char types - os << +item_value[i] << ' '; - } - os << "\n</DataArray>\n"; + os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" offset=\"" + << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <size_t N, typename DataType> void VTKWriter::_write_cell_value(std::ofstream& os, const std::string& name, - const CellValue<const TinyVector<N, DataType>>& item_value) const + const CellValue<const TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N - << "\">\n"; - for (CellId i = 0; i < item_value.size(); ++i) { - for (size_t j = 0; j < N; ++j) { - // The following '+' enforces integer output for char types - os << +item_value[i][j] << ' '; - } - } - os << "\n</DataArray>\n"; + << "\" offset=\"" << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <size_t N, typename DataType> void VTKWriter::_write_cell_value(std::ofstream& os, const std::string& name, - const CellValue<const TinyMatrix<N, DataType>>& item_value) const + const CellValue<const TinyMatrix<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const { os << "<DataArray type=\"" << VTKType<DataType>::name << "\" Name=\"" << name << "\" NumberOfComponents=\"" << N * N - << "\">\n"; - for (CellId i = 0; i < item_value.size(); ++i) { - for (size_t j = 0; j < N; ++j) { - for (size_t k = 0; k < N; ++k) { - // The following '+' enforces integer output for char types - os << +item_value[i](j, k) << ' '; - } - } - } - os << "\n</DataArray>\n"; + << "\" offset=\"" << serialized_data_list.offset() << "\" format=\"appended\"/>\n"; + serialized_data_list.add(item_value); } template <typename DataType> void -VTKWriter::_write_cell_value(std::ofstream&, const std::string&, const NodeValue<const DataType>&) const +VTKWriter::_write_cell_value(std::ofstream&, + const std::string&, + const NodeValue<const DataType>&, + SerializedDataList&) const {} template <typename MeshType> @@ -329,23 +396,34 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, fout << "</VTKFile>\n"; } - { // write VTK files + { + SerializedDataList serialize_data_list; + + // write VTK files std::ofstream fout(_getFilenameVTU(parallel::rank())); fout << "<?xml version=\"1.0\"?>\n"; fout << _getDateAndVersionComment(); - fout << "<VTKFile type=\"UnstructuredGrid\">\n"; + fout << "<VTKFile type=\"UnstructuredGrid\""; +#if defined(PUGS_LITTLE_ENDIAN) + fout << " byte_order=\"LittleEndian\""; +#else + fout << " byte_order=\"BigEndian\""; +#endif + fout << ">\n"; fout << "<UnstructuredGrid>\n"; fout << "<Piece NumberOfPoints=\"" << mesh->numberOfNodes() << "\" NumberOfCells=\"" << mesh->numberOfCells() << "\">\n"; fout << "<CellData>\n"; for (const auto& [name, item_value_variant] : output_named_item_value_set) { - std::visit([&, name = name](auto&& item_value) { return this->_write_cell_value(fout, name, item_value); }, + std::visit([&, name = name]( + auto&& item_value) { return this->_write_cell_value(fout, name, item_value, serialize_data_list); }, item_value_variant); } fout << "</CellData>\n"; fout << "<PointData>\n"; for (const auto& [name, item_value_variant] : output_named_item_value_set) { - std::visit([&, name = name](auto&& item_value) { return this->_write_node_value(fout, name, item_value); }, + std::visit([&, name = name]( + auto&& item_value) { return this->_write_node_value(fout, name, item_value, serialize_data_list); }, item_value_variant); } fout << "</PointData>\n"; @@ -363,7 +441,7 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, positions[r][i] = 0; } }); - _write_array(fout, "Positions", positions); + _write_array(fout, "Positions", positions, serialize_data_list); } fout << "</Points>\n"; @@ -371,7 +449,7 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, { const auto& cell_to_node_matrix = mesh->connectivity().cellToNodeMatrix(); - _write_array(fout, "connectivity", cell_to_node_matrix.entries()); + _write_array(fout, "connectivity", cell_to_node_matrix.entries(), serialize_data_list); } { @@ -383,7 +461,7 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, offset += cell_nodes.size(); offsets[j] = offset; } - _write_array(fout, "offsets", offsets); + _write_array(fout, "offsets", offsets, serialize_data_list); } { @@ -437,7 +515,7 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, } } }); - _write_array(fout, "types", types); + _write_array(fout, "types", types, serialize_data_list); if constexpr (MeshType::Dimension == 3) { const bool has_general_polyhedron = [&] { for (size_t i = 0; i < types.size(); ++i) { @@ -507,6 +585,11 @@ VTKWriter::_write(const std::shared_ptr<const MeshType>& mesh, fout << "</Cells>\n"; fout << "</Piece>\n"; fout << "</UnstructuredGrid>\n"; + fout << "<AppendedData encoding=\"raw\">\n"; + fout << "_"; + serialize_data_list.write(fout); + fout << '\n'; + fout << "</AppendedData>\n"; fout << "</VTKFile>\n"; } diff --git a/src/output/VTKWriter.hpp b/src/output/VTKWriter.hpp index 704ba63f990ead2b6b8e8f64cafdda627c2be64b..7f38119222474af2df46508e96fb27d7a40053f9 100644 --- a/src/output/VTKWriter.hpp +++ b/src/output/VTKWriter.hpp @@ -14,6 +14,8 @@ class IMesh; class VTKWriter : public WriterBase { private: + class SerializedDataList; + std::string _getDateAndVersionComment() const; std::string _getFilenamePVTU() const; @@ -56,42 +58,64 @@ class VTKWriter : public WriterBase struct VTKType; template <typename DataType> - void _write_array(std::ofstream& os, const std::string& name, const Array<DataType>& item_value) const; + void _write_array(std::ofstream& os, + const std::string& name, + const Array<DataType>& item_value, + SerializedDataList& serialized_data_list) const; template <size_t N, typename DataType> - void _write_array(std::ofstream& os, const std::string& name, const Array<TinyVector<N, DataType>>& item_value) const; + void _write_array(std::ofstream& os, + const std::string& name, + const Array<TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const; template <typename DataType> - void _write_node_value(std::ofstream& os, const std::string& name, const NodeValue<const DataType>& item_value) const; + void _write_node_value(std::ofstream& os, + const std::string& name, + const NodeValue<const DataType>& item_value, + SerializedDataList& serialized_data_list) const; template <size_t N, typename DataType> void _write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyVector<N, DataType>>& item_value) const; + const NodeValue<const TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const; template <size_t N, typename DataType> void _write_node_value(std::ofstream& os, const std::string& name, - const NodeValue<const TinyMatrix<N, DataType>>& item_value) const; + const NodeValue<const TinyMatrix<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const; template <typename DataType> - void _write_node_value(std::ofstream&, const std::string&, const CellValue<const DataType>&) const; + void _write_node_value(std::ofstream&, + const std::string&, + const CellValue<const DataType>&, + SerializedDataList&) const; template <typename DataType> - void _write_cell_value(std::ofstream& os, const std::string& name, const CellValue<const DataType>& item_value) const; + void _write_cell_value(std::ofstream& os, + const std::string& name, + const CellValue<const DataType>& item_value, + SerializedDataList& serialized_data_list) const; template <size_t N, typename DataType> void _write_cell_value(std::ofstream& os, const std::string& name, - const CellValue<const TinyVector<N, DataType>>& item_value) const; + const CellValue<const TinyVector<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const; template <size_t N, typename DataType> void _write_cell_value(std::ofstream& os, const std::string& name, - const CellValue<const TinyMatrix<N, DataType>>& item_value) const; + const CellValue<const TinyMatrix<N, DataType>>& item_value, + SerializedDataList& serialized_data_list) const; template <typename DataType> - void _write_cell_value(std::ofstream&, const std::string&, const NodeValue<const DataType>&) const; + void _write_cell_value(std::ofstream&, + const std::string&, + const NodeValue<const DataType>&, + SerializedDataList&) const; template <typename MeshType> void _write(const std::shared_ptr<const MeshType>& mesh, diff --git a/src/utils/pugs_config.hpp.in b/src/utils/pugs_config.hpp.in index de267d26e10fb41994bbc72438b57d577e4b447a..84a6d8fa0c2d50eb623d5d1c2b52765f5610de24 100644 --- a/src/utils/pugs_config.hpp.in +++ b/src/utils/pugs_config.hpp.in @@ -9,6 +9,8 @@ #cmakedefine SYSTEM_IS_DARWIN #cmakedefine SYSTEM_IS_WINDOWS +#cmakedefine PUGS_LITTLE_ENDIAN + #define PUGS_BUILD_TYPE "@CMAKE_BUILD_TYPE@" #define PUGS_BINARY_DIR "@PUGS_BINARY_DIR@"