Serializer class: SummaryState & UDQState

This commit is contained in:
Joakim Hove 2020-08-31 08:45:30 +02:00
parent 432f666768
commit 4b3304730c
9 changed files with 276 additions and 70 deletions

View File

@ -404,6 +404,7 @@ if(ENABLE_ECL_OUTPUT)
tests/test_RFT.cpp
tests/test_rst.cpp
tests/test_Solution.cpp
tests/test_Serializer.cpp
tests/test_Summary.cpp
tests/test_Summary_Group.cpp
tests/test_Tables.cpp
@ -518,6 +519,7 @@ list( APPEND PUBLIC_HEADER_FILES
opm/common/OpmLog/OpmLog.hpp
opm/common/OpmLog/StreamLog.hpp
opm/common/OpmLog/TimerLog.hpp
opm/common/utility/Serializer.hpp
opm/common/utility/ActiveGridCells.hpp
opm/common/utility/FileSystem.hpp
opm/common/utility/numeric/cmp.hpp

View File

@ -0,0 +1,106 @@
/*
Copyright 2020 Equinor ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstring>
#include <unordered_map>
#include <vector>
#ifndef OPM_SERIALIZER_HPP
#define OPM_SERIALIZER_HPP
namespace Opm {
/*
This is a very basic serialization class used to support serialization of
small state objects from opm common. The main serialization code used in
opm/flow is initiated and controlled from the restart code, and therefor
slightly cumbersome to use for objects which should be serialized not as part
of the restart code.
*/
class Serializer {
public:
Serializer() = default;
explicit Serializer(const std::vector<char>& buffer_arg) :
buffer(buffer_arg)
{}
template <typename T>
void put(const T& value) {
this->pack(std::addressof(value), sizeof(T));
}
template <typename T>
T get() {
T value;
std::memcpy(&value, &this->buffer[pos], sizeof(T));
this->pos += sizeof(T);
return value;
}
template<typename K, typename T>
void put(const std::unordered_map<K,T>& values) {
this->put(values.size());
for (const auto& value_pair : values) {
this->put(value_pair.first);
this->put(value_pair.second);
}
}
template<typename K, typename T>
std::unordered_map<K,T> get() {
std::unordered_map<K,T> values;
auto size = this->get<std::size_t>();
for (std::size_t index = 0; index < size; index++) {
auto key = this->get<K>();
auto value = this->get<T>();
values.insert( std::make_pair(key,value) );
}
return std::move(values);
}
std::vector<char> 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 inline Serializer::put(const std::string& value) {
this->put<std::string::size_type>(value.size());
this->pack(value.c_str(), value.size());
}
template<>
std::string inline Serializer::get<std::string>() {
std::string::size_type length = this->get<std::string::size_type>();
this->pos += length;
return {std::addressof(this->buffer[this->pos - length]), length};
}
}
#endif

View File

@ -26,6 +26,7 @@
#include <unordered_map>
#include <vector>
#include <opm/common/utility/Serializer.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
@ -35,7 +36,6 @@ public:
UDQScalar() = default;
explicit UDQScalar(double value);
explicit UDQScalar(const std::string& wgname);
UDQScalar(const std::string& wgname, double value);
void operator+=(const UDQScalar& rhs);
void operator+=(double rhs);
@ -51,6 +51,9 @@ public:
bool defined() const;
double value() const;
const std::string& wgname() const;
bool operator==(const UDQScalar& other) const;
static UDQScalar deserialize(Serializer& ser);
void serialize(Serializer& ser) const;
public:
std::optional<double> m_value;
std::string m_wgname;
@ -64,6 +67,8 @@ public:
UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames);
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
UDQSet(const std::string& name, std::size_t size);
void serialize(Serializer& ser) const;
static UDQSet deserialize(Serializer& ser);
static UDQSet scalar(const std::string& name, double value);
static UDQSet empty(const std::string& name);
static UDQSet wells(const std::string& name, const std::vector<std::string>& wells);
@ -98,6 +103,7 @@ public:
const std::string& name() const;
void name(const std::string& name);
UDQVarType var_type() const;
bool operator==(const UDQSet& other) const;
private:
UDQSet() = default;

