Merge pull request #208 from AtleH/wellnamewithwildcard

Added wildcard support in WCONINJE and WCONPROD
This commit is contained in:
Kristian Flikka 2014-05-16 12:28:39 +02:00
commit 82a38c1cc8
8 changed files with 354 additions and 142 deletions

View File

@ -21,7 +21,6 @@
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
@ -171,108 +170,112 @@ namespace Opm {
void Schedule::handleWCONProducer(DeckKeywordConstPtr keyword, size_t currentStep, bool isPredictionMode) {
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& wellName = record->getItem("WELL")->getTrimmedString(0);
WellPtr well = getWell(wellName);
double orat = record->getItem("ORAT")->getSIDouble(0);
double wrat = record->getItem("WRAT")->getSIDouble(0);
double grat = record->getItem("GRAT")->getSIDouble(0);
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
WellProductionProperties properties = well->getProductionPropertiesCopy(currentStep);
well->setStatus( currentStep , status );
{
double liquidRate = 0;
double resVRate = 0;
double BHPLimit = 0;
double THPLimit = 0;
const std::string& wellNamePattern = record->getItem("WELL")->getTrimmedString(0);
std::vector<WellPtr> wells = getWells(wellNamePattern);
if (isPredictionMode) {
liquidRate = record->getItem("LRAT")->getSIDouble(0);
BHPLimit = record->getItem("BHP")->getSIDouble(0);
THPLimit = record->getItem("THP")->getSIDouble(0);
resVRate = record->getItem("RESV")->getSIDouble(0);
}
properties.predictionMode = isPredictionMode;
properties.OilRate = orat;
properties.WaterRate = wrat;
properties.GasRate = grat;
properties.LiquidRate = liquidRate;
properties.ResVRate = resVRate;
properties.BHPLimit = BHPLimit;
properties.THPLimit = THPLimit;
for (auto wellIter=wells.begin(); wellIter != wells.end(); ++wellIter) {
WellPtr well = *wellIter;
double orat = record->getItem("ORAT")->getSIDouble(0);
double wrat = record->getItem("WRAT")->getSIDouble(0);
double grat = record->getItem("GRAT")->getSIDouble(0);
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
WellProductionProperties properties = well->getProductionProperties(currentStep);
if (isPredictionMode) {
if (record->getItem("LRAT")->defaultApplied())
well->setStatus( currentStep , status );
{
double liquidRate = 0;
double resVRate = 0;
double BHPLimit = 0;
double THPLimit = 0;
if (isPredictionMode) {
liquidRate = record->getItem("LRAT")->getSIDouble(0);
BHPLimit = record->getItem("BHP")->getSIDouble(0);
THPLimit = record->getItem("THP")->getSIDouble(0);
resVRate = record->getItem("RESV")->getSIDouble(0);
}
properties.predictionMode = isPredictionMode;
properties.OilRate = orat;
properties.WaterRate = wrat;
properties.GasRate = grat;
properties.LiquidRate = liquidRate;
properties.ResVRate = resVRate;
properties.BHPLimit = BHPLimit;
properties.THPLimit = THPLimit;
if (isPredictionMode) {
if (record->getItem("LRAT")->defaultApplied())
properties.dropProductionControl(WellProducer::LRAT);
else
properties.addProductionControl(WellProducer::LRAT);
if (record->getItem("RESV")->defaultApplied())
properties.dropProductionControl(WellProducer::RESV);
else
properties.addProductionControl(WellProducer::RESV);
if (record->getItem("BHP")->defaultApplied())
properties.dropProductionControl(WellProducer::BHP);
else
properties.addProductionControl(WellProducer::BHP);
if (record->getItem("THP")->defaultApplied())
properties.dropProductionControl(WellProducer::THP);
else
properties.addProductionControl(WellProducer::THP);
} else {
properties.dropProductionControl(WellProducer::LRAT);
else
properties.addProductionControl(WellProducer::LRAT);
if (record->getItem("RESV")->defaultApplied())
properties.dropProductionControl(WellProducer::RESV);
else
properties.addProductionControl(WellProducer::RESV);
if (record->getItem("BHP")->defaultApplied())
properties.dropProductionControl(WellProducer::BHP);
else
properties.addProductionControl(WellProducer::BHP);
if (record->getItem("THP")->defaultApplied())
properties.dropProductionControl(WellProducer::THP);
else
properties.addProductionControl(WellProducer::THP);
} else {
properties.dropProductionControl(WellProducer::LRAT);
properties.dropProductionControl(WellProducer::RESV);
properties.dropProductionControl(WellProducer::BHP);
properties.dropProductionControl(WellProducer::THP);
}
}
}
if (record->getItem("ORAT")->defaultApplied())
properties.dropProductionControl(WellProducer::ORAT);
else
properties.addProductionControl(WellProducer::ORAT);
if (record->getItem("GRAT")->defaultApplied())
properties.dropProductionControl(WellProducer::GRAT);
else
properties.addProductionControl(WellProducer::GRAT);
if (record->getItem("WRAT")->defaultApplied())
properties.dropProductionControl(WellProducer::WRAT);
else
properties.addProductionControl(WellProducer::WRAT);
if (record->getItem("ORAT")->defaultApplied())
properties.dropProductionControl(WellProducer::ORAT);
else
properties.addProductionControl(WellProducer::ORAT);
if (status != WellCommon::SHUT) {
const std::string& cmodeString = record->getItem("CMODE")->getTrimmedString(0);
WellProducer::ControlModeEnum control = WellProducer::ControlModeFromString( cmodeString );
if (properties.hasProductionControl( control))
properties.controlMode = control;
else {
/*
This is an awkward situation. The current control mode variable
points to a control which has not been specified in the deck; i.e. a
situation like this:
if (record->getItem("GRAT")->defaultApplied())
properties.dropProductionControl(WellProducer::GRAT);
else
properties.addProductionControl(WellProducer::GRAT);
WCONHIST
'WELL' 'OPEN' 'RESV' 0.000 0.000 0.000 5* /
/
We have specified that the well should be controlled with 'RESV'
mode, but actual RESV value has been defaulted. ECLIPSE seems to
handle this, but the well machinery in OPM-Core keeps close track of
which controls are available, i.e. have a value set, and will be
confused by this. We therefor throw here; the fix is to modify the
deck to set an explicit value for the defaulted control, or
alternatively change control mode.
*/
throw std::invalid_argument("Tried to set invalid control: " + cmodeString + " for well: " + wellName);
if (record->getItem("WRAT")->defaultApplied())
properties.dropProductionControl(WellProducer::WRAT);
else
properties.addProductionControl(WellProducer::WRAT);
if (status != WellCommon::SHUT) {
const std::string& cmodeString = record->getItem("CMODE")->getTrimmedString(0);
WellProducer::ControlModeEnum control = WellProducer::ControlModeFromString( cmodeString );
if (properties.hasProductionControl( control))
properties.controlMode = control;
else {
/*
This is an awkward situation. The current control mode variable
points to a control which has not been specified in the deck; i.e. a
situation like this:
WCONHIST
'WELL' 'OPEN' 'RESV' 0.000 0.000 0.000 5* /
/
We have specified that the well should be controlled with 'RESV'
mode, but actual RESV value has been defaulted. ECLIPSE seems to
handle this, but the well machinery in OPM-Core keeps close track of
which controls are available, i.e. have a value set, and will be
confused by this. We therefor throw here; the fix is to modify the
deck to set an explicit value for the defaulted control, or
alternatively change control mode.
*/
throw std::invalid_argument("Tried to set invalid control: " + cmodeString + " for well: " + wellNamePattern);
}
}
}
well->setProductionProperties(currentStep, properties);
well->setProductionProperties(currentStep, properties);
}
}
}
@ -287,60 +290,63 @@ namespace Opm {
void Schedule::handleWCONINJE(DeckConstPtr deck, DeckKeywordConstPtr keyword, size_t currentStep) {
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& wellName = record->getItem("WELL")->getTrimmedString(0);
WellPtr well = getWell(wellName);
const std::string& wellNamePattern = record->getItem("WELL")->getTrimmedString(0);
std::vector<WellPtr> wells = getWells(wellNamePattern);
// calculate the injection rates. These are context
// dependent, so we have to jump through some hoops
// here...
WellInjector::TypeEnum injectorType = WellInjector::TypeFromString( record->getItem("TYPE")->getTrimmedString(0) );
double surfaceInjectionRate = record->getItem("RATE")->getRawDouble(0);
double reservoirInjectionRate = record->getItem("RESV")->getRawDouble(0);
surfaceInjectionRate = convertInjectionRateToSI(surfaceInjectionRate, injectorType, *deck->getActiveUnitSystem());
reservoirInjectionRate = convertInjectionRateToSI(reservoirInjectionRate, injectorType, *deck->getActiveUnitSystem());
for (auto wellIter=wells.begin(); wellIter != wells.end(); ++wellIter) {
WellPtr well = *wellIter;
// calculate the injection rates. These are context
// dependent, so we have to jump through some hoops
// here...
WellInjector::TypeEnum injectorType = WellInjector::TypeFromString( record->getItem("TYPE")->getTrimmedString(0) );
double surfaceInjectionRate = record->getItem("RATE")->getRawDouble(0);
double reservoirInjectionRate = record->getItem("RESV")->getRawDouble(0);
surfaceInjectionRate = convertInjectionRateToSI(surfaceInjectionRate, injectorType, *deck->getActiveUnitSystem());
reservoirInjectionRate = convertInjectionRateToSI(reservoirInjectionRate, injectorType, *deck->getActiveUnitSystem());
double BHPLimit = record->getItem("BHP")->getSIDouble(0);
double THPLimit = record->getItem("THP")->getSIDouble(0);
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
well->setStatus( currentStep , status );
WellInjectionProperties properties(well->getInjectionPropertiesCopy(currentStep));
properties.surfaceInjectionRate = surfaceInjectionRate;
properties.reservoirInjectionRate = reservoirInjectionRate;
properties.BHPLimit = BHPLimit;
properties.THPLimit = THPLimit;
properties.injectorType = injectorType;
properties.predictionMode = true;
if (record->getItem("RATE")->defaultApplied())
properties.dropInjectionControl(WellInjector::RATE);
else
properties.addInjectionControl(WellInjector::RATE);
double BHPLimit = record->getItem("BHP")->getSIDouble(0);
double THPLimit = record->getItem("THP")->getSIDouble(0);
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
if (record->getItem("RESV")->defaultApplied())
properties.dropInjectionControl(WellInjector::RESV);
else
properties.addInjectionControl(WellInjector::RESV);
well->setStatus( currentStep , status );
WellInjectionProperties properties(well->getInjectionPropertiesCopy(currentStep));
properties.surfaceInjectionRate = surfaceInjectionRate;
properties.reservoirInjectionRate = reservoirInjectionRate;
properties.BHPLimit = BHPLimit;
properties.THPLimit = THPLimit;
properties.injectorType = injectorType;
properties.predictionMode = true;
if (record->getItem("THP")->defaultApplied())
properties.dropInjectionControl(WellInjector::THP);
else
properties.addInjectionControl(WellInjector::THP);
if (record->getItem("RATE")->defaultApplied())
properties.dropInjectionControl(WellInjector::RATE);
else
properties.addInjectionControl(WellInjector::RATE);
if (record->getItem("BHP")->defaultApplied())
properties.dropInjectionControl(WellInjector::BHP);
else
properties.addInjectionControl(WellInjector::BHP);
{
const std::string& cmodeString = record->getItem("CMODE")->getTrimmedString(0);
WellInjector::ControlModeEnum controlMode = WellInjector::ControlModeFromString( cmodeString );
if (properties.hasInjectionControl( controlMode))
properties.controlMode = controlMode;
else {
throw std::invalid_argument("Tried to set invalid control: " + cmodeString + " for well: " + wellName);
if (record->getItem("RESV")->defaultApplied())
properties.dropInjectionControl(WellInjector::RESV);
else
properties.addInjectionControl(WellInjector::RESV);
if (record->getItem("THP")->defaultApplied())
properties.dropInjectionControl(WellInjector::THP);
else
properties.addInjectionControl(WellInjector::THP);
if (record->getItem("BHP")->defaultApplied())
properties.dropInjectionControl(WellInjector::BHP);
else
properties.addInjectionControl(WellInjector::BHP);
{
const std::string& cmodeString = record->getItem("CMODE")->getTrimmedString(0);
WellInjector::ControlModeEnum controlMode = WellInjector::ControlModeFromString( cmodeString );
if (properties.hasInjectionControl( controlMode))
properties.controlMode = controlMode;
else {
throw std::invalid_argument("Tried to set invalid control: " + cmodeString + " for well: " + wellNamePattern);
}
}
well->setInjectionProperties(currentStep, properties);
}
well->setInjectionProperties(currentStep, properties);
}
}
@ -540,6 +546,23 @@ namespace Opm {
return wells;
}
std::vector<WellPtr> Schedule::getWells(const std::string& wellNamePattern) const {
std::vector<WellPtr> wells;
size_t wildcard_pos = wellNamePattern.find("*");
if (wildcard_pos == wellNamePattern.length()-1) {
for (auto wellIter = m_wells.begin(); wellIter != m_wells.end(); ++wellIter) {
WellPtr well = (*wellIter).second;
if (wellNamePattern.compare (0, wildcard_pos, well->name(), 0, wildcard_pos) == 0) {
wells.push_back (well);
}
}
}
else {
wells.push_back(getWell(wellNamePattern));
}
return wells;
}
void Schedule::addGroup(const std::string& groupName, size_t timeStep) {
if (!m_timeMap) {
throw std::invalid_argument("TimeMap is null, can't add group named: " + groupName);

View File

@ -49,6 +49,7 @@ namespace Opm
WellPtr getWell(const std::string& wellName) const;
std::vector<WellConstPtr> getWells() const;
std::vector<WellConstPtr> getWells(size_t timeStep) const;
std::vector<WellPtr> getWells(const std::string& wellNamePattern) const;
GroupTreePtr getGroupTree(size_t t) const;
size_t numGroups() const;

View File

@ -62,7 +62,7 @@ static DeckPtr createDeckWithWells() {
" 10 AUG 2007 / \n"
"/\n"
"WELSPECS\n"
" \'W_2\' \'OP\' 30 37 3.33 \'OIL\' 7* / \n"
" \'WX2\' \'OP\' 30 37 3.33 \'OIL\' 7* / \n"
" \'W_3\' \'OP\' 20 51 3.92 \'OIL\' 7* / \n"
"/\n";
@ -204,3 +204,22 @@ BOOST_AUTO_TEST_CASE(WellsIterator_HasWells_WellsReturned) {
}
BOOST_AUTO_TEST_CASE(WellsIteratorWithRegex_HasWells_WellsReturned) {
DeckPtr deck = createDeckWithWells();
Schedule schedule(deck);
std::string wellNamePattern;
std::vector<WellPtr> wells;
wellNamePattern = "*";
wells = schedule.getWells(wellNamePattern);
BOOST_CHECK_EQUAL(3U, wells.size());
wellNamePattern = "W_*";
wells = schedule.getWells(wellNamePattern);
BOOST_CHECK_EQUAL(2U, wells.size());
wellNamePattern = "W_3";
wells = schedule.getWells(wellNamePattern);
BOOST_CHECK_EQUAL(1U, wells.size());
}

View File

@ -14,6 +14,10 @@ add_executable(runParseWCONHIST ParseWCONHIST.cpp)
target_link_libraries(runParseWCONHIST Parser ${Boost_LIBRARIES})
add_test(NAME runParseWCONHIST WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} COMMAND ${TEST_MEMCHECK_TOOL} ${EXECUTABLE_OUTPUT_PATH}/runParseWCONHIST)
add_executable(runParseWellWithWildcards ParseWellWithWildcards.cpp)
target_link_libraries(runParseWellWithWildcards Parser ${Boost_LIBRARIES})
add_test(NAME runParseWellWithWildcards WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} COMMAND ${TEST_MEMCHECK_TOOL} ${EXECUTABLE_OUTPUT_PATH}/runParseWellWithWildcards)
add_executable(runParsePORO ParsePORO.cpp)
target_link_libraries(runParsePORO Parser ${Boost_LIBRARIES})
add_test(NAME runParsePORO WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} COMMAND ${TEST_MEMCHECK_TOOL} ${EXECUTABLE_OUTPUT_PATH}/runParsePORO)

View File

@ -0,0 +1,104 @@
/*
Copyright 2013 Statoil 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 <http://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE ParserIntegrationTests
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/parser/eclipse/Parser/ParserIntItem.hpp>
#include <opm/parser/eclipse/Parser/ParserStringItem.hpp>
#include <opm/parser/eclipse/Parser/ParserEnums.hpp>
#include <opm/parser/eclipse/Units/ConversionFactors.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
using namespace Opm;
BOOST_AUTO_TEST_CASE( parse_WCONPROD_OK ) {
ParserPtr parser(new Parser());
boost::filesystem::path wconprodFile("testdata/integration_tests/WellWithWildcards/WCONPROD1");
DeckPtr deck = parser->parseFile(wconprodFile.string());
ScheduleConstPtr sched(new Schedule(deck));
BOOST_CHECK_EQUAL(5U, sched->numWells());
BOOST_CHECK(sched->hasWell("INJE1"));
BOOST_CHECK(sched->hasWell("PROD2"));
BOOST_CHECK(sched->hasWell("PROD3"));
BOOST_CHECK(sched->hasWell("PROD4"));
BOOST_CHECK(sched->hasWell("PROX5"));
{
WellPtr well = sched->getWell("PROD2");
BOOST_CHECK_CLOSE(1000/Metric::Time, well->getProductionProperties(0).OilRate, 0.001);
BOOST_CHECK_CLOSE(1500/Metric::Time, well->getProductionProperties(1).OilRate, 0.001);
}
{
WellPtr well = sched->getWell("PROD3");
BOOST_CHECK_CLOSE(0/Metric::Time, well->getProductionProperties(0).OilRate, 0.001);
BOOST_CHECK_CLOSE(1500/Metric::Time, well->getProductionProperties(1).OilRate, 0.001);
}
{
WellPtr well = sched->getWell("PROX5");
BOOST_CHECK_CLOSE(2000/Metric::Time, well->getProductionProperties(0).OilRate, 0.001);
BOOST_CHECK_CLOSE(2000/Metric::Time, well->getProductionProperties(1).OilRate, 0.001);
}
}
BOOST_AUTO_TEST_CASE( parse_WCONINJE_OK ) {
ParserPtr parser(new Parser());
boost::filesystem::path wconprodFile("testdata/integration_tests/WellWithWildcards/WCONINJE1");
DeckPtr deck = parser->parseFile(wconprodFile.string());
ScheduleConstPtr sched(new Schedule(deck));
BOOST_CHECK_EQUAL(5U, sched->numWells());
BOOST_CHECK(sched->hasWell("PROD1"));
BOOST_CHECK(sched->hasWell("INJE2"));
BOOST_CHECK(sched->hasWell("INJE3"));
BOOST_CHECK(sched->hasWell("PROD4"));
BOOST_CHECK(sched->hasWell("INJX5"));
{
WellPtr well = sched->getWell("INJE2");
BOOST_CHECK_CLOSE(1000/Metric::Time, well->getInjectionProperties(0).surfaceInjectionRate, 0.001);
BOOST_CHECK_CLOSE(1500/Metric::Time, well->getInjectionProperties(1).surfaceInjectionRate, 0.001);
}
{
WellPtr well = sched->getWell("INJE3");
BOOST_CHECK_CLOSE(0/Metric::Time, well->getInjectionProperties(0).surfaceInjectionRate, 0.001);
BOOST_CHECK_CLOSE(1500/Metric::Time, well->getInjectionProperties(1).surfaceInjectionRate, 0.001);
}
{
WellPtr well = sched->getWell("INJX5");
BOOST_CHECK_CLOSE(2000/Metric::Time, well->getInjectionProperties(0).surfaceInjectionRate, 0.001);
BOOST_CHECK_CLOSE(2000/Metric::Time, well->getInjectionProperties(1).surfaceInjectionRate, 0.001);
}
}

View File

@ -28,10 +28,19 @@
namespace Opm {
bool tokenContainsStar(const std::string& token) {
if (token.find('*') == std::string::npos)
size_t pos = token.find('*');
if (pos == std::string::npos)
return false;
else
return true;
else {
if (pos == 0) return true;
try {
boost::lexical_cast<int>(token.substr(0, pos));
return true;
}
catch (boost::bad_lexical_cast&) {
return false;
}
}
}

View File

@ -0,0 +1,26 @@
START
10 MAI 2007 /
SCHEDULE
WELSPECS
-- Well specification data
'PROD1' 'P' 11 3 9110 'OIL' /
'INJE2' 'I' 24 25 9110 'WATER' /
'INJE3' 'I' 24 25 9110 'WATER' /
'PROD4' 'P' 11 3 9110 'OIL' /
'INJX5' 'I' 10 4 9110 'WATER' /
/
WCONINJE
'INJE2' 'WATER' 'OPEN' 'RATE' 1000 4* 1000 /
'INJX5' 'WATER' 'OPEN' 'RATE' 2000 4* 1000 /
/
TSTEP
10 /
WCONINJE
'INJE*' 'WATER' 'OPEN' 'RATE' 1500 4* 1000 /
/

View File

@ -0,0 +1,26 @@
START
10 MAI 2007 /
SCHEDULE
WELSPECS
-- Well specification data
'INJE1' 'I' 24 25 9110 'WATER' /
'PROD2' 'P' 5 1 9110 'OIL' /
'PROD3' 'P' 8 2 9110 'OIL' /
'PROD4' 'P' 11 3 9110 'OIL' /
'PROX5' 'P' 10 4 9110 'OIL' /
/
WCONPROD
'PROD2' 'OPEN' 'ORAT' 1000 4* 1000 /
'PROX5' 'OPEN' 'ORAT' 2000 4* 1000 /
/
TSTEP
10 /
WCONPROD
'PROD*' 'OPEN' 'ORAT' 1500 4* 1000 /
/