diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index d3b7842f3..aaee42251 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -98,6 +98,7 @@ if(ENABLE_ECL_INPUT) src/opm/parser/eclipse/EclipseState/Schedule/WellEconProductionLimits.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellInjectionProperties.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.cpp + src/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellTestConfig.cpp src/opm/parser/eclipse/EclipseState/Schedule/WellTestState.cpp @@ -237,6 +238,7 @@ if(ENABLE_ECL_INPUT) tests/parser/UnitTests.cpp tests/parser/ValueTests.cpp tests/parser/WellSolventTests.cpp + tests/parser/WellTracerTests.cpp tests/parser/WellTests.cpp tests/parser/WTEST.cpp) endif() @@ -460,6 +462,7 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp opm/parser/eclipse/EclipseState/Schedule/WellEconProductionLimits.hpp opm/parser/eclipse/EclipseState/Schedule/WellPolymerProperties.hpp + opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.hpp opm/parser/eclipse/EclipseState/Schedule/Tuning.hpp opm/parser/eclipse/EclipseState/Schedule/Group.hpp opm/parser/eclipse/EclipseState/Schedule/MessageLimits.hpp diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 5330bdf4f..5bee10644 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -176,6 +176,7 @@ namespace Opm void handleWCONINJE( const SCHEDULESection&, const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWPOLYMER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWSOLVENT( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); + void handleWTRACER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext); void handleWPMITAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext); void handleWSKPTAB( const DeckKeyword& keyword, const size_t currentStep, const ParseContext& parseContext); diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well.hpp index 24fbae731..96d50fafe 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -150,6 +151,9 @@ namespace Opm { WellPolymerProperties getPolymerPropertiesCopy(size_t timeStep) const; const WellPolymerProperties& getPolymerProperties(size_t timeStep) const; + bool setTracerProperties(size_t timeStep , const WellTracerProperties& properties); + const WellTracerProperties& getTracerProperties(size_t timeStep) const; + bool setSolventFraction(size_t timeStep , const double fraction); const double& getSolventFraction(size_t timeStep) const; @@ -222,6 +226,7 @@ namespace Opm { DynamicState< WellPolymerProperties > m_polymerProperties; DynamicState< WellEconProductionLimits > m_econproductionlimits; DynamicState< double > m_solventFraction; + DynamicState< WellTracerProperties > m_tracerProperties; DynamicState< std::string > m_groupName; DynamicState< int > m_rft; DynamicState< int > m_plt; diff --git a/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.hpp b/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.hpp new file mode 100644 index 000000000..1a2450f9d --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.hpp @@ -0,0 +1,45 @@ +/* + Copyright 2018 NORCE. + + 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 WELLTRACERPROPERTIES_HPP_HEADER_INCLUDED +#define WELLTRACERPROPERTIES_HPP_HEADER_INCLUDED +#include +#include +#include + +namespace Opm { + + class WellTracerProperties { + + public: + WellTracerProperties(); + + void setConcentration(const std::string& name, const double& concentration); + double getConcentration(const std::string& name) const; + + bool operator==(const WellTracerProperties& other) const; + bool operator!=(const WellTracerProperties& other) const; + + private: + std::map< std::string, double > m_tracerConcentrations; + }; + +} + +#endif diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 7a408e8e8..2e26dce4b 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -192,6 +192,9 @@ namespace Opm { else if (keyword.name() == "WSOLVENT") handleWSOLVENT(keyword, currentStep, parseContext); + else if (keyword.name() == "WTRACER") + handleWTRACER(keyword, currentStep, parseContext); + else if (keyword.name() == "WTEST") handleWTEST(keyword, currentStep, parseContext); @@ -890,6 +893,26 @@ namespace Opm { } } } + + void Schedule::handleWTRACER( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext) { + + for( const auto& record : keyword ) { + const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); + const auto wells = getWells( wellNamePattern ); + + if (wells.empty()) + invalidNamePattern(wellNamePattern, parseContext, keyword); + + for( auto* well : wells) { + WellTracerProperties wellTracerProperties = well->getTracerProperties( currentStep ); + double tracerConcentration = record.getItem("CONCENTRATION").get< double >(0); + const std::string& tracerName = record.getItem("TRACER").getTrimmedString(0); + wellTracerProperties.setConcentration(tracerName, tracerConcentration); + well->setTracerProperties(currentStep, wellTracerProperties); + + } + } + } void Schedule::handleWTEMP( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext) { for( const auto& record : keyword ) { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well.cpp index 47e75d686..aa8f17a08 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well.cpp @@ -54,6 +54,7 @@ namespace Opm { m_polymerProperties( timeMap, WellPolymerProperties() ), m_econproductionlimits( timeMap, WellEconProductionLimits() ), m_solventFraction( timeMap, 0.0 ), + m_tracerProperties( timeMap, WellTracerProperties() ), m_groupName( timeMap, "" ), m_rft( timeMap, false ), m_plt( timeMap, false ), @@ -208,6 +209,13 @@ namespace Opm { return m_solventFraction.update(timeStep, fraction); } + bool Well::setTracerProperties(size_t timeStep , const WellTracerProperties& newProperties) { + if (isProducer(timeStep)) + throw std::invalid_argument("WTRACER keyword can only be applied to injectors"); + + return m_tracerProperties.update(timeStep, newProperties); + } + bool Well::setEconProductionLimits(const size_t timeStep, const WellEconProductionLimits& productionlimits) { // not sure if this keyword turning a well to be producer. // not sure what will happen if we use this keyword to a injector. @@ -222,6 +230,10 @@ namespace Opm { return m_solventFraction.at(timeStep); } + const WellTracerProperties& Well::getTracerProperties(size_t timeStep) const { + return m_tracerProperties.at(timeStep); + } + bool Well::hasBeenDefined(size_t timeStep) const { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.cpp new file mode 100644 index 000000000..a4fb5e92f --- /dev/null +++ b/src/opm/parser/eclipse/EclipseState/Schedule/WellTracerProperties.cpp @@ -0,0 +1,52 @@ +/* + Copyright 2018 NORCE. + + 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 +#include +#include + +namespace Opm { + + WellTracerProperties::WellTracerProperties() { + } + + bool WellTracerProperties::operator==(const WellTracerProperties& other) const { + if (m_tracerConcentrations == other.m_tracerConcentrations) + return true; + else + return false; + + } + + void WellTracerProperties::setConcentration(const std::string& name, const double& concentration) { + m_tracerConcentrations[name] = concentration; + } + + double WellTracerProperties::getConcentration(const std::string& name) const { + auto it = m_tracerConcentrations.find(name); + if (it == m_tracerConcentrations.end()) + return 0.0; + return it->second; + } + + bool WellTracerProperties::operator!=(const WellTracerProperties& other) const { + return !(*this == other); + } +} diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TBLK b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TBLK new file mode 100644 index 000000000..08a745cde --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TBLK @@ -0,0 +1,6 @@ +{ +"name" : "TBLK", +"deck_name_regex":"TBLK(F|S).{1,3}", +"sections" : ["SOLUTION"], +"data" : {"value_type" : "DOUBLE", "dimension" : "1"} +} diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TVDP b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TVDP index eb58d4509..dc0efd1e3 100644 --- a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TVDP +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/T/TVDP @@ -9,6 +9,6 @@ "name" : "table", "value_type" : "DOUBLE", "size_type" : "ALL", - "dimension" : ["Length" , "ContextDependent"] + "dimension" : ["Length" , "1"] }] } diff --git a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake index 939d55063..b84b45be2 100644 --- a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake +++ b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake @@ -328,6 +328,7 @@ set( keywords 000_Eclipse100/S/SWOF 000_Eclipse100/S/SWU 000_Eclipse100/T/TABDIMS + 000_Eclipse100/T/TBLK 000_Eclipse100/T/TEMP 000_Eclipse100/T/THCONR 000_Eclipse100/T/THERMAL diff --git a/tests/parser/WellTracerTests.cpp b/tests/parser/WellTracerTests.cpp new file mode 100644 index 000000000..63ada06e8 --- /dev/null +++ b/tests/parser/WellTracerTests.cpp @@ -0,0 +1,155 @@ +/* + Copyright 2018 NORCE + + 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 WellTracerTests + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Opm; + +static Deck createDeckWithOutTracer() { + Opm::Parser parser; + std::string input = + "SCHEDULE\n" + "WELSPECS\n" + " 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n" + "/\n" + "COMPDAT\n" + " 'W_1' 2* 1 1 'OPEN' / \n" + "/\n" + "WCONINJE\n" + " 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n"; + + return parser.parseString(input, ParseContext()); +} + + +static Deck createDeckWithDynamicWTRACER() { + Opm::Parser parser; + std::string input = + "START -- 0 \n" + "1 JAN 2000 / \n" + "SCHEDULE\n" + "WELSPECS\n" + " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" + "/\n" + "COMPDAT\n" + " 'W_1' 2* 1 1 'OPEN' / \n" + "/\n" + "WCONINJE\n" + " 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n" + "DATES -- 1\n" + " 1 MAY 2000 / \n" + "/\n" + "WTRACER\n" + " 'W_1' 'I1' 1 / \n " + " 'W_1' 'I2' 1 / \n " + "/\n" + "DATES -- 2, 3\n" + " 1 JUL 2000 / \n" + " 1 AUG 2000 / \n" + "/\n" + "WTRACER\n" + " 'W_1' 'I1' 0 / \n " + "/\n" + "DATES -- 4\n" + " 1 SEP 2000 / \n" + "/\n"; + + return parser.parseString(input, ParseContext()); +} + +static Deck createDeckWithTracerInProducer() { + Opm::Parser parser; + std::string input = + "START -- 0 \n" + "1 JAN 2000 / \n" + "SCHEDULE\n" + "WELSPECS\n" + " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" + "/\n" + "COMPDAT\n" + " 'W_1' 2* 1 1 'OPEN' / \n" + "/\n" + "WCONPROD\n" + "'W_1' 'OPEN' 'ORAT' 20000 4* 1000 /\n" + "WTRACER\n" + " 'W_1' 'I1' 1 / \n " + " 'W_1' 'I2' 1 / \n " + "/\n"; + + return parser.parseString(input, ParseContext()); +} + + +BOOST_AUTO_TEST_CASE(TestNoTracer) { + auto deck = createDeckWithOutTracer(); + EclipseGrid grid(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid); + Runspec runspec ( deck ); + Schedule schedule(deck, grid , eclipseProperties, runspec , ParseContext()); + BOOST_CHECK(!deck.hasKeyword("WTRACER")); +} + + +BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) { + auto deck = createDeckWithDynamicWTRACER(); + EclipseGrid grid(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid); + Runspec runspec ( deck ); + Schedule schedule(deck, grid , eclipseProperties, runspec , ParseContext()); + BOOST_CHECK(deck.hasKeyword("WTRACER")); + const auto& keyword = deck.getKeyword("WTRACER"); + BOOST_CHECK_EQUAL(keyword.size(),1); + const auto& record = keyword.getRecord(0); + const std::string& wellNamesPattern = record.getItem("WELL").getTrimmedString(0); + auto wells_Tracer = schedule.getWellsMatching(wellNamesPattern); + BOOST_CHECK_EQUAL(wellNamesPattern, "W_1"); + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(0).getConcentration("I1"),0); //default 0 + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(0).getConcentration("I2"),0); //default 0 + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(1).getConcentration("I1"),1); + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(2).getConcentration("I1"),1); + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(4).getConcentration("I1"),0); + BOOST_CHECK_EQUAL(wells_Tracer[0]->getTracerProperties(4).getConcentration("I2"),1); +} + + +BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW) { + auto deck = createDeckWithTracerInProducer(); + EclipseGrid grid(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid); + Runspec runspec ( deck ); + + BOOST_CHECK_THROW(Schedule(deck, grid, eclipseProperties, runspec , ParseContext()), std::invalid_argument); +} + diff --git a/tests/parser/data/integration_tests/IOConfig/RPTRST_DECK.DATA b/tests/parser/data/integration_tests/IOConfig/RPTRST_DECK.DATA index b3bcfe75a..007fd12eb 100644 --- a/tests/parser/data/integration_tests/IOConfig/RPTRST_DECK.DATA +++ b/tests/parser/data/integration_tests/IOConfig/RPTRST_DECK.DATA @@ -91,9 +91,6 @@ RPTSCHED DATES 16 'JUL' 1998 / / -WTRACER - 'C-1H' 'SEA' 1.000 1* / -/ RPTSCHED 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -158,18 +155,12 @@ DATES DATES 21 'JAN' 1999 / / -WTRACER - 'C-2H' 'SEA' 1.000 1* / -/ DATES 1 'FEB' 1999 / / DATES 24 'FEB' 1999 / / -WTRACER - 'C-4H' 'SEA' 1.000 1* / -/ DATES 1 'MAR' 1999 / / @@ -209,9 +200,6 @@ DATES DATES 20 'MAY' 1999 / / -WTRACER - 'C-3H' 'SEA' 1.000 1* / -/ DATES 21 'MAY' 1999 / / @@ -245,28 +233,15 @@ DATES DATES 1 'SEP' 1999 / / -WTRACER - 'F-1H' 'SEA' 1.000 1* / -/ DATES 3 'SEP' 1999 / / DATES 21 'SEP' 1999 / / -WTRACER - 'C-1H' 'HTO' 1000.000 1* / - 'C-3H' '4FB' 1000.000 1* / - 'F-1H' 'S36' 98.000 1* / -/ DATES 22 'SEP' 1999 / / -WTRACER - 'C-1H' 'HTO' 0.000 1* / - 'C-3H' '4FB' 0.000 1* / - 'F-1H' 'S36' 0.000 1* / -/ DATES 1 'OCT' 1999 / / @@ -285,9 +260,6 @@ DATES DATES 13 'OCT' 1999 / / -WTRACER - 'F-2H' 'SEA' 1.000 1* / -/ DATES 16 'OCT' 1999 / / @@ -375,19 +347,9 @@ DATES DATES 26 'AUG' 2000 / / -WTRACER - 'C-2H' 'S36' 78.000 1* / - 'C-4H' '2FB' 1000.000 1* / - 'F-2H' 'DFB' 1000.000 1* / -/ DATES 27 'AUG' 2000 / / -WTRACER - 'C-2H' 'S36' 0.000 1* / - 'C-4H' '2FB' 0.000 1* / - 'F-2H' 'DFB' 0.000 1* / -/ DATES 1 'SEP' 2000 / / @@ -403,9 +365,6 @@ DATES DATES 22 'SEP' 2000 / / -WTRACER - 'F-3H' 'SEA' 1.000 1* / -/ DATES 1 'OCT' 2000 / / @@ -509,9 +468,6 @@ DATES DATES 10 'SEP' 2001 / / -WTRACER - 'F-4H' 'SEA' 1.000 1* / -/ DATES 1 'OCT' 2001 / / @@ -545,15 +501,9 @@ RPTSCHED DATES 12 'FEB' 2002 / / -WTRACER - 'F-3H' 'TFB' 1000.000 1* / -/ DATES 13 'FEB' 2002 / / -WTRACER - 'F-3H' 'TFB' 0.000 1* / -/ DATES 1 'MAR' 2002 / / @@ -771,9 +721,6 @@ RPTSCHED DATES 20 'JAN' 2004 / / -WTRACER - 'C-4AH' 'SEA' 1.000 1* / -/ DATES 1 'FEB' 2004 / /