View File

@ -22,6 +22,7 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
@ -40,6 +41,9 @@ public:
double get_well_var(const std::string& well, const std::string& var) const;
void add(const UDQSet& result);
std::vector<char> serialize() const;
void deserialize(const std::vector<char>& buffer);
bool operator==(const UDQState& other) const;
private:
double get_wg_var(const std::string& well, const std::string& key, UDQVarType var_type) const;
double undefined_value;

View File

@ -23,6 +23,7 @@
#include <iostream>
#include <iomanip>
#include <opm/common/utility/Serializer.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/SummaryState.hpp>
@ -303,80 +304,22 @@ namespace {
}
namespace {
class Serializer {
public:
Serializer() = default;
explicit Serializer(const std::vector<char>& buffer_arg) :
buffer(buffer_arg)
{}
template <typename T>
void put(const T& value) {
this->pack(std::addressof(value), sizeof(T));
}
template <typename T>
T get() {
T value;
std::memcpy(&value, &this->buffer[pos], sizeof(T));
this->pos += sizeof(T);
return value;
}
std::vector<char> 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<std::string::size_type>(value.size());
this->pack(value.c_str(), value.size());
}
template <>
std::string Serializer::get() {
std::string::size_type length = this->get<std::string::size_type>();
this->pos += length;
return {std::addressof(this->buffer[this->pos - length]), length};
}
void put_map(Serializer& ser, const std::unordered_map<std::string, double>& values) {
ser.put(values.size());
for (const auto& value_pair : values) {
ser.put(value_pair.first);
ser.put(value_pair.second);
}
}
}
std::vector<char> SummaryState::serialize() const {
Serializer ser;
ser.put(this->elapsed);
put_map(ser, values);
ser.put(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(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);
ser.put(group_var_pair.second);
}
return std::move(ser.buffer);
@ -393,14 +336,7 @@ namespace {
Serializer ser(buffer);
this->elapsed = ser.get<double>();
{
std::size_t num_values = ser.get<std::size_t>();
for (std::size_t index = 0; index < num_values; index++) {
std::string key = ser.get<std::string>();
double value = ser.get<double>();
this->update(key, value);
}
}
this->values = ser.get<std::string, double>();
{
std::size_t num_well_var = ser.get<std::size_t>();

View File

@ -24,6 +24,29 @@
namespace Opm {
UDQScalar UDQScalar::deserialize(Serializer& ser) {
std::string wgname = ser.get<std::string>();
UDQScalar scalar(wgname);
bool has_value = ser.get<bool>();
if (has_value) {
double value = ser.get<double>();
scalar.assign(value);
}
return scalar;
}
void UDQScalar::serialize(Serializer& ser) const {
ser.put<std::string>(this->m_wgname);
if (this->m_value.has_value()) {
ser.put<bool>(true);
ser.put<double>(*this->m_value);
} else
ser.put<bool>(false);
}
UDQScalar::UDQScalar(double value)
{
this->assign(value);
@ -108,6 +131,11 @@ UDQScalar::operator bool() const {
return this->defined();
}
bool UDQScalar::operator==(const UDQScalar& other) const {
return this->m_value == other.m_value &&
this->m_wgname == other.m_wgname;
}
const std::string& UDQSet::name() const {
return this->m_name;
@ -511,4 +539,35 @@ UDQSet operator/(double lhs, const UDQSet&rhs) {
return result;
}
bool UDQSet::operator==(const UDQSet& other) const {
return this->m_name == other.m_name &&
this->m_var_type == other.m_var_type &&
this->values == other.values;
}
UDQSet UDQSet::deserialize(Serializer& ser)
{
auto name = ser.get<std::string>();
auto var_type = ser.get<UDQVarType>();
auto size = ser.get<std::size_t>();
UDQSet udq_set(name, var_type, size);
for (std::size_t index = 0; index < size; index++) {
auto value = UDQScalar::deserialize(ser);
udq_set.values[index] = std::move(value);
}
return udq_set;
}
void UDQSet::serialize(Serializer& ser) const {
ser.put<std::string>(this->m_name);
ser.put<UDQVarType>(this->m_var_type);
ser.put<std::size_t>(this->values.size());
for (const auto& value : this->values)
value.serialize(ser);
}
}

View File

@ -20,6 +20,7 @@
#include <stdexcept>
#include <opm/common/utility/Serializer.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQState.hpp>
namespace Opm {
@ -119,6 +120,38 @@ double UDQState::get_group_var(const std::string& group, const std::string& key)
return this->get_wg_var(group, key, UDQVarType::GROUP_VAR);
}
bool UDQState::operator==(const UDQState& other) const {
return this->undefined_value == other.undefined_value &&
this->values == other.values;
}
std::vector<char> UDQState::serialize() const {
Serializer ser;
ser.put(this->undefined_value);
ser.put(this->values.size());
for (const auto& set_pair : this->values) {
ser.put( set_pair.first );
set_pair.second.serialize( ser );
}
return std::move(ser.buffer);
}
void UDQState::deserialize(const std::vector<char>& buffer) {
Serializer ser(buffer);
this->undefined_value = ser.get<double>();
this->values.clear();
{
std::size_t size = ser.get<std::size_t>();
for (std::size_t index = 0; index < size; index++) {
auto key = ser.get<std::string>();
auto udq_set = UDQSet::deserialize(ser);
this->values.insert( std::make_pair(key, udq_set) );
}
}
}
}

View File

@ -94,8 +94,15 @@ BOOST_AUTO_TEST_CASE(UDQSTATE) {
BOOST_CHECK_EQUAL(st.get_well_var("P1", "WUPR"), 75);
BOOST_CHECK_EQUAL(st.get_well_var("P2", "WUPR"), undefined_value);
const auto buffer = st.serialize();
UDQState st2(1067);
st2.deserialize( buffer );
BOOST_CHECK(st == st2);
}
BOOST_AUTO_TEST_CASE(TYPE_COERCION) {
BOOST_CHECK( UDQVarType::SCALAR == UDQ::coerce(UDQVarType::SCALAR, UDQVarType::SCALAR) );
@ -247,6 +254,9 @@ BOOST_AUTO_TEST_CASE(UDQFieldSetTest) {
BOOST_AUTO_TEST_CASE(UDQWellSetNANTest) {
std::vector<std::string> wells = {"P1", "P2", "I1", "I2"};
UDQSet ws = UDQSet::wells("NAME", wells);
UDQSet ws2 = UDQSet::wells("NAME", wells);
BOOST_CHECK(ws == ws2);
for (std::size_t i = 0; i < 4; i++)
ws.assign(i, i*1.0);

50
tests/test_Serializer.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright 2020 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE "Serializer"
#include <boost/test/unit_test.hpp>
#include <string>
#include <unordered_map>
#include <opm/common/utility/Serializer.hpp>
BOOST_AUTO_TEST_CASE(SERIALIZER) {
Opm::Serializer ser;
int int_value = 100;
double double_value = 3.14;
std::string string_value = "String";
std::unordered_map<std::string, int> m = {{"A", 1}, {"B", 2}, {"C", 3}};
ser.put(int_value);
ser.put(double_value);
ser.put(string_value);
ser.put(m);
Opm::Serializer ser2(ser.buffer);
BOOST_CHECK_EQUAL(ser2.get<int>(), int_value);
BOOST_CHECK_EQUAL(ser2.get<double>(), double_value);
BOOST_CHECK_EQUAL(ser2.get<std::string>(), string_value);
std::unordered_map<std::string, int> m2 = ser2.get<std::string,int>();
BOOST_CHECK(m2 == m);
}