Extract Common Base Class For Flat Tables With Record Copying

This commit introduces a new helper template class,

    FlatTableWithCopy<RecordType>

which wraps a vector<RecordType>, provides constructors from
DeckKeyword and initializer_list<RecordType> and handles copying
tables for all-defaulted records.

We reimplement the PVTW, DENSITY, and GRAVITY tables in terms of
this helper class to reduce duplication.  If the copy behaviour is
generally useful/needed we expect to replace the existing FlatTable
mechanism with the new helper.

Suggested by: Markus Blatt
This commit is contained in:
Bård Skaflestad 2022-06-24 12:56:08 +02:00
parent d35abfddb6
commit 254b2e2862
2 changed files with 76 additions and 149 deletions

View File

@ -3,6 +3,7 @@
#include <cstddef> #include <cstddef>
#include <initializer_list> #include <initializer_list>
#include <string_view>
#include <vector> #include <vector>
namespace Opm { namespace Opm {
@ -24,6 +25,45 @@ struct FlatTable : public std::vector< T > {
} }
}; };
template <typename RecordType>
class FlatTableWithCopy
{
public:
FlatTableWithCopy() = default;
explicit FlatTableWithCopy(const DeckKeyword& kw,
std::string_view expect = "");
explicit FlatTableWithCopy(std::initializer_list<RecordType> records);
auto size() const { return this->table_.size(); }
bool empty() const { return this->table_.empty(); }
auto begin() const { return this->table_.begin(); }
auto end() const { return this->table_.end(); }
const RecordType& operator[](const std::size_t tableID) const
{
return this->table_[tableID];
}
const RecordType& at(const std::size_t tableID) const
{
return this->table_.at(tableID);
}
bool operator==(const FlatTableWithCopy& other) const
{
return this->table_ == other.table_;
}
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer.vector(this->table_);
}
protected:
std::vector<RecordType> table_{};
};
struct GRAVITYRecord { struct GRAVITYRecord {
static constexpr std::size_t size = 3; static constexpr std::size_t size = 3;
@ -46,33 +86,12 @@ struct GRAVITYRecord {
} }
}; };
class GravityTable struct GravityTable : public FlatTableWithCopy<GRAVITYRecord>
{ {
public:
GravityTable() = default; GravityTable() = default;
explicit GravityTable(const DeckKeyword& kw); explicit GravityTable(const DeckKeyword& kw);
explicit GravityTable(std::initializer_list<GRAVITYRecord> records); explicit GravityTable(std::initializer_list<GRAVITYRecord> records);
auto size() const { return this->table_.size(); }
bool empty() const { return this->table_.empty(); }
auto begin() const { return this->table_.begin(); }
auto end() const { return this->table_.end(); }
const GRAVITYRecord& operator[](const std::size_t tableID) const
{
return this->table_[tableID];
}
const GRAVITYRecord& at(const std::size_t tableID) const
{
return this->table_.at(tableID);
}
bool operator==(const GravityTable& other) const
{
return this->table_ == other.table_;
}
static GravityTable serializeObject() static GravityTable serializeObject()
{ {
return GravityTable({{1.0, 2.0, 3.0}}); return GravityTable({{1.0, 2.0, 3.0}});
@ -81,11 +100,8 @@ public:
template <class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer.vector(this->table_); FlatTableWithCopy::serializeOp(serializer);
} }
private:
std::vector<GRAVITYRecord> table_{};
}; };
struct DENSITYRecord { struct DENSITYRecord {
@ -110,33 +126,12 @@ struct DENSITYRecord {
} }
}; };
class DensityTable struct DensityTable : public FlatTableWithCopy<DENSITYRecord>
{ {
public:
DensityTable() = default; DensityTable() = default;
explicit DensityTable(const DeckKeyword& kw); explicit DensityTable(const DeckKeyword& kw);
explicit DensityTable(std::initializer_list<DENSITYRecord> records);
explicit DensityTable(const GravityTable& gravity); explicit DensityTable(const GravityTable& gravity);
explicit DensityTable(std::initializer_list<DENSITYRecord> records);
auto size() const { return this->table_.size(); }
bool empty() const { return this->table_.empty(); }
auto begin() const { return this->table_.begin(); }
auto end() const { return this->table_.end(); }
const DENSITYRecord& operator[](const std::size_t tableID) const
{
return this->table_[tableID];
}
const DENSITYRecord& at(const std::size_t tableID) const
{
return this->table_.at(tableID);
}
bool operator==(const DensityTable& other) const
{
return this->table_ == other.table_;
}
static DensityTable serializeObject() static DensityTable serializeObject()
{ {
@ -146,11 +141,8 @@ public:
template <class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer.vector(this->table_); FlatTableWithCopy::serializeOp(serializer);
} }
private:
std::vector<DENSITYRecord> table_{};
}; };
struct DiffCoeffRecord { struct DiffCoeffRecord {
@ -227,31 +219,12 @@ struct PVTWRecord {
} }
}; };
class PvtwTable struct PvtwTable : public FlatTableWithCopy<PVTWRecord>
{ {
public:
PvtwTable() = default; PvtwTable() = default;
explicit PvtwTable(const DeckKeyword& kw); explicit PvtwTable(const DeckKeyword& kw);
explicit PvtwTable(std::initializer_list<PVTWRecord> records); explicit PvtwTable(std::initializer_list<PVTWRecord> records);
auto size() const { return this->table_.size(); }
bool empty() const { return this->table_.empty(); }
const PVTWRecord& operator[](const std::size_t tableID) const
{
return this->table_[tableID];
}
const PVTWRecord& at(const std::size_t tableID) const
{
return this->table_.at(tableID);
}
bool operator==(const PvtwTable& other) const
{
return this->table_ == other.table_;
}
static PvtwTable serializeObject() static PvtwTable serializeObject()
{ {
return PvtwTable({{1.0, 2.0, 3.0, 4.0, 5.0}}); return PvtwTable({{1.0, 2.0, 3.0, 4.0, 5.0}});
@ -260,11 +233,8 @@ public:
template <class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer.vector(this->table_); FlatTableWithCopy::serializeOp(serializer);
} }
private:
std::vector<PVTWRecord> table_{};
}; };
struct ROCKRecord { struct ROCKRecord {

View File

@ -94,6 +94,7 @@
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <stdexcept> #include <stdexcept>
#include <string_view>
#include <stddef.h> #include <stddef.h>
@ -1574,13 +1575,14 @@ bool all_defaulted(const DeckRecord& record)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
PvtwTable::PvtwTable(const DeckKeyword& kw) template <typename RecordType>
FlatTableWithCopy<RecordType>::FlatTableWithCopy(const DeckKeyword& kw,
std::string_view expect)
{ {
if (kw.name() != ParserKeywords::PVTW::keywordName) { if (!expect.empty() && (kw.name() != expect)) {
throw std::invalid_argument { throw std::invalid_argument {
fmt::format("Keyword {} cannot be used to " fmt::format("Keyword {} cannot be used to "
"initialise {} table structures", kw.name(), "initialise {} table structures", kw.name(), expect)
ParserKeywords::PVTW::keywordName)
}; };
} }
@ -1588,9 +1590,9 @@ PvtwTable::PvtwTable(const DeckKeyword& kw)
for (const auto& record : kw) { for (const auto& record : kw) {
if (all_defaulted(record)) { if (all_defaulted(record)) {
// All-defaulted records imply PVTW in region R is equal to PVTW // All-defaulted records imply table in region R is equal to
// in region R-1. PVTW must not be defaulted in region 1 (i.e., // table in region R-1. Table must not be defaulted in region 1
// when PVTNUM=1). // (i.e., when PVTNUM=1).
if (this->table_.empty()) { if (this->table_.empty()) {
throw OpmInputError { throw OpmInputError {
"First record cannot be defaulted", "First record cannot be defaulted",
@ -1601,89 +1603,34 @@ PvtwTable::PvtwTable(const DeckKeyword& kw)
this->table_.push_back(this->table_.back()); this->table_.push_back(this->table_.back());
} }
else { else {
this->table_.push_back(flat_get<PVTWRecord>(record, mkseq<PVTWRecord::size>{})); this->table_.push_back(flat_get<RecordType>(record, mkseq<RecordType::size>{}));
} }
} }
} }
PvtwTable::PvtwTable(std::initializer_list<PVTWRecord> records) template <typename RecordType>
: table_(records) FlatTableWithCopy<RecordType>::FlatTableWithCopy(std::initializer_list<RecordType> records)
: table_{ records }
{} {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
GravityTable::GravityTable(const DeckKeyword& kw) GravityTable::GravityTable(const DeckKeyword& kw)
{ : FlatTableWithCopy(kw, ParserKeywords::GRAVITY::keywordName)
if (kw.name() != ParserKeywords::GRAVITY::keywordName) { {}
throw std::invalid_argument {
fmt::format("Keyword {} cannot be used to "
"initialise {} table structures", kw.name(),
ParserKeywords::GRAVITY::keywordName)
};
}
this->table_.reserve(kw.size());
for (const auto& record : kw) {
if (all_defaulted(record)) {
// All-defaulted records imply GRAVITY in region R is equal to
// GRAVITY in region R-1. GRAVITY must not be defaulted in
// region 1 (i.e., when PVTNUM=1).
if (this->table_.empty()) {
throw OpmInputError {
"First record cannot be defaulted",
kw.location()
};
}
this->table_.push_back(this->table_.back());
}
else {
this->table_.push_back(flat_get<GRAVITYRecord>(record, mkseq<GRAVITYRecord::size>{}));
}
}
}
GravityTable::GravityTable(std::initializer_list<GRAVITYRecord> records) GravityTable::GravityTable(std::initializer_list<GRAVITYRecord> records)
: table_(records) : FlatTableWithCopy(records)
{} {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
DensityTable::DensityTable(const DeckKeyword& kw) DensityTable::DensityTable(const DeckKeyword& kw)
{ : FlatTableWithCopy(kw, ParserKeywords::DENSITY::keywordName)
if (kw.name() != ParserKeywords::DENSITY::keywordName) { {}
throw std::invalid_argument {
fmt::format("Keyword {} cannot be used to "
"initialise {} table structures", kw.name(),
ParserKeywords::DENSITY::keywordName)
};
}
this->table_.reserve(kw.size());
for (const auto& record : kw) {
if (all_defaulted(record)) {
// All-defaulted records imply DENSITY in region R is equal to
// DENSITY in region R-1. DENSITY must not be defaulted in
// region 1 (i.e., when PVTNUM=1).
if (this->table_.empty()) {
throw OpmInputError {
"First record cannot be defaulted",
kw.location()
};
}
this->table_.push_back(this->table_.back());
}
else {
this->table_.push_back(flat_get<DENSITYRecord>(record, mkseq<DENSITYRecord::size>{}));
}
}
}
DensityTable::DensityTable(std::initializer_list<DENSITYRecord> records) DensityTable::DensityTable(std::initializer_list<DENSITYRecord> records)
: table_(records) : FlatTableWithCopy(records)
{} {}
DensityTable::DensityTable(const GravityTable& gravity) DensityTable::DensityTable(const GravityTable& gravity)
@ -1716,6 +1663,16 @@ DensityTable::DensityTable(const GravityTable& gravity)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
PvtwTable::PvtwTable(const DeckKeyword& kw)
: FlatTableWithCopy(kw, ParserKeywords::PVTW::keywordName)
{}
PvtwTable::PvtwTable(std::initializer_list<PVTWRecord> records)
: FlatTableWithCopy(records)
{}
// ------------------------------------------------------------------------
template< typename T > template< typename T >
FlatTable< T >::FlatTable( const DeckKeyword& kw ) : FlatTable< T >::FlatTable( const DeckKeyword& kw ) :
std::vector< T >( flat_records< T >( kw, mkseq< T::size >{} ) ) std::vector< T >( flat_records< T >( kw, mkseq< T::size >{} ) )