Implement Defaulted Table Copy for DENSITY and GRAVITY
Use the same targeted strategy as for PVTW.
This commit is contained in:
parent
54ba23d71b
commit
d35abfddb6
@ -24,37 +24,6 @@ struct FlatTable : public std::vector< T > {
|
||||
}
|
||||
};
|
||||
|
||||
struct DENSITYRecord {
|
||||
static constexpr std::size_t size = 3;
|
||||
|
||||
double oil;
|
||||
double water;
|
||||
double gas;
|
||||
|
||||
bool operator==(const DENSITYRecord& data) const {
|
||||
return oil == data.oil &&
|
||||
water == data.water &&
|
||||
gas == data.gas;
|
||||
}
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(oil);
|
||||
serializer(water);
|
||||
serializer(gas);
|
||||
}
|
||||
};
|
||||
|
||||
struct DensityTable : public FlatTable< DENSITYRecord > {
|
||||
using FlatTable< DENSITYRecord >::FlatTable;
|
||||
|
||||
static DensityTable serializeObject()
|
||||
{
|
||||
return DensityTable({{1.0, 2.0, 3.0}});
|
||||
}
|
||||
};
|
||||
|
||||
struct GRAVITYRecord {
|
||||
static constexpr std::size_t size = 3;
|
||||
|
||||
@ -77,13 +46,111 @@ struct GRAVITYRecord {
|
||||
}
|
||||
};
|
||||
|
||||
struct GravityTable : public FlatTable< GRAVITYRecord > {
|
||||
using FlatTable< GRAVITYRecord >::FlatTable;
|
||||
class GravityTable
|
||||
{
|
||||
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}});
|
||||
}
|
||||
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer.vector(this->table_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<GRAVITYRecord> table_{};
|
||||
};
|
||||
|
||||
struct DENSITYRecord {
|
||||
static constexpr std::size_t size = 3;
|
||||
|
||||
double oil;
|
||||
double water;
|
||||
double gas;
|
||||
|
||||
bool operator==(const DENSITYRecord& data) const {
|
||||
return oil == data.oil &&
|
||||
water == data.water &&
|
||||
gas == data.gas;
|
||||
}
|
||||
|
||||
template<class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(oil);
|
||||
serializer(water);
|
||||
serializer(gas);
|
||||
}
|
||||
};
|
||||
|
||||
class DensityTable
|
||||
{
|
||||
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_;
|
||||
}
|
||||
|
||||
static DensityTable serializeObject()
|
||||
{
|
||||
return DensityTable({{1.0, 2.0, 3.0}});
|
||||
}
|
||||
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer.vector(this->table_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<DENSITYRecord> table_{};
|
||||
};
|
||||
|
||||
struct DiffCoeffRecord {
|
||||
|
@ -123,36 +123,6 @@ std::optional<JFunc> make_jfunc(const Deck& deck) {
|
||||
return JFunc(deck);
|
||||
}
|
||||
|
||||
DensityTable make_density_table(const GravityTable& gravity) {
|
||||
auto rho = DensityTable{};
|
||||
rho.reserve(gravity.size());
|
||||
|
||||
constexpr auto default_air_density =
|
||||
1.22 * unit::kilogram / unit::cubic(unit::meter);
|
||||
|
||||
constexpr auto default_water_density =
|
||||
1000.0 * unit::kilogram / unit::cubic(unit::meter);
|
||||
|
||||
// Degrees API defined as
|
||||
//
|
||||
// API = (141.5 / SG) - 131.5
|
||||
//
|
||||
// with SG being the specific gravity of oil relative to pure water.
|
||||
|
||||
std::transform(gravity.begin(), gravity.end(),
|
||||
std::back_inserter(rho),
|
||||
[](const GRAVITYRecord& record)
|
||||
{
|
||||
return DENSITYRecord {
|
||||
(141.5 / (record.oil_api + 131.5)) * default_water_density,
|
||||
record.water_sg * default_water_density,
|
||||
record.gas_sg * default_air_density
|
||||
};
|
||||
});
|
||||
|
||||
return rho;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -197,7 +167,7 @@ DensityTable make_density_table(const GravityTable& gravity) {
|
||||
this->m_densityTable = DensityTable( deck["DENSITY"].back() );
|
||||
|
||||
else if( deck.hasKeyword( "GRAVITY" ) )
|
||||
this->m_densityTable = make_density_table( GravityTable ( deck["GRAVITY"].back() ) );
|
||||
this->m_densityTable = DensityTable( GravityTable ( deck["GRAVITY"].back() ) );
|
||||
|
||||
if( deck.hasKeyword( "DIFFC" ) )
|
||||
this->m_diffCoeffTable = DiffCoeffTable( deck["DIFFC"].back() );
|
||||
|
@ -24,10 +24,13 @@
|
||||
#include <opm/input/eclipse/EclipseState/Tables/ColumnSchema.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableSchema.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/C.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/D.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/G.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/P.hpp>
|
||||
#include <opm/input/eclipse/Parser/ParserKeywords/V.hpp>
|
||||
#include <opm/input/eclipse/Units/Dimension.hpp>
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Tables/FlatTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/EnkrvdTable.hpp>
|
||||
@ -1609,13 +1612,115 @@ PvtwTable::PvtwTable(std::initializer_list<PVTWRecord> 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>{}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GravityTable::GravityTable(std::initializer_list<GRAVITYRecord> records)
|
||||
: table_(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>{}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DensityTable::DensityTable(std::initializer_list<DENSITYRecord> records)
|
||||
: table_(records)
|
||||
{}
|
||||
|
||||
DensityTable::DensityTable(const GravityTable& gravity)
|
||||
{
|
||||
this->table_.reserve(gravity.size());
|
||||
|
||||
constexpr auto default_air_density =
|
||||
1.22 * unit::kilogram / unit::cubic(unit::meter);
|
||||
|
||||
constexpr auto default_water_density =
|
||||
1000.0 * unit::kilogram / unit::cubic(unit::meter);
|
||||
|
||||
// Degrees API defined as
|
||||
//
|
||||
// API = (141.5 / SG) - 131.5
|
||||
//
|
||||
// with SG being the specific gravity of oil relative to pure water.
|
||||
|
||||
std::transform(gravity.begin(), gravity.end(),
|
||||
std::back_inserter(this->table_),
|
||||
[](const GRAVITYRecord& record)
|
||||
{
|
||||
return DENSITYRecord {
|
||||
(141.5 / (record.oil_api + 131.5)) * default_water_density,
|
||||
record.water_sg * default_water_density,
|
||||
record.gas_sg * default_air_density
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template< typename T >
|
||||
FlatTable< T >::FlatTable( const DeckKeyword& kw ) :
|
||||
std::vector< T >( flat_records< T >( kw, mkseq< T::size >{} ) )
|
||||
{}
|
||||
|
||||
template FlatTable< DENSITYRecord >::FlatTable( const DeckKeyword& );
|
||||
template FlatTable< GRAVITYRecord >::FlatTable( const DeckKeyword& );
|
||||
template FlatTable< DiffCoeffRecord >::FlatTable( const DeckKeyword& );
|
||||
template FlatTable< PVCDORecord >::FlatTable( const DeckKeyword& );
|
||||
template FlatTable< ROCKRecord >::FlatTable( const DeckKeyword& );
|
||||
|
@ -1223,6 +1223,70 @@ END
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DensityTable_Tests) {
|
||||
// PVT tables from opm-tests/model5/include/pvt_live_oil_dgas.ecl .
|
||||
const auto deck = Opm::Parser{}.parseString(R"(RUNSPEC
|
||||
OIL
|
||||
WATER
|
||||
TABDIMS
|
||||
1 2 /
|
||||
PROPS
|
||||
DENSITY
|
||||
924.1 1026.0 1.03446 /
|
||||
/ -- Copied from region 1
|
||||
END
|
||||
)");
|
||||
|
||||
const auto tmgr = Opm::TableManager { deck };
|
||||
const auto& dens = tmgr.getDensityTable();
|
||||
BOOST_REQUIRE_EQUAL(dens.size(), std::size_t{2});
|
||||
|
||||
{
|
||||
const auto& t1 = dens[0];
|
||||
BOOST_CHECK_CLOSE(t1.oil, 924.1, 1.0e-8);
|
||||
BOOST_CHECK_CLOSE(t1.gas, 1.03446, 1.0e-8);
|
||||
BOOST_CHECK_CLOSE(t1.water, 1026.0, 1.0e-8);
|
||||
}
|
||||
|
||||
{
|
||||
const auto& t2 = dens[1];
|
||||
BOOST_CHECK_CLOSE(t2.oil, 924.1, 1.0e-8);
|
||||
BOOST_CHECK_CLOSE(t2.gas, 1.03446, 1.0e-8);
|
||||
BOOST_CHECK_CLOSE(t2.water, 1026.0, 1.0e-8);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(GravityTable_Tests) {
|
||||
const auto deck = Opm::Parser{}.parseString(R"(RUNSPEC
|
||||
OIL
|
||||
WATER
|
||||
TABDIMS
|
||||
1 2 /
|
||||
GRAVITY
|
||||
12.34 1.2 1.21 /
|
||||
/ -- Copied from region 1
|
||||
END
|
||||
)");
|
||||
|
||||
const auto tmgr = Opm::TableManager { deck };
|
||||
const auto& dens = tmgr.getDensityTable();
|
||||
BOOST_REQUIRE_EQUAL(dens.size(), std::size_t{2});
|
||||
|
||||
{
|
||||
const auto& t1 = dens[0];
|
||||
BOOST_CHECK_CLOSE( 983.731924360, t1.oil , 1.0e-8 );
|
||||
BOOST_CHECK_CLOSE( 1200.0 , t1.water, 1.0e-8 );
|
||||
BOOST_CHECK_CLOSE( 1.4762 , t1.gas , 1.0e-8 );
|
||||
}
|
||||
|
||||
{
|
||||
const auto& t2 = dens[1];
|
||||
BOOST_CHECK_CLOSE( 983.731924360, t2.oil , 1.0e-8 );
|
||||
BOOST_CHECK_CLOSE( 1200.0 , t2.water, 1.0e-8 );
|
||||
BOOST_CHECK_CLOSE( 1.4762 , t2.gas , 1.0e-8 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests "happy path" for a VFPPROD table, i.e., when everything goes well
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user