diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index d296cb53f..fa567b437 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -98,6 +98,7 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/EclipseState/Schedule/Action/Condition.cpp src/opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.cpp src/opm/parser/eclipse/EclipseState/Schedule/Events.cpp + src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/Group.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRate.cpp src/opm/parser/eclipse/EclipseState/Schedule/Group/GuideRateConfig.cpp @@ -668,6 +669,7 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Schedule/Action/ASTNode.hpp opm/parser/eclipse/EclipseState/Schedule/Action/PyAction.hpp opm/parser/eclipse/EclipseState/Schedule/ArrayDimChecker.hpp + opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp opm/parser/eclipse/EclipseState/Schedule/Network/Branch.hpp opm/parser/eclipse/EclipseState/Schedule/Network/ExtNetwork.hpp opm/parser/eclipse/EclipseState/Schedule/Network/Node.hpp diff --git a/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp b/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp new file mode 100644 index 000000000..08321af35 --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.hpp @@ -0,0 +1,251 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ +#ifndef GAS_LIFT_OPT_HPP +#define GAS_LIFT_OPT_HPP + +#include +#include +#include + +namespace Opm { + +class GasLiftOpt { +public: + + class Group { + public: + Group() = default; + + Group(const std::string& name) : + m_name(name) + {} + + const std::optional& max_lift_gas() const { + return this->m_max_lift_gas; + } + + void max_lift_gas(double value) { + if (value >= 0) + this->m_max_lift_gas = value; + } + + const std::optional& max_total_gas() const { + return this->m_max_total_gas; + } + + void max_total_gas(double value) { + if (value >= 0) + this->m_max_total_gas = value; + } + + const std::string& name() const { + return this->m_name; + } + + template + void serializeOp(Serializer& serializer) + { + serializer(m_name); + serializer(m_max_lift_gas); + serializer(m_max_total_gas); + } + + + static Group serializeObject() { + Group group; + group.m_name = "GR"; + group.m_max_lift_gas = 100; + group.m_max_total_gas = 200; + return group; + } + + + bool operator==(const Group& other) const { + return this->m_name == other.m_name && + this->m_max_lift_gas == other.m_max_lift_gas && + this->m_max_total_gas == other.m_max_total_gas; + } + + private: + std::string m_name; + std::optional m_max_lift_gas; + std::optional m_max_total_gas; + }; + + + class Well { + public: + Well() = default; + Well(const std::string& name, bool use_glo) : + m_name(name), + m_use_glo(use_glo) + {} + + const std::string& name() const { + return this->m_name; + } + + bool use_glo() const { + return this->m_use_glo; + } + + void max_rate(double value) { + this->m_max_rate = value; + } + + + /* + The semantics of the max_rate is quite complicated: + + 1. If the std::optional has a value that value should be + used as the maximum rate and all is fine. + + 2. If the std::optional does not a have well we must check + the value of Well::use_glo(): + + False: The maximum gas lift should have been set with WCONPROD / + WELTARG - this code does not provide a value in that case. + + True: If the well should be controlled with gas lift optimization + the value to use should be the largest ALQ value in the wells + VFP table. + */ + const std::optional& max_rate() const { + return this->m_max_rate; + } + + void weight_factor(double value) { + if (this->m_use_glo) + this->m_weight = value; + } + + double weight_factor() const { + return this->m_weight; + } + + void inc_weight_factor(double value) { + if (this->m_use_glo) + this->m_inc_weight = value; + } + + double inc_weight_factor() const { + return this->m_inc_weight; + } + + void min_rate(double value) { + if (this->m_use_glo) + this->m_min_rate = value; + } + + double min_rate() const { + return this->m_min_rate; + } + + void alloc_extra_gas(bool value) { + if (this->m_use_glo) + this->m_alloc_extra_gas = value; + } + + bool alloc_extra_gas() const { + return this->m_alloc_extra_gas; + } + + template + void serializeOp(Serializer& serializer) + { + serializer(m_name); + serializer(m_use_glo); + serializer(m_max_rate); + serializer(m_min_rate); + serializer(m_weight); + serializer(m_inc_weight); + serializer(m_alloc_extra_gas); + } + + static Well serializeObject() { + Well well; + well.m_name = "WELL"; + well.m_max_rate = 2000; + well.m_min_rate = 56; + well.m_use_glo = true; + well.m_weight = 1.25; + well.m_inc_weight = 0.25; + well.m_alloc_extra_gas = false; + return well; + } + + bool operator==(const Well& other) const { + return this->m_name == other.m_name && + this->m_max_rate == other.m_max_rate && + this->m_min_rate == other.m_min_rate && + this->m_use_glo == other.m_use_glo && + this->m_weight == other.m_weight && + this->m_inc_weight == other.m_inc_weight && + this->m_alloc_extra_gas == other.m_alloc_extra_gas; + } + + private: + std::string m_name; + std::optional m_max_rate; + double m_min_rate = 0; + bool m_use_glo; + double m_weight = 1; + double m_inc_weight = 0; + bool m_alloc_extra_gas = false; + }; + + GasLiftOpt() = default; + + const Group& group(const std::string& gname) const; + const Well& well(const std::string& wname) const; + + void gaslift_increment(double gaslift_increment); + void min_eco_gradient(double min_eco_gradient); + void min_wait(double min_wait); + void all_newton(double all_newton); + void add_group(const Group& group); + void add_well(const Well& well); + bool active() const; + + static GasLiftOpt serializeObject(); + bool operator==(const GasLiftOpt& other) const; + + template + void serializeOp(Serializer& serializer) + { + serializer(m_increment); + serializer(m_min_eco_gradient); + serializer(m_min_wait); + serializer(m_all_newton); + serializer.map(m_groups); + serializer.map(m_wells); + } +private: + double m_increment = 0; + double m_min_eco_gradient; + double m_min_wait; + bool m_all_newton = true; + + std::map m_groups; + std::map m_wells; +}; + +} + +#endif diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 1fa46982a..ae2c3e966 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -266,6 +267,7 @@ namespace Opm const Network::ExtNetwork& network(std::size_t report_step) const; + const GasLiftOpt& glo(std::size_t report_step) const; bool operator==(const Schedule& data) const; std::shared_ptr python() const; @@ -310,6 +312,7 @@ namespace Opm global_whistctl_mode.template serializeOp(serializer); m_actions.serializeOp(serializer); m_network.serializeOp(serializer); + m_glo.serializeOp(serializer); rft_config.serializeOp(serializer); m_nupcol.template serializeOp(serializer); restart_config.serializeOp(serializer); @@ -346,6 +349,7 @@ namespace Opm DynamicState global_whistctl_mode; DynamicState> m_actions; DynamicState> m_network; + DynamicState> m_glo; RFTConfig rft_config; DynamicState m_nupcol; RestartConfig restart_config; @@ -429,7 +433,9 @@ namespace Opm void handleBRANPROP( const DeckKeyword& keyword, size_t currentStep); void handleNODEPROP( const DeckKeyword& keyword, size_t currentStep); - + void handleLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep); + void handleGLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); + void handleWLIFTOPT(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors); void handleTUNING( const DeckKeyword& keyword, size_t currentStep); void handlePYACTION( std::shared_ptr python, const std::string& input_path, const DeckKeyword& keyword, size_t currentStep); void handleNUPCOL( const DeckKeyword& keyword, size_t currentStep); diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp new file mode 100644 index 000000000..83bd868cb --- /dev/null +++ b/src/opm/parser/eclipse/EclipseState/Schedule/GasLiftOpt.cpp @@ -0,0 +1,100 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#include + +#include + +namespace Opm { + +bool GasLiftOpt::active() const { + return (this->m_increment > 0); +} + +void GasLiftOpt::gaslift_increment(double gaslift_increment) { + this->m_increment = gaslift_increment; +} + +void GasLiftOpt::min_eco_gradient(double min_eco_gradient) { + this->m_min_eco_gradient = min_eco_gradient; +} + +void GasLiftOpt::min_wait(double min_wait) { + this->m_min_wait = min_wait; +} + +void GasLiftOpt::all_newton(double all_newton) { + this->m_all_newton = all_newton; +} + +const GasLiftOpt::Group& GasLiftOpt::group(const std::string& gname) const { + const auto iter = this->m_groups.find(gname); + if (iter == this->m_groups.end()) + throw std::out_of_range("No such group: " + gname + " configured for gas lift optimization"); + + return iter->second; +} + + +void GasLiftOpt::add_group(const Group& group) { + auto iter = this->m_groups.find(group.name()); + if (iter == this->m_groups.end()) + this->m_groups.insert( std::make_pair(group.name(), group) ); + else + iter->second = group; +} + + +void GasLiftOpt::add_well(const Well& well) { + auto iter = this->m_wells.find(well.name()); + if (iter == this->m_wells.end()) + this->m_wells.insert( std::make_pair(well.name(), well) ); + else + iter->second = well; +} + + +const GasLiftOpt::Well& GasLiftOpt::well(const std::string& wname) const { + const auto iter = this->m_wells.find(wname); + if (iter == this->m_wells.end()) + throw std::out_of_range("No such well: " + wname + " configured for gas lift optimization"); + + return iter->second; +} + +GasLiftOpt GasLiftOpt::serializeObject() { + GasLiftOpt glo; + glo.m_increment = 0; + glo.m_min_eco_gradient = 100; + glo.m_min_wait = 1; + glo.m_all_newton = true; + return glo; +} + +bool GasLiftOpt::operator==(const GasLiftOpt& other) const { + return this->m_increment == other.m_increment && + this->m_min_eco_gradient == other.m_min_eco_gradient && + this->m_min_wait == other.m_min_wait && + this->m_all_newton == other.m_all_newton && + this->m_groups == other.m_groups && + this->m_wells == other.m_wells; +} + +} + diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 4a029db60..df1321d9f 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -149,6 +149,7 @@ std::pair restart_info(const RestartIO::RstState * rst global_whistctl_mode(this->m_timeMap, Well::ProducerCMode::CMODE_UNDEFINED), m_actions(this->m_timeMap, std::make_shared()), m_network(this->m_timeMap, std::make_shared()), + m_glo(this->m_timeMap, std::make_shared()), rft_config(this->m_timeMap), m_nupcol(this->m_timeMap, ParserKeywords::NUPCOL::NUM_ITER::defaultValue), restart_config(m_timeMap, deck, parseContext, errors), @@ -263,6 +264,7 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext& result.wlist_manager = {{std::make_shared(WListManager::serializeObject())}, 1}; result.udq_config = {{std::make_shared(UDQConfig::serializeObject())}, 1}; result.m_network = {{std::make_shared(Network::ExtNetwork::serializeObject())}, 1}; + result.m_glo = {{std::make_shared(GasLiftOpt::serializeObject())}, 1}; result.udq_active = {{std::make_shared(UDQActive::serializeObject())}, 1}; result.guide_rate_config = {{std::make_shared(GuideRateConfig::serializeObject())}, 1}; result.gconsale = {{std::make_shared(GConSale::serializeObject())}, 1}; @@ -492,6 +494,15 @@ Schedule::Schedule(const Deck& deck, const EclipseState& es, const ParseContext& else if (keyword.name() == "BRANPROP") handleBRANPROP(keyword, currentStep); + else if (keyword.name() == "LIFTOPT") + handleLIFTOPT(keyword, currentStep); + + else if (keyword.name() == "GLIFTOPT") + handleGLIFTOPT(keyword, currentStep, parseContext, errors); + + else if (keyword.name() == "WLIFTOPT") + handleWLIFTOPT(keyword, currentStep, parseContext, errors); + else if (keyword.name() == "PYACTION") handlePYACTION(python, input_path, keyword, currentStep); @@ -3031,6 +3042,7 @@ void Schedule::invalidNamePattern( const std::string& namePattern, std::size_t compareMap(this->vfpprod_tables, data.vfpprod_tables) && compareMap(this->vfpinj_tables, data.vfpinj_tables) && compareDynState(this->m_network, data.m_network) && + compareDynState(this->m_glo, data.m_glo) && compareDynState(this->wtest_config, data.wtest_config) && compareDynState(this->wlist_manager, data.wlist_manager) && compareDynState(this->udq_config, data.udq_config) && @@ -3175,6 +3187,93 @@ void Schedule::handleNODEPROP(const DeckKeyword& keyword, std::size_t report_ste this->updateNetwork(ext_network, report_step); } +const GasLiftOpt& Schedule::glo(std::size_t report_step) const { + return *this->m_glo[report_step]; +} + +void Schedule::handleLIFTOPT(const DeckKeyword& keyword, std::size_t report_step) { + using LO = ParserKeywords::LIFTOPT; + auto glo = std::make_shared( this->glo(report_step) ); + const auto& record = keyword.getRecord(0); + double gaslift_increment = record.getItem().getSIDouble(0); + double min_eco_gradient = record.getItem().getSIDouble(0); + double min_wait = record.getItem().getSIDouble(0); + bool all_newton = DeckItem::to_bool( record.getItem().get(0) ); + + glo->gaslift_increment(gaslift_increment); + glo->min_eco_gradient(min_eco_gradient); + glo->min_wait(min_wait); + glo->all_newton(all_newton); + + this->m_glo.update(report_step, std::move(glo)); +} + + +void Schedule::handleGLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors) { + using GLO = ParserKeywords::GLIFTOPT; + auto glo = std::make_shared( this->glo(report_step) ); + for (const auto& record : keyword) { + const std::string& groupNamePattern = record.getItem().getTrimmedString(0); + const auto group_names = this->groupNames(groupNamePattern); + if (group_names.empty()) + invalidNamePattern(groupNamePattern, report_step, parseContext, errors, keyword); + + const auto& max_total_item = record.getItem(); + const auto& max_gas_item = record.getItem(); + double max_lift_gas_value = -1; + double max_total_gas_value = -1; + + if (max_gas_item.hasValue(0)) + max_lift_gas_value = max_gas_item.getSIDouble(0); + + if (max_total_item.hasValue(0)) + max_total_gas_value = max_total_item.getSIDouble(0); + + for (const auto& gname : group_names) { + auto group = GasLiftOpt::Group(gname); + group.max_lift_gas(max_lift_gas_value); + group.max_total_gas(max_total_gas_value); + + glo->add_group(group); + } + } + this->m_glo.update(report_step, std::move(glo)); +} + +void Schedule::handleWLIFTOPT(const DeckKeyword& keyword, std::size_t report_step, const ParseContext& parseContext, ErrorGuard& errors) { + using WLO = ParserKeywords::WLIFTOPT; + auto glo = std::make_shared( this->glo(report_step) ); + + for (const auto& record : keyword) { + const std::string& wellNamePattern = record.getItem().getTrimmedString(0); + bool use_glo = DeckItem::to_bool( record.getItem().get(0)); + bool alloc_extra_gas = DeckItem::to_bool( record.getItem().get(0)); + double weight_factor = record.getItem().get(0); + double inc_weight_factor = record.getItem().get(0); + double min_rate = record.getItem().getSIDouble(0); + const auto& max_rate_item = record.getItem(); + + const auto well_names = this->wellNames(wellNamePattern); + if (well_names.empty()) + invalidNamePattern(wellNamePattern, report_step, parseContext, errors, keyword); + + for (const auto& wname : well_names) { + auto well = GasLiftOpt::Well(wname, use_glo); + + if (max_rate_item.hasValue(0)) + well.max_rate( max_rate_item.getSIDouble(0) ); + + well.weight_factor(weight_factor); + well.inc_weight_factor(inc_weight_factor); + well.min_rate(min_rate); + well.alloc_extra_gas(alloc_extra_gas); + + glo->add_well(well); + } + } + + this->m_glo.update(report_step, std::move(glo)); +} void Schedule::handleBRANPROP(const DeckKeyword& keyword, std::size_t report_step) { using BP = ParserKeywords::BRANPROP; diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GLIFTOPT b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GLIFTOPT index f665e3042..dfb14715f 100644 --- a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GLIFTOPT +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/G/GLIFTOPT @@ -11,11 +11,13 @@ { "name": "MAX_LIFT_GAS_SUPPLY", "value_type": "DOUBLE", + "dimension" : "GasSurfaceVolume/Time", "default": -1e+20 }, { "name": "MAX_TOTAL_GAS_RATE", "value_type": "DOUBLE", + "dimension" : "GasSurfaceVolume/Time", "default": -1e+20 } ] diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/L/LIFTOPT b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/L/LIFTOPT index 4290ece3f..470c2bcc9 100644 --- a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/L/LIFTOPT +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/L/LIFTOPT @@ -7,15 +7,18 @@ "items": [ { "name": "INCREMENT_SIZE", - "value_type": "DOUBLE" + "value_type": "DOUBLE", + "dimension" : "GasSurfaceVolume/Time" }, { "name": "MIN_ECONOMIC_GRADIENT", - "value_type": "DOUBLE" + "value_type": "DOUBLE", + "dimension" : "LiquidSurfaceVolume/GasSurfaceVolume" }, { "name": "MIN_INTERVAL_BETWEEN_GAS_LIFT_OPTIMIZATIONS", "value_type": "DOUBLE", + "dimension" : "Time", "default": 0 }, { diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index 35f48f861..5350373d8 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -3604,3 +3605,85 @@ BOOST_AUTO_TEST_CASE(SKIPREST_VFP) { const auto& tables = sched.getVFPProdTables(3); BOOST_CHECK( !tables.empty() ); } + + + + +BOOST_AUTO_TEST_CASE(GASLIFT_OPT) { + GasLiftOpt glo; + BOOST_CHECK(!glo.active()); + BOOST_CHECK_THROW(glo.group("NO_SUCH_GROUP"), std::out_of_range); + BOOST_CHECK_THROW(glo.well("NO_SUCH_WELL"), std::out_of_range); +} + + +BOOST_AUTO_TEST_CASE(GASLIFT_OPT_DECK) { + const auto input = R"(-- Turns on gas lift optimization +SCHEDULE + +GRUPTREE + 'PROD' 'FIELD' / + + 'M5S' 'PLAT-A' / + 'M5N' 'PLAT-A' / + + 'C1' 'M5N' / + 'F1' 'M5N' / + 'B1' 'M5S' / + 'G1' 'M5S' / + / + +LIFTOPT + 12500 5E-3 0.0 YES / + + +-- Group lift gas limits for gas lift optimization +GLIFTOPT + 'PLAT-A' 200000 / -- +/ + +WELSPECS +--WELL GROUP IHEEL JHEEL DREF PHASE DRAD INFEQ SIINS XFLOW PRTAB DENS + 'B-1H' 'B1' 11 3 1* OIL 1* 1* SHUT 1* 1* 1* / + 'B-2H' 'B1' 4 7 1* OIL 1* 1* SHUT 1* 1* 1* / + 'B-3H' 'B1' 11 12 1* OIL 1* 1* SHUT 1* 1* 1* / + 'C-1H' 'C1' 13 20 1* OIL 1* 1* SHUT 1* 1* 1* / + 'C-2H' 'C1' 12 27 1* OIL 1* 1* SHUT 1* 1* 1* / +/ + +-- well savailable for gass lift +-- minimum gas lift rate, enough to keep well flowing +WLIFTOPT + 'B-1H' YES 150000 1.01 -1.0 / + 'B-2H' YES 150000 1.01 -1.0 / + 'B-3H' YES 150000 1.01 -1.0 / + 'C-1H' YES 150000 1.01 -1.0 1.0 YES/ + 'C-2H' NO 150000 1.01 -1.0 / +/ +)"; + Opm::UnitSystem unitSystem = UnitSystem( UnitSystem::UnitType::UNIT_TYPE_METRIC ); + double siFactorG = unitSystem.parse("GasSurfaceVolume/Time").getSIScaling(); + const auto sched = make_schedule(input); + const auto& glo = sched.glo(0); + const auto& plat_group = glo.group("PLAT-A"); + BOOST_CHECK_EQUAL( *plat_group.max_lift_gas(), siFactorG * 200000); + BOOST_CHECK(!plat_group.max_total_gas().has_value()); + + + const auto& w1 = glo.well("B-1H"); + BOOST_CHECK(w1.use_glo()); + BOOST_CHECK_EQUAL(*w1.max_rate(), 150000 * siFactorG); + BOOST_CHECK_EQUAL(w1.weight_factor(), 1.01); + + const auto& w2 = glo.well("C-2H"); + BOOST_CHECK_EQUAL(w2.weight_factor(), 1.00); + BOOST_CHECK_EQUAL(w2.min_rate(), 0.00); + BOOST_CHECK_EQUAL(w2.inc_weight_factor(), 0.00); + BOOST_CHECK(!w2.alloc_extra_gas()); + + const auto& w3 = glo.well("C-1H"); + BOOST_CHECK_EQUAL(w3.min_rate(), -1.00 * siFactorG); + BOOST_CHECK_EQUAL(w3.inc_weight_factor(), 1.00); + BOOST_CHECK(w3.alloc_extra_gas()); +} +