adding the following aquifer summary keywords

AAQR, AAQT, AAQP
This commit is contained in:
Kai Bao 2020-04-20 09:56:05 +02:00
parent 0ab50fbc95
commit fd773423b0
14 changed files with 187 additions and 18 deletions

View File

@ -43,7 +43,8 @@ int main(int /* argc */, char** argv) {
Opm::Deck deck = parser.parseFile(deck_file, parse_context, error_guard);
Opm::EclipseState state(deck);
Opm::Schedule schedule(deck, state, parse_context, error_guard, python);
Opm::SummaryConfig summary_config(deck, schedule, state.getTableManager(), parse_context, error_guard);
Opm::SummaryConfig summary_config(deck, schedule, state.getTableManager(), state.aquifer(),
parse_context, error_guard);
if (error_guard) {
error_guard.dump();

View File

@ -70,7 +70,8 @@ inline void loadDeck( const char * deck_file) {
std::cout << "creating SummaryConfig .... "; std::cout.flush();
start = std::chrono::system_clock::now();
Opm::SummaryConfig summary( deck, schedule, state.getTableManager( ), parseContext, errors );
Opm::SummaryConfig summary( deck, schedule, state.getTableManager( ), state.aquifer(),
parseContext, errors );
auto summary_time = std::chrono::system_clock::now() - start;
std::cout << "complete." << std::endl << std::endl;

View File

@ -46,14 +46,31 @@ namespace Opm { namespace data {
struct AquiferData {
int aquiferID; //< One-based ID, range 1..NANAQ
double pressure; //< Aquifer pressure
double fluxRate; //< Aquifer influx rate (liquid aquifer)
// TODO: volume should have a better name, since meaning not clear
double volume; //< Produced liquid volume
double initPressure; //< Aquifer's initial pressure
double datumDepth; //< Aquifer's pressure reference depth
AquiferType type;
std::shared_ptr<FetkovichData> aquFet;
double get(const std::string& key) const
{
if ( key == "AAQR" ) {
return this->fluxRate;
} else if ( key == "AAQT" ) {
return this->volume;
} else if ( key == "AAQP" ) {
return this->pressure;
}
return 0.;
}
};
// TODO: not sure what extension we will need
using Aquifers = std::map<int, AquiferData>;
}} // Opm::data
#endif // OPM_OUTPUT_AQUIFER_HPP

View File

@ -22,6 +22,9 @@
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
// TODO: following the convention here, it should be removed.
#include <opm/output/data/Aquifer.hpp>
#include <map>
#include <memory>
#include <string>
@ -68,7 +71,8 @@ public:
const data::GroupAndNetworkValues& group_and_nwrk_solution,
GlobalProcessParameters single_values,
const RegionParameters& region_values = {},
const BlockValues& block_values = {}) const;
const BlockValues& block_values = {},
const data::Aquifers& aquifers_values = {}) const;
void write() const;

View File

@ -118,6 +118,8 @@ namespace Opm {
const std::vector<AquiferCT::AQUCT_data>& data() const;
bool operator==(const AquiferCT& other) const;
bool hasAquifer(const int aquID) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{

View File

@ -43,6 +43,7 @@ public:
const Aquifetp& fetp() const;
const Aquancon& connections() const;
bool operator==(const AquiferConfig& other);
bool hasAquifer(const int aquID) const;
template<class Serializer>
void serializeOp(Serializer& serializer)

View File

@ -76,6 +76,8 @@ class Aquifetp {
std::vector<Aquifetp::AQUFETP_data>::const_iterator end() const;
bool operator==(const Aquifetp& other) const;
bool hasAquifer(const int aquID) const;
template<class Serializer>
void serializeOp(Serializer& serializer)
{

View File

@ -123,6 +123,7 @@ namespace Opm {
class ParseContext;
class Schedule;
class TableManager;
class AquiferConfig;
class SummaryConfig {
public:
@ -134,6 +135,7 @@ namespace Opm {
SummaryConfig( const Deck&,
const Schedule&,
const TableManager&,
const AquiferConfig&,
const ParseContext&,
ErrorGuard&);
@ -141,12 +143,14 @@ namespace Opm {
SummaryConfig( const Deck&,
const Schedule&,
const TableManager&,
const AquiferConfig&,
const ParseContext&,
T&&);
SummaryConfig( const Deck&,
const Schedule&,
const TableManager&);
const TableManager&,
const AquiferConfig&);
SummaryConfig(const keyword_list& kwds,
const std::set<std::string>& shortKwds,
@ -209,6 +213,7 @@ namespace Opm {
SummaryConfig( const Deck& deck,
const Schedule& schedule,
const TableManager& tables,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
ErrorGuard& errors,
const GridDims& dims);

View File

@ -46,6 +46,7 @@
#include <opm/output/data/Groups.hpp>
#include <opm/output/data/GuideRateValue.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/data/Aquifer.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
@ -1447,6 +1448,12 @@ static const std::unordered_map< std::string, Opm::UnitSystem::measure> block_un
{"BOVIS" , Opm::UnitSystem::measure::viscosity},
};
static const std::unordered_map< std::string, Opm::UnitSystem::measure> aquifer_units = {
{"AAQT", Opm::UnitSystem::measure::liquid_surface_volume},
{"AAQR", Opm::UnitSystem::measure::liquid_surface_rate},
{"AAQP", Opm::UnitSystem::measure::pressure},
};
inline std::vector<Opm::Well> find_wells( const Opm::Schedule& schedule,
const Opm::EclIO::SummaryNode& node,
const int sim_step,
@ -1639,6 +1646,7 @@ namespace Evaluator {
const std::map<std::string, double>& single;
const std::map<std::string, std::vector<double>>& region;
const std::map<std::pair<std::string, int>, double>& block;
const Opm::data::Aquifers& aquifers;
};
class Base
@ -1747,6 +1755,35 @@ namespace Evaluator {
}
};
class AquiferValue: public Base
{
public:
explicit AquiferValue(Opm::EclIO::SummaryNode node,
const Opm::UnitSystem::measure m)
: node_(std::move(node))
, m_ (m)
{}
void update(const std::size_t /* sim_step */,
const double /* stepSize */,
const InputData& input,
const SimulatorResults& simRes,
Opm::SummaryState& st) const override
{
auto xPos = simRes.aquifers.find(this->node_.number);
if (xPos == simRes.aquifers.end()) {
return;
}
const auto& usys = input.es.getUnits();
updateValue(this->node_, usys.from_si(this->m_, xPos->second.get(this->node_.keyword)), st);
}
private:
Opm::EclIO::SummaryNode node_;
Opm::UnitSystem::measure m_;
};
class RegionValue : public Base
{
public:
@ -1983,12 +2020,14 @@ namespace Evaluator {
Descriptor functionRelation();
Descriptor blockValue();
Descriptor aquiferValue();
Descriptor regionValue();
Descriptor globalProcessValue();
Descriptor userDefinedValue();
Descriptor unknownParameter();
bool isBlockValue();
bool isAquiferValue();
bool isRegionValue();
bool isGlobalProcessValue();
bool isFunctionRelation();
@ -2009,6 +2048,9 @@ namespace Evaluator {
if (this->isBlockValue())
return this->blockValue();
if (this->isAquiferValue())
return this->aquiferValue();
if (this->isRegionValue())
return this->regionValue();
@ -2045,6 +2087,18 @@ namespace Evaluator {
return desc;
}
Factory::Descriptor Factory::aquiferValue()
{
auto desc = this->unknownParameter();
desc.unit = this->directUnitString();
desc.evaluator.reset(new AquiferValue {
*this->node_, this->paramUnit_
});
return desc;
}
Factory::Descriptor Factory::regionValue()
{
auto desc = this->unknownParameter();
@ -2105,6 +2159,18 @@ namespace Evaluator {
return true;
}
bool Factory::isAquiferValue()
{
auto pos = aquifer_units.find(this->node_->keyword);
if (pos == aquifer_units.end()) return false;
// if the aquifer does not exist, should we warn?
if ( !this->es_.aquifer().hasAquifer(this->node_->number) ) return false;
this->paramUnit_ = pos->second;
return true;
}
bool Factory::isRegionValue()
{
auto keyword = this->node_->keyword;
@ -2392,6 +2458,7 @@ public:
const GlobalProcessParameters& single_values,
const RegionParameters& region_values,
const BlockValues& block_values,
const data::Aquifers& aquifer_values,
SummaryState& st) const;
void internal_store(const SummaryState& st, const int report_step);
@ -2494,6 +2561,7 @@ eval(const EclipseState& es,
const GlobalProcessParameters& single_values,
const RegionParameters& region_values,
const BlockValues& block_values,
const data::Aquifers& aquifer_values,
Opm::SummaryState& st) const
{
const Evaluator::InputData input {
@ -2501,7 +2569,7 @@ eval(const EclipseState& es,
};
const Evaluator::SimulatorResults simRes {
well_solution, grp_nwrk_solution, single_values, region_values, block_values
well_solution, grp_nwrk_solution, single_values, region_values, block_values, aquifer_values
};
for (auto& evalPtr : this->outputParameters_.getEvaluators()) {
@ -2794,7 +2862,8 @@ void Summary::eval(SummaryState& st,
const data::GroupAndNetworkValues& grp_nwrk_solution,
GlobalProcessParameters single_values,
const RegionParameters& region_values,
const BlockValues& block_values) const
const BlockValues& block_values,
const Opm::data::Aquifers& aquifer_values) const
{
validateElapsedTime(secs_elapsed, es, st);
@ -2816,7 +2885,7 @@ void Summary::eval(SummaryState& st,
this->pImpl_->eval(es, schedule, sim_step, duration,
well_solution, grp_nwrk_solution, single_values,
region_values, block_values, st);
region_values, block_values, aquifer_values, st);
st.update_elapsed(duration);
}

View File

@ -175,4 +175,11 @@ const std::vector<AquiferCT::AQUCT_data>& AquiferCT::data() const {
return this->m_aquct;
}
bool AquiferCT::hasAquifer(const int aquID) const {
const auto it = std::find_if(this->m_aquct.begin(), this->m_aquct.end(),
[&aquID](const auto& aqu){ return aqu.aquiferID == aquID; });
return ( it != this->m_aquct.end() );
}
}

View File

@ -70,4 +70,8 @@ const Aquancon& AquiferConfig::connections() const {
return this->aqconn;
}
bool AquiferConfig::hasAquifer(const int aquID) const {
return aquifetp.hasAquifer(aquID) || aquiferct.hasAquifer(aquID);
}
}

View File

@ -113,4 +113,11 @@ std::vector<Aquifetp::AQUFETP_data>::const_iterator Aquifetp::end() const {
return this->m_aqufetp.end();
}
bool Aquifetp::hasAquifer(const int aquID) const {
const auto it = std::find_if(this->m_aqufetp.begin(), this->m_aqufetp.end(),
[&aquID](const auto& aqu){ return aqu.aquiferID == aquID; });
return ( it != this->m_aqufetp.end() );
}
}

View File

@ -41,6 +41,7 @@
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Tables/TableManager.hpp>
#include <opm/parser/eclipse/EclipseState/AquiferConfig.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
#include <opm/parser/eclipse/EclipseState/Grid/GridDims.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
@ -71,7 +72,8 @@ namespace {
"WVPR", "WVPT", "WWCT", "WWGR", "WWIR", "WWIT", "WWPR",
"WWPT",
// ALL will not expand to these keywords yet
"AAQR", "AAQRG", "AAQT", "AAQTG"
// Analytical aquifer keywords
"AAQR", "AAQRG", "AAQT", "AAQTG", "AAQP"
};
const std::vector<std::string> GMWSET_keywords = {
@ -354,6 +356,33 @@ inline void keywordW( SummaryConfig::keyword_list& list,
for (const auto& wname : well_names)
list.push_back( baseWellParam.namedEntity(wname) );
}
// later check whether parseContext and errors are required
// maybe loc will be needed
inline void keywordAquifer( SummaryConfig::keyword_list& list,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
ErrorGuard& errors,
const DeckKeyword& keyword,
const Schedule& schedule) {
auto param = SummaryConfigNode {
keyword.name(), SummaryConfigNode::Category::Aquifer, keyword.location()
}
.parameterType( parseKeywordType(keyword.name()) )
.isUserDefined( is_udq(keyword.name()) );
if (keyword.size() && keyword.getDataRecord().getDataItem().hasValue(0)) {
for( const int id: keyword.getIntData()) {
list.push_back(param.number(id));
}
} else {
for (const auto& aq : aquiferConfig.ct()) {
list.push_back(param.number(aq.aquiferID));
}
for (const auto& aq : aquiferConfig.fetp()) {
list.push_back(param.number(aq.aquiferID));
}
}
}
inline void keywordW( SummaryConfig::keyword_list& list,
const std::string& keyword,
@ -518,6 +547,18 @@ inline void keywordF( SummaryConfig::keyword_list& list,
list.push_back( std::move(param) );
}
inline void keywordAquifer( SummaryConfig::keyword_list& list,
const std::string& keyword,
KeywordLocation loc) {
auto param = SummaryConfigNode {
keyword, SummaryConfigNode::Category::Aquifer, std::move(loc)
}
.parameterType( parseKeywordType(keyword) )
.isUserDefined( is_udq(keyword) );
list.push_back( std::move(param) );
}
inline void keywordF( SummaryConfig::keyword_list& list,
const DeckKeyword& keyword ) {
if( keyword.name() == "FMWSET" ) return;
@ -879,6 +920,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
const DeckKeyword& keyword,
const Schedule& schedule,
const TableManager& tables,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
ErrorGuard& errors,
const GridDims& dims) {
@ -897,6 +939,7 @@ inline void keywordMISC( SummaryConfig::keyword_list& list,
case Cat::Connection: return keywordC( list, parseContext, errors, keyword, schedule, dims);
case Cat::Segment: return keywordS( list, parseContext, errors, keyword, schedule );
case Cat::Node: return keyword_node( list, node_names, parseContext, errors, keyword );
case Cat::Aquifer: return keywordAquifer(list, aquiferConfig, parseContext, errors, keyword, schedule);
case Cat::Miscellaneous: return keywordMISC( list, keyword );
default:
@ -919,12 +962,12 @@ inline void handleKW( SummaryConfig::keyword_list& list,
if (is_udq(keyword))
throw std::logic_error("UDQ keywords not handleded when expanding alias list");
if (is_aquifer(keyword)) {
/* if (is_aquifer(keyword)) {
std::string msg = "Summary output keyword {keyword} of type AQUIFER is not supported\n"
"In {{file}} line {{line}}";
parseContext.handleError(ParseContext::SUMMARY_UNHANDLED_KEYWORD, msg, location, errors);
return;
}
} */
using Cat = SummaryConfigNode::Category;
const auto cat = parseKeywordCategory( keyword );
@ -933,6 +976,7 @@ inline void handleKW( SummaryConfig::keyword_list& list,
case Cat::Well: return keywordW( list, keyword, location, schedule );
case Cat::Group: return keywordG( list, keyword, location, schedule );
case Cat::Field: return keywordF( list, keyword, location );
case Cat::Aquifer: return keywordAquifer( list, keyword, location );
case Cat::Miscellaneous: return keywordMISC( list, keyword, location);
default:
@ -956,6 +1000,7 @@ SummaryConfigNode::Category parseKeywordCategory(const std::string& keyword) {
if (is_special(keyword)) { return Cat::Miscellaneous; }
switch (keyword[0]) {
// TODO: maybe A and N?
case 'A': return Cat::Aquifer;
case 'W': return Cat::Well;
case 'G': return distinguish_group_from_node(keyword);
@ -1136,6 +1181,7 @@ bool operator<(const SummaryConfigNode& lhs, const SummaryConfigNode& rhs)
SummaryConfig::SummaryConfig( const Deck& deck,
const Schedule& schedule,
const TableManager& tables,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
ErrorGuard& errors,
const GridDims& dims) {
@ -1148,7 +1194,7 @@ SummaryConfig::SummaryConfig( const Deck& deck,
if (is_processing_instruction(kw.name())) {
handleProcessingInstruction(kw.name());
} else {
handleKW(this->m_keywords, node_names, kw, schedule, tables, parseContext, errors, dims);
handleKW(this->m_keywords, node_names, kw, schedule, tables, aquiferConfig, parseContext, errors, dims);
}
}
@ -1182,9 +1228,10 @@ SummaryConfig::SummaryConfig( const Deck& deck,
SummaryConfig::SummaryConfig( const Deck& deck,
const Schedule& schedule,
const TableManager& tables,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
ErrorGuard& errors) :
SummaryConfig( deck , schedule, tables, parseContext, errors, GridDims( deck ))
SummaryConfig( deck , schedule, tables, aquiferConfig, parseContext, errors, GridDims( deck ))
{ }
@ -1192,16 +1239,18 @@ template <typename T>
SummaryConfig::SummaryConfig( const Deck& deck,
const Schedule& schedule,
const TableManager& tables,
const AquiferConfig& aquiferConfig,
const ParseContext& parseContext,
T&& errors) :
SummaryConfig(deck, schedule, tables, parseContext, errors)
SummaryConfig(deck, schedule, tables, aquiferConfig, parseContext, errors)
{}
SummaryConfig::SummaryConfig( const Deck& deck,
const Schedule& schedule,
const TableManager& tables) :
SummaryConfig(deck, schedule, tables, ParseContext(), ErrorGuard())
const TableManager& tables,
const AquiferConfig& aquiferConfig) :
SummaryConfig(deck, schedule, tables, aquiferConfig, ParseContext(), ErrorGuard())
{}

View File

@ -156,7 +156,7 @@ static SummaryConfig createSummary( std::string input , const ParseContext& pars
auto python = std::make_shared<Python>();
EclipseState state( deck );
Schedule schedule(deck, state, parseContext, errors, python);
return SummaryConfig( deck, schedule, state.getTableManager( ), parseContext, errors );
return SummaryConfig(deck, schedule, state.getTableManager(), <#initializer#>, parseContext, errors);
}
BOOST_AUTO_TEST_CASE(wells_all) {
@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(wells_missingI) {
parseContext.update(ParseContext::SUMMARY_UNKNOWN_WELL, InputError::THROW_EXCEPTION);
EclipseState state( deck );
Schedule schedule(deck, state, parseContext, errors, python );
BOOST_CHECK_NO_THROW( SummaryConfig( deck, schedule, state.getTableManager( ), parseContext, errors ));
BOOST_CHECK_NO_THROW(SummaryConfig(deck, schedule, state.getTableManager(), <#initializer#>, parseContext, errors));
}
@ -1077,7 +1077,7 @@ END
const auto parseContext = ParseContext{};
const auto state = EclipseState (deck);
const auto schedule = Schedule (deck, state, parseContext, errors, std::make_shared<const Python>());
const auto smry = SummaryConfig(deck, schedule, state.getTableManager(), parseContext, errors );
const auto smry = SummaryConfig(deck, schedule, state.getTableManager(), <#initializer#>, parseContext, errors);
BOOST_CHECK_MESSAGE(deck.hasKeyword("GPR"), R"(Deck must have "GPR" keyword)");
BOOST_CHECK_MESSAGE(smry.hasKeyword("GPR"), R"(SummaryConfig must have "GPR" keyword)");