From ec976db68488ffcc6abdf04b8e5a17c4da2d7057 Mon Sep 17 00:00:00 2001 From: Jostein Alvestad Date: Fri, 15 May 2020 08:43:32 +0200 Subject: [PATCH] correction for lift quantity well-data corrections to IUAD and IUAP various improvements of E100 compatible restart file add debug output additonal debug print corrected loop placement for active prod/inj wells remove debug print and clean up code --- opm/output/eclipse/VectorItems/msw.hpp | 2 + opm/output/eclipse/VectorItems/well.hpp | 1 + .../EclipseState/Schedule/UDQ/UDQActive.hpp | 1 + src/opm/output/eclipse/AggregateGroupData.cpp | 86 ++++++------------- src/opm/output/eclipse/AggregateMSWData.cpp | 5 ++ src/opm/output/eclipse/AggregateUDQData.cpp | 31 ++++--- src/opm/output/eclipse/AggregateWellData.cpp | 8 +- src/opm/output/eclipse/CreateInteHead.cpp | 37 +++++++- .../EclipseState/Schedule/UDQ/UDQActive.cpp | 9 +- 9 files changed, 101 insertions(+), 79 deletions(-) diff --git a/opm/output/eclipse/VectorItems/msw.hpp b/opm/output/eclipse/VectorItems/msw.hpp index f0e1661e9..8c0052ea6 100644 --- a/opm/output/eclipse/VectorItems/msw.hpp +++ b/opm/output/eclipse/VectorItems/msw.hpp @@ -55,6 +55,8 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems GasFlowFract = 10, // Normalised Gas flow rate fraction Pressure = 11, // Segment pressure + item31 = 30, // Very close to Normalised Water flow rate fraction - value used pr today + item40 = 39, // Unknown ValveLength = 40, // Length of valve diff --git a/opm/output/eclipse/VectorItems/well.hpp b/opm/output/eclipse/VectorItems/well.hpp index f257cfbb7..62ec24117 100644 --- a/opm/output/eclipse/VectorItems/well.hpp +++ b/opm/output/eclipse/VectorItems/well.hpp @@ -113,6 +113,7 @@ namespace Opm { namespace RestartIO { namespace Helpers { namespace VectorItems BHPTarget = 6, // Well's bottom hole pressure target DatumDepth = 9, // Well's reference depth for BHP + Alq_value = 10, // Well's artificial lift quantity DrainageRadius = 17, // Well's drainage radius - item 7 from WELSPECS EfficiencyFactor1 = 24, // Item2 from WEFAC; this value is repeated at two locations. diff --git a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp index 8ba93460a..e2225f7aa 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.hpp @@ -87,6 +87,7 @@ public: std::size_t use_index = 0; UDAControl control; int uad_code; + std::string wg_name() const; std::size_t use_count; private: // The wgname is need in the update process, but it should diff --git a/src/opm/output/eclipse/AggregateGroupData.cpp b/src/opm/output/eclipse/AggregateGroupData.cpp index 79c96d970..3a6a70e0c 100644 --- a/src/opm/output/eclipse/AggregateGroupData.cpp +++ b/src/opm/output/eclipse/AggregateGroupData.cpp @@ -230,9 +230,6 @@ int higherLevelProdControlGroupSeqIndex(const Opm::Schedule& sched, cur_prod_ctrl = sumState.get(group_key); } else { - //std::stringstream str; - //str << "Current group control is not defined for group: " << current.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current group control is not defined for group: " << current.name() << " at timestep: " << simStep << std::endl; cur_prod_ctrl = 0.; } @@ -269,9 +266,6 @@ int higherLevelProdControlMode(const Opm::Schedule& sched, cur_prod_ctrl = sumState.get(group_key); } else { - //std::stringstream str; - //str << "Current group control is not defined for group: " << current.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current group control is not defined for group: " << current.name() << " at timestep: " << simStep << std::endl; cur_prod_ctrl = 0.; } @@ -313,9 +307,6 @@ int higherLevelInjControlGroupSeqIndex(const Opm::Schedule& sched, cur_inj_ctrl = sumState.get(group_key); } else { - //std::stringstream str; - //str << "Current injection group control: " << curInjCtrlKey << " is not defined for group: " << current.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current injection group control: " << curInjCtrlKey << " is not defined for group: " << current.name() << " at timestep: " << simStep << std::endl; cur_inj_ctrl = 0.; } @@ -353,9 +344,6 @@ int higherLevelInjControlMode(const Opm::Schedule& sched, cur_inj_ctrl = sumState.get(group_key); } else { - //std::stringstream str; - //str << "Current injection group control: " << curInjCtrlKey << " is not defined for group: " << current.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current injection group control: " << curInjCtrlKey << " is not defined for group: " << current.name() << " at timestep: " << simStep << std::endl; cur_inj_ctrl = 0.; } @@ -519,6 +507,33 @@ void staticContrib(const Opm::Schedule& sched, // location nwgmax iGrp[nwgmax] = groupSize(group); + // Find number of active production wells and injection wells for group + std::string group_key_1; + group_key_1 = gf_key("GMWPR", group.name()); + double g_act_pwells = -1.; + if (sumState.has(group_key_1)) { + g_act_pwells = sumState.get(group_key_1); + } + else { + g_act_pwells = 0.; + } + + group_key_1 = gf_key("GMWIN", group.name()); + double g_act_iwells = -1.; + if (sumState.has(group_key_1)) { + g_act_iwells = sumState.get(group_key_1); + } + else { + g_act_iwells = 0.; + } + // set the number of active wells for a group + if (g_act_pwells >= 0 && g_act_iwells >= 0) { + iGrp[nwgmax + 33] = g_act_pwells + g_act_iwells; + } + else { + iGrp[nwgmax + 33] = 0; + } + //Treat groups that have production if ((group.getGroupType() == Opm::Group::GroupType::NONE) || (group.getGroupType() == Opm::Group::GroupType::PRODUCTION) || (group.getGroupType() == Opm::Group::GroupType::MIXED)) { @@ -527,7 +542,6 @@ void staticContrib(const Opm::Schedule& sched, const auto& prod_guide_rate_def = group.productionControls(sumState).guide_rate_def; const auto& p_exceed_act = group.productionControls(sumState).exceed_action; // Find production control mode for group - std::string group_key_1; group_key_1 = gf_key("GMCTP", group.name()); double cur_prod_ctrl = -1.; Opm::Group::ProductionCMode pctl_mode = Opm::Group::ProductionCMode::NONE; @@ -545,34 +559,6 @@ void staticContrib(const Opm::Schedule& sched, //throw std::invalid_argument(str.str()); } - // Find number of active production wells and injection wells for group - - group_key_1 = gf_key("GMWPR", group.name()); - double g_act_pwells = -1.; - if (sumState.has(group_key_1)) { - g_act_pwells = sumState.get(group_key_1); - } - else { - //std::stringstream str; - //str << "Number of flowing production wells is not defined for group: " << group.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); - std::cout << "Number of flowing production wells is not defined for group: " << group.name() << " at timestep: " << simStep << std::endl; - g_act_pwells = 0.; - } - - group_key_1 = gf_key("GMWIN", group.name()); - double g_act_iwells = -1.; - if (sumState.has(group_key_1)) { - g_act_iwells = sumState.get(group_key_1); - } - else { - //std::stringstream str; - //str << "Number of flowing injection wells is not defined for group: " << group.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); - std::cout << "Number of flowing injection wells is not defined for group: " << group.name() << " at timestep: " << simStep << std::endl; - g_act_iwells = 0.; - } - /*IGRP[NWGMAX + 5] - the value is determined by a relatively complex logic, a pseudo code scetch follows: if (group is free to respond to higher level production rate target_reinj_fraction) @@ -762,15 +748,6 @@ void staticContrib(const Opm::Schedule& sched, iGrp[nwgmax + 10] = 0; } } - - // set the number of active wells for a group - - if (g_act_pwells >= 0 && g_act_iwells >= 0) { - iGrp[nwgmax + 33] = g_act_pwells + g_act_iwells; - } - else { - iGrp[nwgmax + 33] = 0; - } } //default value - iGrp[nwgmax + 17] = -1; @@ -800,9 +777,6 @@ void staticContrib(const Opm::Schedule& sched, } } else { - //std::stringstream str; - //str << "Current group water injection control is not defined for group: " << group.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current group water injection control is not defined for group: " << group.name() << " at timestep: " << simStep << std::endl; } if (group.name() != "FIELD") { @@ -900,9 +874,6 @@ void staticContrib(const Opm::Schedule& sched, } } else { - //std::stringstream str; - //str << "Current group gas injection control is not defined for group: " << group.name() << " at timestep: " << simStep; - //throw std::invalid_argument(str.str()); std::cout << "Current group gas injection control is not defined for group: " << group.name() << " at timestep: " << simStep << std::endl; } @@ -1109,12 +1080,10 @@ void staticContrib(const Opm::Group& group, if (prod_cntl.oil_target > 0.) { sGrp[Isp::OilRateLimit] = sgprop(M::liquid_surface_rate, prod_cntl.oil_target); - //sGrp[37] = sGrp[Isp::OilRateLimit]; sGrp[52] = sGrp[Isp::OilRateLimit]; // "ORAT" control } if (prod_cntl.water_target > 0.) { sGrp[Isp::WatRateLimit] = sgprop(M::liquid_surface_rate, prod_cntl.water_target); - //sGrp[38] = sGrp[Isp::WatRateLimit]; sGrp[53] = sGrp[Isp::WatRateLimit]; //"WRAT" control } if (prod_cntl.gas_target > 0.) { @@ -1123,7 +1092,6 @@ void staticContrib(const Opm::Group& group, } if (prod_cntl.liquid_target > 0.) { sGrp[Isp::LiqRateLimit] = sgprop(M::liquid_surface_rate, prod_cntl.liquid_target); - //sGrp[40] = sGrp[Isp::LiqRateLimit]; sGrp[54] = sGrp[Isp::LiqRateLimit]; //"LRAT" control } } diff --git a/src/opm/output/eclipse/AggregateMSWData.cpp b/src/opm/output/eclipse/AggregateMSWData.cpp index c6877f8d3..520fabc8b 100644 --- a/src/opm/output/eclipse/AggregateMSWData.cpp +++ b/src/opm/output/eclipse/AggregateMSWData.cpp @@ -698,6 +698,9 @@ namespace { rSeg[iS + Ix::WatFlowFract] = (std::abs(temp_w) > 0) ? temp_w / rSeg[8] : 0.; rSeg[iS + Ix::GasFlowFract] = (std::abs(temp_g) > 0) ? temp_g / rSeg[8] : 0.; + + rSeg[iS + Ix::item31] = rSeg[iS + Ix::WatFlowFract]; + // value is 1. based on tests on several data sets rSeg[iS + Ix::item40] = 1.; @@ -751,6 +754,8 @@ namespace { rSeg[iS + Ix::WatFlowFract] = (std::abs(temp_w) > 0) ? temp_w / rSeg[iS + 8] : 0.; rSeg[iS + Ix::GasFlowFract] = (std::abs(temp_g) > 0) ? temp_g / rSeg[iS + 8] : 0.; + rSeg[iS + Ix::item31] = rSeg[iS + Ix::WatFlowFract]; + rSeg[iS + Ix::item40] = 1.; rSeg[iS + Ix::item106] = 1.0; diff --git a/src/opm/output/eclipse/AggregateUDQData.cpp b/src/opm/output/eclipse/AggregateUDQData.cpp index de89db652..da0634152 100644 --- a/src/opm/output/eclipse/AggregateUDQData.cpp +++ b/src/opm/output/eclipse/AggregateUDQData.cpp @@ -64,11 +64,10 @@ namespace { return inteHead[163]; } - - // Categorize function in terms of which token-types are used in formula + // Categorize function in terms of which token-types are used in formula int define_type(const std::set tokens) { int type = -4; - std::vector type_1 = { + std::vector type_1 = { Opm::UDQTokenType::elemental_func_sorta, Opm::UDQTokenType::elemental_func_sortd, Opm::UDQTokenType::elemental_func_undef, @@ -77,18 +76,17 @@ namespace { Opm::UDQTokenType::scalar_func_aveg, Opm::UDQTokenType::scalar_func_aveh, Opm::UDQTokenType::scalar_func_max, - Opm::UDQTokenType::scalar_func_min, + Opm::UDQTokenType::scalar_func_min, Opm::UDQTokenType::binary_op_div }; - + int num_type_1 = 0; for (const auto& tok_type : type_1) { num_type_1 += tokens.count(tok_type); - } + } type = (num_type_1 > 0) ? -1 : -4; return type; } - namespace iUdq { @@ -134,7 +132,7 @@ namespace { } template - void staticContrib(const Opm::UDQActive::Record& udq_record, IUADArray& iUad) + void staticContrib(const Opm::UDQActive::Record& udq_record, IUADArray& iUad, int use_cnt_diff) { iUad[0] = udq_record.uad_code; iUad[1] = udq_record.input_index + 1; @@ -143,7 +141,7 @@ namespace { iUad[2] = 1; iUad[3] = udq_record.use_count; - iUad[4] = udq_record.use_index + 1; + iUad[4] = udq_record.use_index + 1 - use_cnt_diff; } } // iUad @@ -445,7 +443,9 @@ const std::vector iuap_data(const Opm::Schedule& sched, } else if ((wg_key == Opm::UDAKeyword::GCONPROD) || (wg_key == Opm::UDAKeyword::GCONINJE)) { const auto& group = sched.getGroup(iuap[ind].wgname, simStep); - wg_no.push_back(group.insert_index() - 1); + if (iuap[ind].wgname != "FIELD") { + wg_no.push_back(group.insert_index() - 1); + } } else { std::cout << "Invalid Control keyword: " << static_cast(ctrl) << std::endl; @@ -511,9 +511,14 @@ captureDeclaredUDQData(const Opm::Schedule& sched, int cnt_iuad = 0; for (std::size_t index = 0; index < udq_records.size(); index++) { const auto& record = udq_records[index]; - auto i_uad = this->iUAD_[index]; - iUad::staticContrib(record, i_uad); - cnt_iuad += 1; + auto i_uad = this->iUAD_[cnt_iuad]; + const auto& ctrl = record.control; + const auto wg_key = Opm::UDQ::keyword(ctrl); + if (!(((wg_key == Opm::UDAKeyword::GCONPROD) || (wg_key == Opm::UDAKeyword::GCONINJE)) && (record.wg_name() == "FIELD"))) { + int use_count_diff = static_cast(index) - cnt_iuad; + iUad::staticContrib(record, i_uad, use_count_diff); + cnt_iuad += 1; + } } if (cnt_iuad != inteHead[VI::intehead::NO_IUADS]) { std::stringstream str; diff --git a/src/opm/output/eclipse/AggregateWellData.cpp b/src/opm/output/eclipse/AggregateWellData.cpp index 1fe3b60ae..7cdafc84b 100644 --- a/src/opm/output/eclipse/AggregateWellData.cpp +++ b/src/opm/output/eclipse/AggregateWellData.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -496,6 +497,11 @@ namespace { : swprop(M::pressure, 1.0*::Opm::unit::atm); sWell[Ix::HistBHPTarget] = sWell[Ix::BHPTarget]; + //alq_value - has no unit conversion according to parser code + if (pc.alq_value != 0.0) { + sWell[Ix::Alq_value] = pc.alq_value; + } + if (predMode) { //if (well.getStatus() == Opm::Well::Status::OPEN) { sWell[Ix::OilRateTarget] = getRateLimit(units, M::liquid_surface_rate, pc.oil_rate); @@ -903,7 +909,7 @@ captureDeclaredWellData(const Schedule& sched, void Opm::RestartIO::Helpers::AggregateWellData:: -captureDynamicWellData(const Schedule& sched, +captureDynamicWellData(const Opm::Schedule& sched, const std::size_t sim_step, const Opm::data::WellRates& xw, const ::Opm::SummaryState& smry) diff --git a/src/opm/output/eclipse/CreateInteHead.cpp b/src/opm/output/eclipse/CreateInteHead.cpp index 77fbe5522..794d84903 100755 --- a/src/opm/output/eclipse/CreateInteHead.cpp +++ b/src/opm/output/eclipse/CreateInteHead.cpp @@ -154,6 +154,39 @@ namespace { return std::count_if(input.begin(), input.end(), [](const Opm::UDQInput inp) { return (inp.var_type() == Opm::UDQVarType::GROUP_VAR); }); } + int noIuads(const Opm::Schedule& sched, + const std::size_t rptStep, + const std::size_t simStep) + { + if (rptStep == std::size_t{0}) { + return 0; + } + + const auto& udqAct = sched.udqActive(simStep); + const auto& iuad = udqAct.get_iuad(); + + return std::count_if(iuad.begin(), iuad.end(), [](const Opm::UDQActive::Record rec) { + return (!(((Opm::UDQ::keyword(rec.control) == Opm::UDAKeyword::GCONPROD) || (Opm::UDQ::keyword(rec.control) == Opm::UDAKeyword::GCONINJE)) + && (rec.wg_name() == "FIELD"))); }); + } + + int noIuaps(const Opm::Schedule& sched, + const std::size_t rptStep, + const std::size_t simStep) + { + if (rptStep == std::size_t{0}) { + return 0; + } + + const auto& udqAct = sched.udqActive(simStep); + const auto& iuap = udqAct.get_iuap(); + + return std::count_if(iuap.begin(), iuap.end(), [](const Opm::UDQActive::InputRecord rec) { + return (!(((Opm::UDQ::keyword(rec.control) == Opm::UDAKeyword::GCONPROD) || (Opm::UDQ::keyword(rec.control) == Opm::UDAKeyword::GCONINJE)) + && (rec.wgname == "FIELD"))); }); + } + + int noFieldUdqs(const Opm::Schedule& sched, const std::size_t rptStep, const std::size_t simStep) @@ -288,8 +321,8 @@ namespace { const auto no_wudq = noWellUdqs(sched, rptStep, simStep); const auto no_gudq = noGroupUdqs(sched, rptStep, simStep); const auto no_fudq = noFieldUdqs(sched, rptStep, simStep); - const auto no_iuads = udqActive.IUAD_size(); - const auto no_iuaps = udqActive.IUAP_size(); + const auto no_iuads = noIuads(sched, rptStep, simStep); + const auto no_iuaps = noIuaps(sched, rptStep, simStep); return { r_seed, diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.cpp index 42cc12be2..9313293d0 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQActive.cpp @@ -50,6 +50,11 @@ UDQActive::operator bool() const { return this->input_data.size() > 0; } + +std::string UDQActive::Record::wg_name() const { + return this->wgname; +} + std::string UDQActive::udq_hash(const std::string& udq, UDAControl control) { return udq + std::to_string(static_cast(control)); } @@ -144,10 +149,6 @@ const std::vector& UDQActive::get_iuad() const { this->output_data.emplace_back(input_record.udq, input_record.input_index, 0, input_record.wgname, input_record.control); } - std::sort(this->output_data.begin(), this->output_data.end(), - [](const UDQActive::Record& rec1, const UDQActive::Record& rec2) { return rec1.input_index < rec2.input_index;}); - - if (!output_data.empty()) { for (std::size_t index = 1; index < output_data.size(); index++) { const auto& prev_record = this->output_data[index - 1];