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 <initializer_list>
#include <string_view>
#include <vector>
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 {
static constexpr std::size_t size = 3;
@ -46,33 +86,12 @@ struct GRAVITYRecord {
}
};
class GravityTable
struct GravityTable : public FlatTableWithCopy<GRAVITYRecord>
{
public:
GravityTable() = default;
explicit GravityTable(const DeckKeyword& kw);
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()
{
return GravityTable({{1.0, 2.0, 3.0}});
@ -81,11 +100,8 @@ public:
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer.vector(this->table_);
FlatTableWithCopy::serializeOp(serializer);
}
private:
std::vector<GRAVITYRecord> table_{};
};
struct DENSITYRecord {
@ -110,33 +126,12 @@ struct DENSITYRecord {
}
};
class DensityTable
struct DensityTable : public FlatTableWithCopy<DENSITYRecord>
{
public:
DensityTable() = default;
explicit DensityTable(const DeckKeyword& kw);
explicit DensityTable(std::initializer_list<DENSITYRecord> records);
explicit DensityTable(const GravityTable& gravity);
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_;
}
explicit DensityTable(std::initializer_list<DENSITYRecord> records);
static DensityTable serializeObject()
{
@ -146,11 +141,8 @@ public:
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer.vector(this->table_);
FlatTableWithCopy::serializeOp(serializer);
}
private:
std::vector<DENSITYRecord> table_{};
};
struct DiffCoeffRecord {
@ -227,31 +219,12 @@ struct PVTWRecord {
}
};
class PvtwTable
struct PvtwTable : public FlatTableWithCopy<PVTWRecord>
{
public:
PvtwTable() = default;
explicit PvtwTable(const DeckKeyword& kw);
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()
{
return PvtwTable({{1.0, 2.0, 3.0, 4.0, 5.0}});
@ -260,11 +233,8 @@ public:
template <class Serializer>
void serializeOp(Serializer& serializer)
{
serializer.vector(this->table_);
FlatTableWithCopy::serializeOp(serializer);
}
private:
std::vector<PVTWRecord> table_{};
};
struct ROCKRecord {

View File

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