/* Copyright (c) 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 . */ #define BOOST_TEST_MODULE test_GuideRate #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { struct Setup { explicit Setup(const std::string& input) : Setup { Opm::Parser{}.parseString(input) } {} explicit Setup(const Opm::Deck& deck) : es { deck } , sched { deck, es, std::make_shared() } , gr { sched } {} Opm::EclipseState es; Opm::Schedule sched; Opm::GuideRate gr; }; Setup case_10x10x10_model4(const double damping_factor = 0.5) { const auto prolog = std::string { R"(RUNSPEC START 4 'AUG' 2020 / TITLE Check GUIDERAT Formula Implementation DIMENS 10 10 10 / OIL GAS WATER DISGAS VAPOIL METRIC TABDIMS / WELLDIMS 3 10 2 2 / GRID DXV 10*100 / DYV 10*100 / DZV 10*5 / DEPTHZ 121*2000 / PERMX 1000*100 / COPY PERMX PERMY / PERMX PERMZ / / MULTIPLY PERMZ 0.1 / / PORO 1000*0.3 / SOLUTION PRESSURE 1000*320 / SOIL 1000*0.85 / SWAT 1000*0.12 / SGAS 1000*0.03 / RS 1000*226.0 / RV 1000*0.0 / SCHEDULE WELSPECS P1 P 10 7 2002.5 OIL / P2 P 7 10 2002.5 OIL / I1 I 2 2 2002.5 GAS / / COMPDAT P1 2* 1 10 OPEN 1* 1* 0.5 / P2 2* 1 10 OPEN 1* 1* 0.5 / I1 2* 1 10 OPEN 1* 1* 0.5 / / WCONINJE 'I1' 'GAS' 'OPEN' 'RATE' 200 1* 450.0 / / )" }; const auto guiderat = std::string { R"( -- GR_{oil} = WOPP / (0.5 + (WWPP / WOPP)) -- with a user-specified damping/time-delay factor (default 0.5). GUIDERAT --1 2 3 4 5 6 7 8 9 10 1.0 OIL 1.0 0.5 1.0 1.0 1* 1* YES )" } + std::to_string(damping_factor) + " /\n"; const auto epilog = std::string { R"( WCONPROD P* OPEN GRUP 150 100 15E+3 250 1* 50 25 / / WCONINJE I1 GAS OPEN RATE 20.0E+3 1* 500 350 / / GCONPROD P 'ORAT' 200.0 150.0 100.0E+3 1* 1* YES 1* FORM / / DATES 5 'AUG' 2020 / 10 'AUG' 2020 / 20 'AUG' 2020 / 1 'SEP' 2020 / 1 'OCT' 2020 / 1 'NOV' 2020 / 1 'DEC' 2020 / 1 'JAN' 2021 / / END )" }; return Setup { prolog + guiderat + epilog }; } } // Namespace anonymous // ====================================================================== BOOST_AUTO_TEST_SUITE(GuideRate_Calculations) BOOST_AUTO_TEST_CASE(P1_First) { auto cse = case_10x10x10_model4(); const auto wopp = 1.0; const auto wgpp = 5.0; const auto wwpp = 0.1; const auto stm = 0.0; const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P1", rpt, stm, wopp, wgpp, wwpp); const auto orat = 2.0; const auto grat = 4.0; // == 2 * orat const auto wrat = 1.0; // == orat / 2 const auto expect_gr_oil = 1.0 / (0.5 + 0.1/1.0); // wopp / (0.5 + wwpp/wopp) // GR_{oil} { const auto grval = cse.gr.get("P1", Opm::Well::GuideRateTarget::OIL, { orat, grat, wrat }); BOOST_CHECK_CLOSE(grval, expect_gr_oil, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P1", Opm::Well::GuideRateTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * expect_gr_oil; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P1", Opm::Well::GuideRateTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * expect_gr_oil; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } } BOOST_AUTO_TEST_CASE(P2_Second) { auto cse = case_10x10x10_model4(); { const auto wopp = 1.0; const auto wgpp = 5.0; const auto wwpp = 0.1; const auto stm = 0.0; const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P2", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 10.0; const auto wgpp = 50.0; const auto wwpp = 1.0; const auto stm = 10.0*Opm::unit::second; // Before recalculation delay const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P2", rpt, stm, wopp, wgpp, wwpp); } const auto orat = 2.0; const auto grat = 4.0; // == 2 * orat const auto wrat = 1.0; // == orat / 2 const auto expect_gr_oil_1 = 1.0 / (0.5 + 0.1/1.0); // wopp_1 / (0.5 + wwpp_1/wopp_1) // GR_{oil} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::OIL, { orat, grat, wrat }); BOOST_CHECK_CLOSE(grval, expect_gr_oil_1, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } { const auto wopp = 10.0; const auto wgpp = 50.0; const auto wwpp = 1.0; const auto stm = 10.0*Opm::unit::day; // After recalculation delay const auto rpt = size_t{3}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P2", rpt, stm, wopp, wgpp, wwpp); } const auto expect_gr_oil_2 = 10.0 / (0.5 + 1.0/10.0); // wopp_2 / (0.5 + wwpp_2/wopp_2) // GR_{oil} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::OIL, { orat, grat, wrat }); const auto expect = 0.5*expect_gr_oil_2 + 0.5*expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * (0.5*expect_gr_oil_2 + 0.5*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P2", Opm::Well::GuideRateTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * (0.5*expect_gr_oil_2 + 0.5*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } } BOOST_AUTO_TEST_CASE(P_Third) { auto cse = case_10x10x10_model4(); { const auto wopp = 1.0; const auto wgpp = 5.0; const auto wwpp = 0.1; const auto stm = 0.0; const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 10.0; const auto wgpp = 50.0; const auto wwpp = 1.0; const auto stm = 10.0*Opm::unit::day; const auto rpt = size_t{3}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 20.0; const auto wgpp = 100.0; const auto wwpp = 10.0; const auto stm = 20.0*Opm::unit::day; const auto rpt = size_t{4}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } const auto expect_gr_oil_1 = 1.0 / (0.5 + 0.1/ 1.0); // wopp_1 / (0.5 + wwpp_1/wopp_1) const auto expect_gr_oil_2 = 10.0 / (0.5 + 1.0/10.0); // wopp_2 / (0.5 + wwpp_2/wopp_2) const auto expect_gr_oil_3 = 20.0 / (0.5 + 10.0/20.0); // wopp_3 / (0.5 + wwpp_3/wopp_3) const auto orat = 2.0; const auto grat = 4.0; // == 2 * orat const auto wrat = 1.0; // == orat / 2 // GR_{oil} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::OIL, { orat, grat, wrat }); const auto expect = 0.5*expect_gr_oil_3 + 0.5*0.5*expect_gr_oil_2 + 0.5*0.5*expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * (0.5*expect_gr_oil_3 + 0.5*0.5*expect_gr_oil_2 + 0.5*0.5*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * (0.5*expect_gr_oil_3 + 0.5*0.5*expect_gr_oil_2 + 0.5*0.5*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } } BOOST_AUTO_TEST_CASE(P_Third_df01) { auto cse = case_10x10x10_model4(0.1); { const auto wopp = 1.0; const auto wgpp = 5.0; const auto wwpp = 0.1; const auto stm = 0.0; const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 10.0; const auto wgpp = 50.0; const auto wwpp = 1.0; const auto stm = 10.0*Opm::unit::day; const auto rpt = size_t{3}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 20.0; const auto wgpp = 100.0; const auto wwpp = 10.0; const auto stm = 20.0*Opm::unit::day; const auto rpt = size_t{4}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } const auto expect_gr_oil_1 = 1.0 / (0.5 + 0.1/ 1.0); // wopp_1 / (0.5 + wwpp_1/wopp_1) const auto expect_gr_oil_2 = 10.0 / (0.5 + 1.0/10.0); // wopp_2 / (0.5 + wwpp_2/wopp_2) const auto expect_gr_oil_3 = 20.0 / (0.5 + 10.0/20.0); // wopp_3 / (0.5 + wwpp_3/wopp_3) const auto orat = 2.0; const auto grat = 4.0; // == 2 * orat const auto wrat = 1.0; // == orat / 2 // GR_{oil} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::OIL, { orat, grat, wrat }); const auto expect = 0.1*expect_gr_oil_3 + 0.1*0.9*expect_gr_oil_2 + 0.9*0.9*expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * (0.1*expect_gr_oil_3 + 0.1*0.9*expect_gr_oil_2 + 0.9*0.9*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * (0.1*expect_gr_oil_3 + 0.1*0.9*expect_gr_oil_2 + 0.9*0.9*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } } BOOST_AUTO_TEST_CASE(P_Third_df09) { auto cse = case_10x10x10_model4(0.9); { const auto wopp = 1.0; const auto wgpp = 5.0; const auto wwpp = 0.1; const auto stm = 0.0; const auto rpt = size_t{1}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 10.0; const auto wgpp = 50.0; const auto wwpp = 1.0; const auto stm = 10.0*Opm::unit::day; const auto rpt = size_t{3}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } { const auto wopp = 20.0; const auto wgpp = 100.0; const auto wwpp = 10.0; const auto stm = 20.0*Opm::unit::day; const auto rpt = size_t{4}; cse.gr.updateGuideRateExpiration(stm, rpt); cse.gr.compute("P", rpt, stm, wopp, wgpp, wwpp); } const auto expect_gr_oil_1 = 1.0 / (0.5 + 0.1/ 1.0); // wopp_1 / (0.5 + wwpp_1/wopp_1) const auto expect_gr_oil_2 = 10.0 / (0.5 + 1.0/10.0); // wopp_2 / (0.5 + wwpp_2/wopp_2) const auto expect_gr_oil_3 = 20.0 / (0.5 + 10.0/20.0); // wopp_3 / (0.5 + wwpp_3/wopp_3) const auto orat = 2.0; const auto grat = 4.0; // == 2 * orat const auto wrat = 1.0; // == orat / 2 // GR_{oil} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::OIL, { orat, grat, wrat }); const auto expect = 0.9*expect_gr_oil_3 + 0.9*0.1*expect_gr_oil_2 + 0.1*0.1*expect_gr_oil_1; BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{gas} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::GAS, { orat, grat, wrat }); const auto expect = (grat / orat) * (0.9*expect_gr_oil_3 + 0.9*0.1*expect_gr_oil_2 + 0.1*0.1*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } // GR_{water} { const auto grval = cse.gr.get("P", Opm::Group::GuideRateProdTarget::WAT, { orat, grat, wrat }); const auto expect = (wrat / orat) * (0.9*expect_gr_oil_3 + 0.9*0.1*expect_gr_oil_2 + 0.1*0.1*expect_gr_oil_1); BOOST_CHECK_CLOSE(grval, expect, 1.0e-5); } const auto& sched = cse.sched; auto wi = sched.getWell("I1", 0); wi.updateWellGuideRate(true, 1.0, Opm::Well::GuideRateTarget::RAT, 1.0); BOOST_CHECK( wi.getGuideRatePhase() == Opm::Well::GuideRateTarget::GAS ); } BOOST_AUTO_TEST_SUITE_END() // GuideRate_Calculations