diff --git a/opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp b/opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp index e8fe0ec07..0fb88ae80 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp @@ -91,6 +91,8 @@ public: std::vector wells(const std::string& var) const; std::vector groups() const; std::vector groups(const std::string& var) const; + std::vector serialize() const; + void deserialize(const std::vector& buffer); const_iterator begin() const; const_iterator end() const; std::size_t num_wells() const; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/SummaryState.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/SummaryState.cpp index c68354a8f..b549256dc 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/SummaryState.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/SummaryState.cpp @@ -18,6 +18,7 @@ */ #include +#include #include @@ -211,4 +212,134 @@ namespace { std::size_t SummaryState::size() const { return this->values.size(); } + + +namespace { + class Serializer { + public: + Serializer() = default; + Serializer(const std::vector& buffer) : + buffer(buffer) + {} + + + template + void put(const T& value) { + this->pack(std::addressof(value), sizeof(T)); + } + + + + template + T get() { + T value; + std::memcpy(&value, &this->buffer[pos], sizeof(T)); + this->pos += sizeof(T); + return value; + } + + std::vector buffer; + private: + void pack(const void * ptr, std::size_t value_size) { + std::size_t write_pos = this->buffer.size(); + std::size_t new_size = write_pos + value_size; + this->buffer.resize( new_size ); + std::memcpy(&this->buffer[write_pos], ptr, value_size); + } + + std::size_t pos = 0; + }; + + template <> + void Serializer::put(const std::string& value) { + this->put(value.size()); + this->pack(value.c_str(), value.size()); + } + + template <> + std::string Serializer::get() { + std::string::size_type length = this->get(); + this->pos += length; + return {std::addressof(this->buffer[this->pos - length]), length}; + } + + void put_map(Serializer& ser, const std::unordered_map& values) { + ser.put(values.size()); + for (const auto& value_pair : values) { + ser.put(value_pair.first); + ser.put(value_pair.second); + } + } + +} + + std::vector SummaryState::serialize() const { + std::vector buffer; + Serializer ser; + ser.put(this->elapsed); + put_map(ser, values); + + ser.put(this->well_values.size()); + for (const auto& well_var_pair : this->well_values) { + ser.put(well_var_pair.first); + put_map(ser, well_var_pair.second); + } + + ser.put(this->group_values.size()); + for (const auto& group_var_pair : this->group_values) { + ser.put(group_var_pair.first); + put_map(ser, group_var_pair.second); + } + + return std::move(ser.buffer); + } + + + void SummaryState::deserialize(const std::vector& buffer) { + this->values.clear(); + this->m_wells.clear(); + this->well_values.clear(); + this->m_groups.clear(); + this->group_values.clear(); + this->elapsed = 0; + + Serializer ser(buffer); + this->elapsed = ser.get(); + { + std::size_t num_values = ser.get(); + for (std::size_t index = 0; index < num_values; index++) { + std::string key = ser.get(); + double value = ser.get(); + this->update(key, value); + } + } + + { + std::size_t num_well_var = ser.get(); + for (std::size_t var_index = 0; var_index < num_well_var; var_index++) { + std::string var = ser.get(); + + std::size_t num_well = ser.get(); + for (std::size_t well_index=0; well_index < num_well; well_index++) { + std::string well = ser.get(); + double value = ser.get(); + this->update_well_var(well, var, value); + } + } + } + + { + std::size_t num_group_var = ser.get(); + for (std::size_t var_index = 0; var_index < num_group_var; var_index++) { + std::string var = ser.get(); + + std::size_t num_group = ser.get(); + for (std::size_t group_index=0; group_index < num_group; group_index++) { + std::string group = ser.get(); + double value = ser.get(); + this->update_group_var(group, var, value); + } + } + } + } } diff --git a/tests/test_Summary.cpp b/tests/test_Summary.cpp index 31c93072d..f51423814 100644 --- a/tests/test_Summary.cpp +++ b/tests/test_Summary.cpp @@ -3225,4 +3225,84 @@ BOOST_AUTO_TEST_CASE(SummaryState_TOTAL) { BOOST_CHECK_EQUAL(st.get_elapsed(), 200); } +bool equal(const SummaryState& st1 , const SummaryState& st2) { + if (st1.size() != st2.size()) + return false; + + { + const auto& wells2 = st2.wells(); + if (wells2.size() != st1.wells().size()) + return false; + + for (const auto& well : st1.wells()) { + auto f = std::find(wells2.begin(), wells2.end(), well); + if (f == wells2.end()) + return false; + } + } + + { + const auto& groups2 = st2.groups(); + if (groups2.size() != st1.groups().size()) + return false; + + for (const auto& group : st1.groups()) { + auto f = std::find(groups2.begin(), groups2.end(), group); + if (f == groups2.end()) + return false; + } + } + + + for (const auto& value_pair : st1) { + const std::string& key = value_pair.first; + double value = value_pair.second; + if (value != st2.get(key)) + return false; + } + + return st1.get_elapsed() == st2.get_elapsed(); +} + + +void test_serialize(const SummaryState& st) { + SummaryState st2; + auto serial = st.serialize(); + st2.deserialize(serial); + BOOST_CHECK( equal(st, st2)); + + st2.update_elapsed(1234567.09); + st2.update("FOPT", 200); + st2.deserialize(serial); + BOOST_CHECK( equal(st, st2)); +} + + +BOOST_AUTO_TEST_CASE(serialize_sumary_state) { + SummaryState st; + test_serialize(st); + + st.update_elapsed(1000); + test_serialize(st); + + st.update("FOPT", 100); + test_serialize(st); + + st.update("FGPT", 100); + test_serialize(st); + + st.update_well_var("OP_1", "WOPR", 1000); + test_serialize(st); + + st.update_well_var("OP_2", "WGOR", 0.67); + test_serialize(st); + + st.update_group_var("G1", "GOPR", 1000); + test_serialize(st); + + st.update_group_var("G2", "GGOR", 0.67); + test_serialize(st); + +} + BOOST_AUTO_TEST_SUITE_END()