// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* 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 . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ #include "config.h" #define BOOST_TEST_MODULE EclOutput #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_DUNE_FEM #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #if BOOST_VERSION / 100000 == 1 && BOOST_VERSION / 100 % 1000 < 71 #include #else #include #endif namespace Opm::Properties { namespace TTag { struct TestEclOutputTypeTag { using InheritsFrom = std::tuple; }; } template struct EnableTerminalOutput { static constexpr bool value = true; }; template struct EnableGravity { static constexpr bool value = false; }; template struct EnableAsyncEclOutput { static constexpr bool value = false; }; template struct EclWellModel { using type = BlackoilWellModel; }; } // namespace Opm::Properties namespace { std::unique_ptr readsum(const std::string& base) { return std::make_unique(base); } double ecl_sum_get_field_var(const Opm::EclIO::ESmry* smry, const int timeIdx, const std::string& var) { return smry->get(var)[timeIdx]; } double ecl_sum_get_general_var(const Opm::EclIO::ESmry* smry, const int timeIdx, const std::string& var) { return smry->get(var)[timeIdx]; } template std::unique_ptr> initSimulator(const char *filename) { using Simulator = Opm::GetPropType; std::string filenameArg = "--ecl-deck-file-name="; filenameArg += filename; const char* argv[] = { "test_equil", filenameArg.c_str() }; Opm::setupParameters_(/*argc=*/sizeof(argv)/sizeof(argv[0]), argv, /*registerParams=*/false); return std::unique_ptr(new Simulator); } struct EclOutputFixture { EclOutputFixture () { int argc = boost::unit_test::framework::master_test_suite().argc; char** argv = boost::unit_test::framework::master_test_suite().argv; #if HAVE_DUNE_FEM Dune::Fem::MPIManager::initialize(argc, argv); #else Dune::MPIHelper::instance(argc, argv); #endif Opm::EclGenericVanguard::setCommunication(std::make_unique()); using TypeTag = Opm::Properties::TTag::TestEclOutputTypeTag; Opm::BlackoilModelParametersEbos::registerParameters(); Opm::Parameters::registerParam("EnableTerminalOutput", "EnableTerminalOutput", Opm::getPropValue(), "Dummy added for the well model to compile."); Opm::registerAllParameters_(); } }; } BOOST_GLOBAL_FIXTURE(EclOutputFixture); BOOST_AUTO_TEST_CASE(Summary) { using TypeTag = Opm::Properties::TTag::TestEclOutputTypeTag; const std::string filename = "SUMMARY_DECK_NON_CONSTANT_POROSITY.DATA"; const std::string casename = "SUMMARY_DECK_NON_CONSTANT_POROSITY"; auto simulator = initSimulator(filename.data()); using Grid = Opm::GetPropType; using EquilGrid = Opm::GetPropType; using GridView = Opm::GetPropType; using CollectDataToIORankType = Opm::CollectDataToIORank; CollectDataToIORankType collectToIORank(simulator->vanguard().grid(), &simulator->vanguard().equilGrid(), simulator->vanguard().gridView(), simulator->vanguard().cartesianIndexMapper(), &simulator->vanguard().equilCartesianIndexMapper()); Opm::EclOutputBlackOilModule eclOutputModule(*simulator, {}, collectToIORank); typedef Opm::EclWriter EclWriterType; // create the actual ECL writer std::unique_ptr eclWriter = std::unique_ptr(new EclWriterType(*simulator)); simulator->model().applyInitialSolution(); Opm::data::Wells dw; bool substep = false; simulator->startNextEpisode(0.0, 1e30); simulator->setEpisodeIndex(0); eclWriter->evalSummaryState(substep); eclWriter->writeOutput(substep); simulator->setEpisodeIndex(1); eclWriter->evalSummaryState(substep); eclWriter->writeOutput(substep); simulator->setEpisodeIndex(2); eclWriter->evalSummaryState(substep); eclWriter->writeOutput(substep); auto res = readsum( casename ); const auto* resp = res.get(); // fpr = sum_ (p * hcpv ) / hcpv, hcpv = pv * (1 - sw) const double fpr = ( (3 * 0.1 + 8 * 0.2) * 500 * (1 - 0.2) ) / ( (500*0.1 + 500*0.2) * (1 - 0.2)); BOOST_CHECK_CLOSE( fpr, ecl_sum_get_field_var( resp, 1, "FPR" ) , 1e-3 ); // foip = sum_ (b * s * pv), rs == 0; const double foip = ( (0.3 * 0.1 + 0.8 * 0.2) * 500 * (1 - 0.2) ); BOOST_CHECK_CLOSE(foip, ecl_sum_get_field_var( resp, 1, "FOIP" ), 1e-1 ); // fgip = sum_ (b * pv * s), sg == 0; const double fgip = 0.0; BOOST_CHECK_CLOSE(fgip, ecl_sum_get_field_var( resp, 1, "FGIP" ), 1e-1 ); // fgip = sum_ (b * pv * s), const double fwip = 1.0/1000 * ( 0.1 + 0.2) * 500 * 0.2; BOOST_CHECK_CLOSE(fwip, ecl_sum_get_field_var( resp, 1, "FWIP" ), 1e-1 ); // region 1 // rpr = sum_ (p * hcpv ) / hcpv, hcpv = pv * (1 - sw) const double rpr1 = ( 2.5 * 0.1 * 400 * (1 - 0.2) ) / (400*0.1 * (1 - 0.2)); BOOST_CHECK_CLOSE( rpr1, ecl_sum_get_general_var( resp, 1, "RPR:1" ) , 1e-3 ); // roip = sum_ (b * s * pv) // rs == 0; const double roip1 = ( 0.25 * 0.1 * 400 * (1 - 0.2) ); BOOST_CHECK_CLOSE(roip1, ecl_sum_get_general_var( resp, 1, "ROIP:1" ), 1e-1 ); // region 2 // rpr = sum_ (p * hcpv ) / hcpv, hcpv = pv * (1 - sw) const double rpr2 = ( (5 * 0.1 * 100 + 6 * 0.2 * 100) * (1 - 0.2) ) / ( (100*0.1 + 100*0.2) * (1 - 0.2)); BOOST_CHECK_CLOSE( rpr2, ecl_sum_get_general_var( resp, 1, "RPR:2" ) , 1e-3 ); // roip = sum_ (b * s * pv) // rs == 0; const double roip2 = ( (0.5 * 0.1 * 100 + 0.6 * 0.2 * 100) * (1 - 0.2) ); BOOST_CHECK_CLOSE(roip2, ecl_sum_get_general_var( resp, 1, "ROIP:2" ), 1e-1 ); } BOOST_AUTO_TEST_CASE(readWriteWells) { using opt = Opm::data::Rates::opt; Opm::data::Rates r1, r2, rc1, rc2, rc3; r1.set( opt::wat, 5.67 ); r1.set( opt::oil, 6.78 ); r1.set( opt::gas, 7.89 ); r2.set( opt::wat, 8.90 ); r2.set( opt::oil, 9.01 ); r2.set( opt::gas, 10.12 ); rc1.set( opt::wat, 20.41 ); rc1.set( opt::oil, 21.19 ); rc1.set( opt::gas, 22.41 ); rc2.set( opt::wat, 23.19 ); rc2.set( opt::oil, 24.41 ); rc2.set( opt::gas, 25.19 ); rc3.set( opt::wat, 26.41 ); rc3.set( opt::oil, 27.19 ); rc3.set( opt::gas, 28.41 ); Opm::data::Well w1, w2; w1.rates = r1; w1.bhp = 1.23; w1.temperature = 3.45; w1.control = 1; //w1.injectionControl = 1; //w1.productionControl = 1; /* * the connection keys (active indices) and well names correspond to the * input deck. All other entries in the well structures are arbitrary. */ w1.connections.push_back( { 88, rc1, 30.45, 123.45, 0.0, 0.0, 0.0, 0.0, 123.456 } ); w1.connections.push_back( { 288, rc2, 33.19, 67.89, 0.0, 0.0, 0.0, 0.0, 123.456 } ); w2.rates = r2; w2.bhp = 2.34; w2.temperature = 4.56; w2.control = 1; //w1.injectionControl = 2; //w1.productionControl = 2; w2.connections.push_back( { 188, rc3, 36.22, 19.28, 0.0, 0.0, 0.0, 0.0, 123.456 } ); Opm::data::Wells wellRates; wellRates["OP_1"] = w1; wellRates["OP_2"] = w2; typedef Dune :: Point2PointCommunicator< Dune :: SimpleMessageBuffer > P2PCommunicatorType; typedef typename P2PCommunicatorType :: MessageBufferType MessageBufferType; MessageBufferType buffer; wellRates.write(buffer); Opm::data::Wells wellRatesCopy; wellRatesCopy.read(buffer); BOOST_CHECK_EQUAL( wellRatesCopy.get( "OP_1" , opt::wat) , wellRates.get( "OP_1" , opt::wat)); BOOST_CHECK_EQUAL( wellRatesCopy.get( "OP_2" , 188 , opt::wat) , wellRates.get( "OP_2" , 188 , opt::wat)); }