Merge pull request #2468 from osae/tracerWell

Support for tracer summary curves, WT(I/P)(R/T/C).
This commit is contained in:
Bård Skaflestad
2021-06-25 17:47:56 +02:00
committed by GitHub
10 changed files with 318 additions and 54 deletions

View File

@@ -69,7 +69,8 @@ namespace Opm {
well_potential_oil = (1 << 15),
well_potential_gas = (1 << 16),
brine = (1 << 17),
alq = (1 << 18)
alq = (1 << 18),
tracer = (1 << 19)
};
using enum_size = std::underlying_type< opt >::type;
@@ -83,10 +84,12 @@ namespace Opm {
/// Read the value indicated by m. Returns a default value if
/// the requested value is unset.
inline double get( opt m, double default_value ) const;
inline double get( opt m, double default_value , const std::string& tracer_name ) const;
/// Set the value specified by m. Throws an exception if multiple
/// values are requested. Returns a self-reference to support
/// chaining.
inline Rates& set( opt m, double value );
inline Rates& set( opt m, double value , const std::string& tracer_name );
/// Returns true if any of the rates oil, gas, water is nonzero
inline bool flowing() const;
@@ -101,7 +104,9 @@ namespace Opm {
inline void init_json(Json::JsonObject& json_data) const;
private:
double& get_ref( opt );
double& get_ref( opt, const std::string& tracer_name );
const double& get_ref( opt ) const;
const double& get_ref( opt, const std::string& tracer_name ) const;
opt mask = static_cast< opt >( 0 );
@@ -124,6 +129,7 @@ namespace Opm {
double well_potential_gas = 0.0;
double brine = 0.0;
double alq = 0.0;
std::map<std::string, double> tracer;
};
struct Connection {
@@ -266,17 +272,17 @@ namespace Opm {
};
struct Well {
Rates rates;
double bhp;
double thp;
double temperature;
int control;
Rates rates{};
double bhp{0.0};
double thp{0.0};
double temperature{0.0};
int control{0};
::Opm::Well::Status dynamicStatus { Opm::Well::Status::OPEN };
std::vector< Connection > connections;
std::unordered_map<std::size_t, Segment> segments;
CurrentControl current_control;
std::vector< Connection > connections{};
std::unordered_map<std::size_t, Segment> segments{};
CurrentControl current_control{};
GuideRateValue guide_rates{};
inline bool flowing() const noexcept;
@@ -336,6 +342,12 @@ namespace Opm {
return well->second.rates.get( m, 0.0 );
}
double get(const std::string& well_name , Rates::opt m, const std::string& tracer_name) const {
const auto& well = this->find( well_name );
if( well == this->end() ) return 0.0;
return well->second.rates.get( m, 0.0, tracer_name);
}
double get(const std::string& well_name , Connection::global_index connection_grid_index, Rates::opt m) const {
const auto& witr = this->find( well_name );
@@ -417,8 +429,29 @@ namespace Opm {
return this->get_ref( m );
}
inline double Rates::get( opt m, double default_value, const std::string& tracer_name) const {
if( !this->has( m ) ) return default_value;
if( m == opt::tracer && this->tracer.find(tracer_name) == this->tracer.end()) return default_value;
return this->get_ref( m, tracer_name);
}
inline Rates& Rates::set( opt m, double value ) {
this->get_ref( m ) = value;
/* mask |= m */
this->mask = static_cast< opt >(
static_cast< enum_size >( this->mask ) |
static_cast< enum_size >( m )
);
return *this;
}
inline Rates& Rates::set( opt m, double value , const std::string& tracer_name ) {
this->get_ref( m , tracer_name) = value;
/* mask |= m */
this->mask = static_cast< opt >(
static_cast< enum_size >( this->mask ) |
@@ -449,7 +482,8 @@ namespace Opm {
well_potential_oil == rate.well_potential_oil &&
well_potential_gas == rate.well_potential_gas &&
brine == rate.brine &&
alq == rate.alq;
alq == rate.alq &&
tracer == rate.tracer;
}
@@ -483,6 +517,8 @@ namespace Opm {
case opt::well_potential_gas: return this->well_potential_gas;
case opt::brine: return this->brine;
case opt::alq: return this->alq;
case opt::tracer: /* Should _not_ be called with tracer argument */
break;
}
throw std::invalid_argument(
@@ -492,12 +528,24 @@ namespace Opm {
}
inline const double& Rates::get_ref( opt m, const std::string& tracer_name ) const {
if (m != opt::tracer)
throw std::logic_error("Logic error - should be called with tracer argument");
return this->tracer.at(tracer_name);
}
inline double& Rates::get_ref( opt m ) {
return const_cast< double& >(
static_cast< const Rates* >( this )->get_ref( m )
);
}
inline double& Rates::get_ref( opt m, const std::string& tracer_name ) {
if (m == opt::tracer) this->tracer.emplace(tracer_name, 0.0);
return this->tracer.at(tracer_name);
}
void Rates::init_json(Json::JsonObject& json_data) const {
if (this->has(opt::wat))
@@ -511,7 +559,6 @@ namespace Opm {
}
bool inline Rates::flowing() const {
return ((this->wat != 0) ||
(this->oil != 0) ||
@@ -544,6 +591,13 @@ namespace Opm {
buffer.write(this->well_potential_gas);
buffer.write(this->brine);
buffer.write(this->alq);
//tracer:
unsigned int size = this->tracer.size();
buffer.write(size);
for (const auto& [name, rate] : this->tracer) {
buffer.write(name);
buffer.write(rate);
}
}
template <class MessageBufferType>
@@ -647,6 +701,16 @@ namespace Opm {
buffer.read(this->well_potential_gas);
buffer.read(this->brine);
buffer.read(this->alq);
//tracer:
unsigned int size;
buffer.read(size);
for (size_t i = 0; i < size; ++i) {
std::string tracer_name;
buffer.read(tracer_name);
double tracer_rate;
buffer.read(tracer_rate);
this->tracer.emplace(tracer_name, tracer_rate);
}
}
template <class MessageBufferType>

View File

@@ -33,27 +33,46 @@ public:
struct TracerEntry {
std::string name;
Phase phase = Phase::OIL;
std::vector<double> concentration;
TracerVdTable tvdpf;
std::vector<double> free_concentration;
std::vector<double> solution_concentration;
TracerVdTable free_tvdp;
TracerVdTable solution_tvdp;
TracerEntry() = default;
TracerEntry(const std::string& name_, Phase phase_, std::vector<double> concentration_)
TracerEntry(const std::string& name_, Phase phase_, std::vector<double> free_concentration_)
: name(name_)
, phase(phase_)
, concentration(std::move(concentration_))
, free_concentration(std::move(free_concentration_))
{}
TracerEntry(const std::string& name_, Phase phase_, TracerVdTable tvdpf_)
TracerEntry(const std::string& name_, Phase phase_, std::vector<double> free_concentration_,
std::vector<double> solution_concentration_)
: name(name_)
, phase(phase_)
, tvdpf(std::move(tvdpf_))
, free_concentration(std::move(free_concentration_))
, solution_concentration(std::move(solution_concentration_))
{}
TracerEntry(const std::string& name_, Phase phase_, TracerVdTable free_tvdp_)
: name(name_)
, phase(phase_)
, free_tvdp(std::move(free_tvdp_))
{}
TracerEntry(const std::string& name_, Phase phase_, TracerVdTable free_tvdp_, TracerVdTable solution_tvdp_)
: name(name_)
, phase(phase_)
, free_tvdp(std::move(free_tvdp_))
, solution_tvdp(std::move(solution_tvdp_))
{}
bool operator==(const TracerEntry& data) const {
return this->name == data.name &&
this->phase == data.phase &&
this->concentration == data.concentration &&
this->tvdpf == data.tvdpf;
this->free_concentration == data.free_concentration &&
this->solution_concentration == data.solution_concentration &&
this->free_tvdp == data.free_tvdp &&
this->solution_tvdp == data.solution_tvdp;
}
template<class Serializer>
@@ -61,8 +80,10 @@ public:
{
serializer(name);
serializer(phase);
serializer(concentration);
tvdpf.serializeOp(serializer);
serializer(free_concentration);
serializer(solution_concentration);
free_tvdp.serializeOp(serializer);
solution_tvdp.serializeOp(serializer);
}
};

View File

@@ -447,6 +447,7 @@ struct fn_args
{
const std::vector<const Opm::Well*>& schedule_wells;
const std::string group_name;
const std::string keyword_name;
double duration;
const int sim_step;
int num;
@@ -605,6 +606,37 @@ inline quantity rate( const fn_args& args ) {
return { sum, rate_unit< phase >() };
}
template< rt tracer, rt phase, bool injection = true >
inline quantity ratetracer( const fn_args& args ) {
double sum = 0.0;
std::string tracer_name = args.keyword_name.substr(4);
for (const auto* sched_well : args.schedule_wells) {
const auto& name = sched_well->name();
auto xwPos = args.wells.find(name);
if ((xwPos == args.wells.end()) ||
(xwPos->second.dynamicStatus == Opm::Well::Status::SHUT))
{
continue;
}
const double eff_fac = efac(args.eff_factors, name);
const auto v = xwPos->second.rates.get(tracer, 0.0, tracer_name) * eff_fac;
if ((v > 0.0) == injection) {
sum += v;
}
}
if (! injection) {
sum *= -1.0;
}
return { sum, rate_unit< phase >() };
}
template< rt phase, bool injection = true >
inline quantity ratel( const fn_args& args ) {
const auto unit = ((phase == rt::polymer) || (phase == rt::brine))
@@ -1443,6 +1475,13 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WNIR", rate< rt::solvent, injector > },
{ "WCIR", rate< rt::polymer, injector > },
{ "WSIR", rate< rt::brine, injector > },
// Allow phase specific interpretation of tracer related summary keywords
{ "WTIR#W", ratetracer< rt::tracer, rt::wat, injector > }, // #W: Water tracers
{ "WTIR#O", ratetracer< rt::tracer, rt::oil, injector > }, // #O: Oil tracers
{ "WTIR#G", ratetracer< rt::tracer, rt::gas, injector > }, // #G: Gas tracers
{ "WTIC#W", div( ratetracer< rt::tracer, rt::wat, injector >, rate< rt::wat, injector >) },
{ "WTIC#O", div( ratetracer< rt::tracer, rt::oil, injector >, rate< rt::oil, injector >) },
{ "WTIC#G", div( ratetracer< rt::tracer, rt::gas, injector >, rate< rt::gas, injector >) },
{ "WVIR", sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
rate< rt::reservoir_gas, injector > ) },
{ "WGIGR", well_guiderate<injector, Opm::data::GuideRateValue::Item::Gas> },
@@ -1456,6 +1495,9 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WNIT", mul( rate< rt::solvent, injector >, duration ) },
{ "WCIT", mul( rate< rt::polymer, injector >, duration ) },
{ "WSIT", mul( rate< rt::brine, injector >, duration ) },
{ "WTIT#W", mul( ratetracer< rt::tracer, rt::wat, injector >, duration ) },
{ "WTIT#O", mul( ratetracer< rt::tracer, rt::oil, injector >, duration ) },
{ "WTIT#G", mul( ratetracer< rt::tracer, rt::gas, injector >, duration ) },
{ "WVIT", mul( sum( sum( rate< rt::reservoir_water, injector >, rate< rt::reservoir_oil, injector > ),
rate< rt::reservoir_gas, injector > ), duration ) },
@@ -1483,6 +1525,12 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WNPR", rate< rt::solvent, producer > },
{ "WCPR", rate< rt::polymer, producer > },
{ "WSPR", rate< rt::brine, producer > },
{ "WTPR#W", ratetracer< rt::tracer, rt::wat, producer > },
{ "WTPR#O", ratetracer< rt::tracer, rt::oil, producer > },
{ "WTPR#G", ratetracer< rt::tracer, rt::gas, producer > },
{ "WTPC#W", div( ratetracer< rt::tracer, rt::wat, producer >, rate< rt::wat, producer >) },
{ "WTPC#O", div( ratetracer< rt::tracer, rt::oil, producer >, rate< rt::oil, producer >) },
{ "WTPC#G", div( ratetracer< rt::tracer, rt::gas, producer >, rate< rt::gas, producer >) },
{ "WCPC", div( rate< rt::polymer, producer >, rate< rt::wat, producer >) },
{ "WSPC", div( rate< rt::brine, producer >, rate< rt::wat, producer >) },
@@ -1508,6 +1556,9 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "WNPT", mul( rate< rt::solvent, producer >, duration ) },
{ "WCPT", mul( rate< rt::polymer, producer >, duration ) },
{ "WSPT", mul( rate< rt::brine, producer >, duration ) },
{ "WTPT#W", mul( ratetracer< rt::tracer, rt::wat, producer >, duration ) },
{ "WTPT#O", mul( ratetracer< rt::tracer, rt::oil, producer >, duration ) },
{ "WTPT#G", mul( ratetracer< rt::tracer, rt::gas, producer >, duration ) },
{ "WLPT", mul( sum( rate< rt::wat, producer >, rate< rt::oil, producer > ),
duration ) },
{ "WGPTS", mul( rate< rt::dissolved_gas, producer >, duration )},
@@ -1754,6 +1805,12 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FSPR", rate< rt::brine, producer > },
{ "FCPC", div( rate< rt::polymer, producer >, rate< rt::wat, producer >) },
{ "FSPC", div( rate< rt::brine, producer >, rate< rt::wat, producer >) },
{ "FTPR#W", ratetracer< rt::tracer, rt::wat, producer > },
{ "FTPR#O", ratetracer< rt::tracer, rt::oil, producer > },
{ "FTPR#G", ratetracer< rt::tracer, rt::gas, producer > },
{ "FTPC#W", div( ratetracer< rt::tracer, rt::wat, producer >, rate< rt::wat, producer >) },
{ "FTPC#O", div( ratetracer< rt::tracer, rt::oil, producer >, rate< rt::oil, producer >) },
{ "FTPC#G", div( ratetracer< rt::tracer, rt::gas, producer >, rate< rt::gas, producer >) },
{ "FVPR", sum( sum( rate< rt::reservoir_water, producer>, rate< rt::reservoir_oil, producer >),
rate< rt::reservoir_gas, producer>)},
{ "FGPRS", rate< rt::dissolved_gas, producer > },
@@ -1770,6 +1827,9 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FNPT", mul( rate< rt::solvent, producer >, duration ) },
{ "FCPT", mul( rate< rt::polymer, producer >, duration ) },
{ "FSPT", mul( rate< rt::brine, producer >, duration ) },
{ "FTPT#W", mul( ratetracer< rt::tracer, rt::wat, producer >, duration ) },
{ "FTPT#O", mul( ratetracer< rt::tracer, rt::oil, producer >, duration ) },
{ "FTPT#G", mul( ratetracer< rt::tracer, rt::gas, producer >, duration ) },
{ "FLPT", mul( sum( rate< rt::wat, producer >, rate< rt::oil, producer > ),
duration ) },
{ "FVPT", mul(sum (sum( rate< rt::reservoir_water, producer>, rate< rt::reservoir_oil, producer >),
@@ -1788,9 +1848,13 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FTIRHEA", rate< rt::energy, injector > },
{ "FNIR", rate< rt::solvent, injector > },
{ "FCIR", rate< rt::polymer, injector > },
{ "FCPR", rate< rt::polymer, producer > },
{ "FSIR", rate< rt::brine, injector > },
{ "FSPR", rate< rt::brine, producer > },
{ "FTIR#W", ratetracer< rt::tracer, rt::wat, injector > },
{ "FTIR#O", ratetracer< rt::tracer, rt::oil, injector > },
{ "FTIR#G", ratetracer< rt::tracer, rt::gas, injector > },
{ "FTIC#W", div( ratetracer< rt::tracer, rt::wat, injector >, rate< rt::wat, injector >) },
{ "FTIC#O", div( ratetracer< rt::tracer, rt::oil, injector >, rate< rt::oil, injector >) },
{ "FTIC#G", div( ratetracer< rt::tracer, rt::gas, injector >, rate< rt::gas, injector >) },
{ "FVIR", sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
rate< rt::reservoir_gas, injector>)},
@@ -1802,9 +1866,10 @@ static const std::unordered_map< std::string, ofun > funs = {
{ "FTITHEA", mul( rate< rt::energy, injector >, duration ) },
{ "FNIT", mul( rate< rt::solvent, injector >, duration ) },
{ "FCIT", mul( rate< rt::polymer, injector >, duration ) },
{ "FCPT", mul( rate< rt::polymer, producer >, duration ) },
{ "FSIT", mul( rate< rt::brine, injector >, duration ) },
{ "FSPT", mul( rate< rt::brine, producer >, duration ) },
{ "FTIT#W", mul( ratetracer< rt::tracer, rt::wat, injector >, duration ) },
{ "FTIT#O", mul( ratetracer< rt::tracer, rt::oil, injector >, duration ) },
{ "FTIT#G", mul( ratetracer< rt::tracer, rt::gas, injector >, duration ) },
{ "FLIT", mul( sum( rate< rt::wat, injector >, rate< rt::oil, injector > ),
duration ) },
{ "FVIT", mul( sum( sum( rate< rt::reservoir_water, injector>, rate< rt::reservoir_oil, injector >),
@@ -2301,7 +2366,7 @@ namespace Evaluator {
efac.setFactors(this->node_, input.sched, wells, sim_step);
const fn_args args {
wells, this->group_name(), stepSize, static_cast<int>(sim_step),
wells, this->group_name(), this->node_.keyword, stepSize, static_cast<int>(sim_step),
std::max(0, this->node_.number),
this->node_.fip_region,
st, simRes.wellSol, simRes.grpNwrkSol, input.reg, input.grid,
@@ -2329,6 +2394,7 @@ namespace Evaluator {
return need_grp_name
? this->node_.wgname : std::string{""};
}
};
class BlockValue : public Base
@@ -2834,6 +2900,30 @@ namespace Evaluator {
return true;
}
if (keyword.length() > 4 ) {
std::string tracer_tag = keyword.substr(0, 4);
std::string tracer_name = keyword.substr(4);
const auto& tracers = es_.tracer();
for (const auto& tracer : tracers) {
if (tracer.name == tracer_name) {
if (tracer.phase == Opm::Phase::WATER)
tracer_tag += "#W";
else if (tracer.phase == Opm::Phase::OIL)
tracer_tag += "#O";
else if (tracer.phase == Opm::Phase::GAS)
tracer_tag += "#G";
pos = funs.find(tracer_tag);
if (pos != funs.end()) {
this->paramFunction_ = pos->second;
return true;
}
break;
}
}
}
return false;
}
@@ -2847,7 +2937,7 @@ namespace Evaluator {
const auto reg = Opm::out::RegionCache{};
const fn_args args {
{}, "", 0.0, 0, std::max(0, this->node_->number),
{}, "", this->node_->keyword, 0.0, 0, std::max(0, this->node_->number),
this->node_->fip_region,
this->st_, {}, {}, reg, this->grid_,
{}, {}, {}, Opm::UnitSystem(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC)

View File

@@ -34,7 +34,7 @@ namespace {
static const std::vector<std::string> totals = {"OPT" , "GPT" , "WPT" , "GIT", "WIT", "OPTF" , "OPTS" , "OIT" , "OVPT" , "OVIT" , "MWT" ,
"WVPT" , "WVIT" , "GMT" , "GPTF" , "SGT" , "GST" , "FGT" , "GCT" , "GIMT" ,
"WGPT" , "WGIT" , "EGT" , "EXGT" , "GVPT" , "GVIT" , "LPT" , "VPT" , "VIT" , "NPT" , "NIT",
"CPT", "CIT", "SPT", "SIT", "EPT", "EIT", "TPTHEA", "TITHEA"};
"TPT", "TIT", "CPT", "CIT", "SPT", "SIT", "EPT", "EIT", "TPTHEA", "TITHEA"};
auto sep_pos = key.find(':');

View File

@@ -206,13 +206,13 @@ struct SummaryConfigContext {
bool is_rate(const std::string& keyword) {
static const keyword_set ratekw {
"OPR", "GPR", "WPR", "GLIR", "LPR", "NPR", "VPR",
"OPR", "GPR", "WPR", "GLIR", "LPR", "NPR", "CPR", "VPR", "TPR", "TPC",
"OPGR", "GPGR", "WPGR", "VPGR",
"OPRH", "GPRH", "WPRH", "LPRH",
"OVPR", "GVPR", "WVPR",
"OPRS", "GPRS", "OPRF", "GPRF",
"OIR", "GIR", "WIR", "LIR", "NIR", "VIR",
"OIR", "GIR", "WIR", "LIR", "NIR", "CIR", "VIR", "TIR", "TIC"
"OIGR", "GIGR", "WIGR",
"OIRH", "GIRH", "WIRH",
"OVIR", "GVIR", "WVIR",
@@ -222,7 +222,7 @@ struct SummaryConfigContext {
"AQR", "AQRG", "NQR",
};
return is_in_set(ratekw, keyword.substr(1));
return is_in_set(ratekw, keyword.substr(1)) || (keyword.length() > 4 && is_in_set({"TPR","TPC","TIR","TIC"}, keyword.substr(1,3)));;
}
bool is_ratio(const std::string& keyword) {
@@ -236,18 +236,18 @@ struct SummaryConfigContext {
bool is_total(const std::string& keyword) {
static const keyword_set totalkw {
"OPT", "GPT", "WPT", "LPT", "NPT",
"VPT", "OVPT", "GVPT", "WVPT",
"OPT", "GPT", "WPT", "LPT", "NPT", "CPT",
"VPT", "TPT", "OVPT", "GVPT", "WVPT",
"WPTH", "OPTH", "GPTH", "LPTH",
"GPTS", "OPTS", "GPTF", "OPTF",
"WIT", "OIT", "GIT", "LIT", "NIT", "CIT", "VIT",
"WIT", "OIT", "GIT", "LIT", "NIT", "CIT", "VIT", "TIT",
"WITH", "OITH", "GITH", "WVIT", "OVIT", "GVIT",
"AQT", "AQTG", "NQT",
};
return is_in_set(totalkw, keyword.substr(1));
return is_in_set(totalkw, keyword.substr(1)) || (keyword.length() > 4 && is_in_set({"TPT","TIT"}, keyword.substr(1,3)));
}
bool is_count(const std::string& keyword) {

View File

@@ -56,22 +56,39 @@ TracerConfig::TracerConfig(const UnitSystem& unit_system, const Deck& deck)
for (const auto& record : keyword) {
const auto& name = record.getItem<TR::NAME>().get<std::string>(0);
Phase phase = phase_from_string(record.getItem<TR::FLUID>().get<std::string>(0));
double inv_volume;
if (phase == Phase::GAS)
inv_volume = unit_system.getDimension(UnitSystem::measure::gas_surface_volume).getSIScaling();
else
inv_volume = unit_system.getDimension(UnitSystem::measure::liquid_surface_volume).getSIScaling();
double inv_volume = 1.0; // TODO: Proper scaling of c input must also take into account item 3 from kw TRACER.
// For now we assume this to be defaulted, leading to unit scaling (vol/vol).
if (!record.getItem<TR::UNIT>().defaultApplied(0))
throw std::runtime_error("Non-default unit not supported, tracer " + name);
//if (phase == Phase::GAS)
// inv_volume = unit_system.getDimension(UnitSystem::measure::gas_surface_volume).getSIScaling();
//else
// inv_volume = unit_system.getDimension(UnitSystem::measure::liquid_surface_volume).getSIScaling();
unit_system.getDimension(UnitSystem::measure::liquid_surface_volume); //hush unused-warning ...
std::string tracer_field = "TBLKF" + name;
if (deck.hasKeyword(tracer_field)) {
const auto& tracer_keyword = deck.getKeyword(tracer_field);
auto concentration = tracer_keyword.getRecord(0).getItem(0).getData<double>();
auto free_concentration = tracer_keyword.getRecord(0).getItem(0).getData<double>();
logger(tracer_keyword.location().format("Loading tracer concentration from {keyword} in {file} line {line}"));
for (auto& c : concentration)
for (auto& c : free_concentration)
c *= inv_volume;
this->tracers.emplace_back(name, phase, std::move(concentration)) ;
std::string tracer_field_solution = "TBLKS" + name;
if (deck.hasKeyword(tracer_field_solution)) {
const auto& tracer_keyword_solution = deck.getKeyword(tracer_field_solution);
auto solution_concentration = tracer_keyword_solution.getRecord(0).getItem(0).getData<double>();
logger(tracer_keyword_solution.location().format("Loading tracer concentration from {keyword} in {file} line {line}"));
for (auto& c : solution_concentration)
c *= inv_volume;
this->tracers.emplace_back(name, phase, std::move(free_concentration), std::move(solution_concentration)) ;
continue;
}
this->tracers.emplace_back(name, phase, std::move(free_concentration)) ;
continue;
}
@@ -80,6 +97,18 @@ TracerConfig::TracerConfig(const UnitSystem& unit_system, const Deck& deck)
const auto& tracer_keyword = deck.getKeyword(tracer_table);
const auto& deck_item = tracer_keyword.getRecord(0).getItem(0);
logger(tracer_keyword.location().format("Loading tracer concentration from {keyword} in {file} line {line}"));
std::string tracer_table_solution = "TVDPS" + name;
if (deck.hasKeyword(tracer_table_solution)) {
const auto& tracer_keyword_solution = deck.getKeyword(tracer_table_solution);
const auto& deck_item_solution = tracer_keyword_solution.getRecord(0).getItem(0);
logger(tracer_keyword_solution.location().format("Loading tracer concentration from {keyword} in {file} line {line}"));
this->tracers.emplace_back(name, phase, TracerVdTable(deck_item, inv_volume),
TracerVdTable(deck_item_solution, inv_volume)) ;
continue;
}
this->tracers.emplace_back(name, phase, TracerVdTable(deck_item, inv_volume));
continue;
}

View File

@@ -275,6 +275,17 @@ BOOST_AUTO_TEST_CASE(fields) {
names.begin(), names.end() );
}
BOOST_AUTO_TEST_CASE(tracer) {
const auto input = "FTIRSEA\n WTICSEA\n'W_1'/\n WTPRSEA\n'W_3' 'WX2'/\n";
const auto summary = createSummary( input );
const auto keywords = { "FTIRSEA", "WTICSEA", "WTPRSEA", "WTPRSEA" };
const auto names = sorted_keywords( summary );
BOOST_CHECK_EQUAL_COLLECTIONS(
keywords.begin(), keywords.end(),
names.begin(), names.end() );
}
BOOST_AUTO_TEST_CASE(field_oil_efficiency) {
const auto input = "FOE\n";
const auto summary = createSummary( input );

View File

@@ -80,12 +80,12 @@ BOOST_AUTO_TEST_CASE(TracerConfigTest) {
auto it = tc.begin();
BOOST_CHECK_EQUAL(it->name, "SEA");
BOOST_CHECK_EQUAL(it->phase, Phase::WATER);
BOOST_CHECK(it->concentration.empty());
BOOST_CHECK_EQUAL(it->tvdpf.numColumns(), 2U);
BOOST_CHECK(it->free_concentration.empty());
BOOST_CHECK_EQUAL(it->free_tvdp.numColumns(), 2U);
++it;
BOOST_CHECK_EQUAL(it->name, "OCE");
BOOST_CHECK_EQUAL(it->phase, Phase::GAS);
BOOST_CHECK_EQUAL(it->concentration.size(), 3U);
BOOST_CHECK_EQUAL(it->tvdpf.numColumns(), 0U);
BOOST_CHECK_EQUAL(it->free_concentration.size(), 3U);
BOOST_CHECK_EQUAL(it->free_tvdp.numColumns(), 0U);
}

View File

@@ -26,6 +26,9 @@ WELLDIMS
6 2 3 2
/
TRACERS
1* 1 /
OIL
GAS
WATER
@@ -60,6 +63,11 @@ PERMY
PERMZ
1000*10 /
PROPS
TRACER
'SEA' 'WAT'/
/
REGIONS
FIPNUM
@@ -75,6 +83,10 @@ FIPNUM
50*10 50*20
/
SOLUTION
TBLKFSEA
1000*0.1/
SUMMARY
DATE
PERFORMA
@@ -99,7 +111,7 @@ FOPRF
FOPRS
FCPR
FSPR
--FTPRSEA
FTPRSEA
-- Injection Rates
FVIR
FWIR
@@ -129,6 +141,7 @@ FOPTS
FVPRT
FCPT
FSPT
FTPTSEA
-- Injection Cummulatives
FVIT
FWIT
@@ -480,6 +493,10 @@ GPR
-- Production Rates
WWPR
/
WTPRSEA
W_1 W_2 /
WTPCSEA
W_1 W_2 /
WWPRH
/
WOPR
@@ -561,6 +578,9 @@ WSIT
WNIT
W_3
/
-- Tracers
WTIRSEA
/
-- Production Cummulatives
WWPT
@@ -585,12 +605,9 @@ WOPTF
/
WOPTS
/
-- Tracers
--WTPRSEA
--/
--WTPTSEA
--/
WTPTSEA
/
-- Injection Cummulatives
WWIT
W_3
@@ -608,6 +625,11 @@ WGLR
/
WGLRH
/
-- Tracers
WTITSEA
/
WTICSEA
/
-- Performance

View File

@@ -150,6 +150,7 @@ data::Wells result_wells(const bool w3_injector = true)
rates1.set( rt::well_potential_gas, -10.15 / day );
rates1.set( rt::polymer, -10.16 / day );
rates1.set( rt::brine, -10.17 / day );
rates1.set( rt::tracer, -10.18 / day, "SEA" );
data::Rates rates2;
rates2.set( rt::wat, -20.0 / day );
@@ -169,6 +170,7 @@ data::Wells result_wells(const bool w3_injector = true)
rates2.set( rt::well_potential_gas, -20.15 / day );
rates2.set( rt::polymer, -20.16 / day );
rates2.set( rt::brine, -20.17 / day );
rates2.set( rt::tracer, -20.18 / day, "SEA" );
data::Rates rates3;
rates3.set( rt::wat, 30.0 / day );
@@ -188,6 +190,7 @@ data::Wells result_wells(const bool w3_injector = true)
rates3.set( rt::well_potential_gas, 30.15 / day );
rates3.set( rt::polymer, 30.16 / day );
rates3.set( rt::brine, 30.17 / day );
rates3.set( rt::tracer, 30.18 / day, "SEA" );
data::Rates rates6;
rates6.set( rt::wat, 60.0 / day );
@@ -207,6 +210,7 @@ data::Wells result_wells(const bool w3_injector = true)
rates6.set( rt::well_potential_gas, 60.15 / day );
rates6.set( rt::polymer, 60.16 / day );
rates6.set( rt::brine, 60.17 / day );
rates6.set( rt::tracer, 60.18 / day, "SEA" );
/* completion rates */
data::Rates crates1;
@@ -549,8 +553,10 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
/* Production rates */
BOOST_CHECK_CLOSE( 10.0, ecl_sum_get_well_var( resp, 1, "W_1", "WWPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.18, ecl_sum_get_well_var( resp, 1, "W_1", "WTPRSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 20.0, ecl_sum_get_well_var( resp, 1, "W_2", "WWPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 20.18, ecl_sum_get_well_var( resp, 1, "W_2", "WTPRSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.1, ecl_sum_get_well_var( resp, 1, "W_1", "WOPR" ), 1e-5 );
@@ -619,7 +625,9 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
/* Production totals */
BOOST_CHECK_CLOSE( 10.0, ecl_sum_get_well_var( resp, 1, "W_1", "WWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.18, ecl_sum_get_well_var( resp, 1, "W_1", "WTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 20.0, ecl_sum_get_well_var( resp, 1, "W_2", "WWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 20.18, ecl_sum_get_well_var( resp, 1, "W_2", "WTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.1, ecl_sum_get_well_var( resp, 1, "W_1", "WOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 20.1, ecl_sum_get_well_var( resp, 1, "W_2", "WOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.2, ecl_sum_get_well_var( resp, 1, "W_1", "WGPT" ), 1e-5 );
@@ -638,6 +646,7 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
ecl_sum_get_well_var( resp, 1, "W_2", "WVPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 10.0, ecl_sum_get_well_var( resp, 2, "W_1", "WWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 10.18, ecl_sum_get_well_var( resp, 2, "W_1", "WTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 20.0, ecl_sum_get_well_var( resp, 2, "W_2", "WWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 10.1, ecl_sum_get_well_var( resp, 2, "W_1", "WOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 20.1, ecl_sum_get_well_var( resp, 2, "W_2", "WOPT" ), 1e-5 );
@@ -682,6 +691,7 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
/* Injection rates */
BOOST_CHECK_CLOSE( 30.0, ecl_sum_get_well_var( resp, 1, "W_3", "WWIR" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.18, ecl_sum_get_well_var( resp, 1, "W_3", "WTIRSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.6, ecl_sum_get_well_var( resp, 1, "W_3", "WWVIR" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.8, ecl_sum_get_well_var( resp, 1, "W_3", "WGVIR" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.2, ecl_sum_get_well_var( resp, 1, "W_3", "WGIR" ), 1e-5 );
@@ -691,12 +701,14 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
/* Injection totals */
BOOST_CHECK_CLOSE( 30.0, ecl_sum_get_well_var( resp, 1, "W_3", "WWIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.18, ecl_sum_get_well_var( resp, 1, "W_3", "WTITSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.2, ecl_sum_get_well_var( resp, 1, "W_3", "WGIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.3, ecl_sum_get_well_var( resp, 1, "W_3", "WNIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 30.16, ecl_sum_get_well_var( resp, 1, "W_3", "WCIT" ), 1e-5 );
BOOST_CHECK_CLOSE( (30.6 + 30.7 + 30.8),
ecl_sum_get_well_var( resp, 1, "W_3", "WVIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 30.0, ecl_sum_get_well_var( resp, 2, "W_3", "WWIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 30.18, ecl_sum_get_well_var( resp, 2, "W_3", "WTITSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 30.2, ecl_sum_get_well_var( resp, 2, "W_3", "WGIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 30.3, ecl_sum_get_well_var( resp, 2, "W_3", "WNIT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * 30.16, ecl_sum_get_well_var( resp, 2, "W_3", "WCIT" ), 1e-5 );
@@ -726,6 +738,14 @@ BOOST_AUTO_TEST_CASE(well_keywords) {
BOOST_CHECK_CLOSE( wwcut2, ecl_sum_get_well_var( resp, 1, "W_2", "WWCT" ), 1e-5 );
BOOST_CHECK_CLOSE( wwcut3, ecl_sum_get_well_var( resp, 1, "W_3", "WWCT" ), 1e-5 );
/* Tracer concentration */
const double wtpc1 = 10.18 / 10.0;
const double wtpc2 = 20.18 / 20.0;
const double wtic3 = 30.18 / 30.0;
BOOST_CHECK_CLOSE( wtpc1, ecl_sum_get_well_var( resp, 1, "W_1", "WTPCSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( wtpc2, ecl_sum_get_well_var( resp, 1, "W_2", "WTPCSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( wtic3, ecl_sum_get_well_var( resp, 1, "W_3", "WTICSEA" ), 1e-5 );
/* gas-oil ratio */
const double wgor1 = 10.2 / 10.1;
const double wgor2 = 20.2 / 20.1;
@@ -801,6 +821,7 @@ BOOST_AUTO_TEST_CASE(well_keywords_dynamic_close) {
/* Production rates */
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WWPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WTPRSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WOPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WGPR" ), 1e-5 );
@@ -822,6 +843,7 @@ BOOST_AUTO_TEST_CASE(well_keywords_dynamic_close) {
/* Production totals */
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WGPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 0.0, ecl_sum_get_well_var( resp, 1, "W_2", "WNPT" ), 1e-5 );
@@ -1297,6 +1319,7 @@ BOOST_AUTO_TEST_CASE(field_keywords) {
/* Production rates */
BOOST_CHECK_CLOSE( 10.0 + 20.0, ecl_sum_get_field_var( resp, 1, "FWPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.18 + 20.18, ecl_sum_get_field_var( resp, 1, "FTPRSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.1 + 20.1, ecl_sum_get_field_var( resp, 1, "FOPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.2 + 20.2, ecl_sum_get_field_var( resp, 1, "FGPR" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.0 + 20.0 + 10.1 + 20.1,
@@ -1323,6 +1346,7 @@ BOOST_AUTO_TEST_CASE(field_keywords) {
/* Production totals */
BOOST_CHECK_CLOSE( 10.0 + 20.0, ecl_sum_get_field_var( resp, 1, "FWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.18 + 20.18, ecl_sum_get_field_var( resp, 1, "FTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.1 + 20.1, ecl_sum_get_field_var( resp, 1, "FOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.2 + 20.2, ecl_sum_get_field_var( resp, 1, "FGPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 10.0 + 20.0 + 10.1 + 20.1,
@@ -1339,6 +1363,7 @@ BOOST_AUTO_TEST_CASE(field_keywords) {
ecl_sum_get_field_var( resp, 1, "FOPTF" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * (10.0 + 20.0), ecl_sum_get_field_var( resp, 2, "FWPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * (10.18 + 20.18), ecl_sum_get_field_var( resp, 2, "FTPTSEA" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * (10.1 + 20.1), ecl_sum_get_field_var( resp, 2, "FOPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * (10.2 + 20.2), ecl_sum_get_field_var( resp, 2, "FGPT" ), 1e-5 );
BOOST_CHECK_CLOSE( 2 * (10.0 + 20.0 + 10.1 + 20.1),
@@ -1916,6 +1941,8 @@ BOOST_AUTO_TEST_CASE(READ_WRITE_WELLDATA) {
Opm::data::Wells wellRatesCopy;
wellRatesCopy.read(buffer);
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_1" , rt::tracer, "SEA") , wellRates.get( "W_1" , rt::tracer, "SEA"), 1e-16);
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_1" , rt::wat) , wellRates.get( "W_1" , rt::wat), 1e-16);
BOOST_CHECK_CLOSE( wellRatesCopy.get( "W_2" , 101 , rt::wat) , wellRates.get( "W_2" , 101 , rt::wat), 1e-16);