Files
opm-common/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp

601 lines
26 KiB
C++
Raw Normal View History

2013-10-25 17:28:56 +02:00
/*
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/>.
*/
2013-10-25 17:28:56 +02:00
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/TimeMap.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/WellProductionProperties.hpp>
#include <opm/parser/eclipse/Deck/Section.hpp>
2014-02-19 15:43:42 +01:00
#include <boost/algorithm/string.hpp>
2013-10-25 17:28:56 +02:00
Refine semantics of WCONHIST implementation This commit splits Schedule::handleWCONProducer() into those parts that are specific to the individual keywords (WCONHIST/matching and WCONPROD/prediction) and those that are common to both. In particular we introduce two new helper functions matchingProperties() and predictionProperties() of which the first constructs a WellProductionProperties object specific to matching semantics and the latter constructs a similar object specifc to prediction. In the case of WCONHIST, the well always supports component rates at surface conditions ({O,W,G}RAT) as well as liquid rate (LRAT) and (total) reservoir volume rate (RESV). The prediction mode keeps the existing semantics of not supporting control modes for which the values have been defaulted. The final helper, function producerProperties(), dispatches to matchingProperties() or predictionProperties() depending on handleWCONProducer()'s 'isPredictionMode' flag and handles the record properties that are common to both WCONHIST and WCONPROD, including whether or not to assign a new active control mode. The end result is that handleWCONProducer() becomes a loop of keyword data records that 1) Determines the wells affected by a given record 2) Determines whether or not the wells are OPEN 3) Computes control mode properties (producerProperties()) 4) Assigns status and those properties to all affected wells This approach reorders the well loop compared to the previous implementation which computed separate WellProductionProperties for each well.
2014-06-27 00:17:56 +02:00
#include <string>
#include <vector>
2014-02-19 15:43:42 +01:00
namespace Opm {
Schedule::Schedule(DeckConstPtr deck) {
initFromDeck(deck);
}
void Schedule::initFromDeck(DeckConstPtr deck) {
createTimeMap(deck);
addGroup( "FIELD", 0 );
initRootGroupTreeNode(getTimeMap());
iterateScheduleSection(deck);
}
void Schedule::initRootGroupTreeNode(TimeMapConstPtr timeMap) {
m_rootGroupTree.reset(new DynamicState<GroupTreePtr>(timeMap, GroupTreePtr(new GroupTree())));
}
void Schedule::createTimeMap(DeckConstPtr deck) {
boost::posix_time::ptime startTime(defaultStartDate);
if (deck->hasKeyword("START")) {
DeckKeywordConstPtr startKeyword = deck->getKeyword("START");
startTime = TimeMap::timeFromEclipse(startKeyword->getRecord(0));
}
m_timeMap.reset(new TimeMap(startTime));
}
void Schedule::iterateScheduleSection(DeckConstPtr deck) {
size_t currentStep = 0;
for (size_t keywordIdx = 0; keywordIdx < deck->size(); ++keywordIdx) {
DeckKeywordConstPtr keyword = deck->getKeyword(keywordIdx);
if (keyword->name() == "DATES") {
handleDATES(keyword);
currentStep += keyword->size();
}
if (keyword->name() == "TSTEP") {
handleTSTEP(keyword);
currentStep += keyword->getRecord(0)->getItem(0)->size(); // This is a bit weird API.
}
if (keyword->name() == "WELSPECS") {
handleWELSPECS(keyword, currentStep);
}
if (keyword->name() == "WCONHIST")
handleWCONHIST(keyword, currentStep);
if (keyword->name() == "WCONPROD")
handleWCONPROD(keyword, currentStep);
if (keyword->name() == "WCONINJE")
handleWCONINJE(deck, keyword, currentStep);
if (keyword->name() == "WCONINJH")
handleWCONINJH(deck, keyword, currentStep);
if (keyword->name() == "WGRUPCON")
handleWGRUPCON(keyword, currentStep);
if (keyword->name() == "COMPDAT")
handleCOMPDAT(keyword, currentStep);
if (keyword->name() == "WELOPEN")
handleWELOPEN(keyword, currentStep);
if (keyword->name() == "GRUPTREE")
handleGRUPTREE(keyword, currentStep);
if (keyword->name() == "GCONINJE")
handleGCONINJE( deck, keyword , currentStep );
2013-11-20 17:07:49 +01:00
if (keyword->name() == "GCONPROD")
handleGCONPROD( keyword , currentStep );
}
}
void Schedule::handleDATES(DeckKeywordConstPtr keyword) {
m_timeMap->addFromDATESKeyword(keyword);
}
void Schedule::handleTSTEP(DeckKeywordConstPtr keyword) {
m_timeMap->addFromTSTEPKeyword(keyword);
}
bool Schedule::handleGroupFromWELSPECS(const std::string& groupName, GroupTreePtr newTree) const {
bool treeUpdated = false;
if (!newTree->getNode(groupName)) {
treeUpdated = true;
newTree->updateTree(groupName);
}
return treeUpdated;
}
void Schedule::handleWELSPECS(DeckKeywordConstPtr keyword, size_t currentStep) {
bool needNewTree = false;
GroupTreePtr newTree = m_rootGroupTree->get(currentStep)->deepCopy();
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& wellName = record->getItem("WELL")->getTrimmedString(0);
const std::string& groupName = record->getItem("GROUP")->getTrimmedString(0);
if (!hasGroup(groupName)) {
addGroup(groupName , currentStep);
}
if (!hasWell(wellName)) {
addWell(wellName, record, currentStep);
2013-10-25 17:28:56 +02:00
}
WellConstPtr currentWell = getWell(wellName);
checkWELSPECSConsistency(currentWell, record);
addWellToGroup( getGroup(groupName) , getWell(wellName) , currentStep);
bool treeChanged = handleGroupFromWELSPECS(groupName, newTree);
needNewTree = needNewTree || treeChanged;
}
if (needNewTree) {
m_rootGroupTree->add(currentStep, newTree);
}
}
void Schedule::checkWELSPECSConsistency(WellConstPtr well, DeckRecordConstPtr record) const {
if (well->getHeadI() != record->getItem("HEAD_I")->getInt(0) - 1) {
throw std::invalid_argument("Unable process WELSPECS for well " + well->name() + ", HEAD_I deviates from existing value");
}
if (well->getHeadJ() != record->getItem("HEAD_J")->getInt(0) - 1) {
throw std::invalid_argument("Unable process WELSPECS for well " + well->name() + ", HEAD_J deviates from existing value");
}
if (well->getRefDepthDefaulted() != record->getItem("REF_DEPTH")->defaultApplied(0)) {
throw std::invalid_argument("Unable process WELSPECS for well " + well->name() + ", REF_DEPTH defaulted state deviates from existing value");
}
if (!well->getRefDepthDefaulted()) {
if (well->getRefDepth() != record->getItem("REF_DEPTH")->getSIDouble(0)) {
throw std::invalid_argument("Unable process WELSPECS for well " + well->name() + ", REF_DEPTH deviates from existing value");
}
}
}
Refine semantics of WCONHIST implementation This commit splits Schedule::handleWCONProducer() into those parts that are specific to the individual keywords (WCONHIST/matching and WCONPROD/prediction) and those that are common to both. In particular we introduce two new helper functions matchingProperties() and predictionProperties() of which the first constructs a WellProductionProperties object specific to matching semantics and the latter constructs a similar object specifc to prediction. In the case of WCONHIST, the well always supports component rates at surface conditions ({O,W,G}RAT) as well as liquid rate (LRAT) and (total) reservoir volume rate (RESV). The prediction mode keeps the existing semantics of not supporting control modes for which the values have been defaulted. The final helper, function producerProperties(), dispatches to matchingProperties() or predictionProperties() depending on handleWCONProducer()'s 'isPredictionMode' flag and handles the record properties that are common to both WCONHIST and WCONPROD, including whether or not to assign a new active control mode. The end result is that handleWCONProducer() becomes a loop of keyword data records that 1) Determines the wells affected by a given record 2) Determines whether or not the wells are OPEN 3) Computes control mode properties (producerProperties()) 4) Assigns status and those properties to all affected wells This approach reorders the well loop compared to the previous implementation which computed separate WellProductionProperties for each well.
2014-06-27 00:17:56 +02:00
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& wellNamePattern =
record->getItem("WELL")->getTrimmedString(0);
const WellCommon::StatusEnum status =
WellCommon::StatusFromString(record->getItem("STATUS")->getTrimmedString(0));
2014-03-17 15:30:41 +01:00
WellProductionProperties properties =
((isPredictionMode)
? WellProductionProperties::prediction(record)
: WellProductionProperties::history (record));
Refine semantics of WCONHIST implementation This commit splits Schedule::handleWCONProducer() into those parts that are specific to the individual keywords (WCONHIST/matching and WCONPROD/prediction) and those that are common to both. In particular we introduce two new helper functions matchingProperties() and predictionProperties() of which the first constructs a WellProductionProperties object specific to matching semantics and the latter constructs a similar object specifc to prediction. In the case of WCONHIST, the well always supports component rates at surface conditions ({O,W,G}RAT) as well as liquid rate (LRAT) and (total) reservoir volume rate (RESV). The prediction mode keeps the existing semantics of not supporting control modes for which the values have been defaulted. The final helper, function producerProperties(), dispatches to matchingProperties() or predictionProperties() depending on handleWCONProducer()'s 'isPredictionMode' flag and handles the record properties that are common to both WCONHIST and WCONPROD, including whether or not to assign a new active control mode. The end result is that handleWCONProducer() becomes a loop of keyword data records that 1) Determines the wells affected by a given record 2) Determines whether or not the wells are OPEN 3) Computes control mode properties (producerProperties()) 4) Assigns status and those properties to all affected wells This approach reorders the well loop compared to the previous implementation which computed separate WellProductionProperties for each well.
2014-06-27 00:17:56 +02:00
const std::vector<WellPtr>& wells = getWells(wellNamePattern);
for (auto wellIter=wells.begin(); wellIter != wells.end(); ++wellIter) {
WellPtr well = *wellIter;
if (well->isAvailableForGroupControl(currentStep)) {
properties.addProductionControl(WellProducer::GRUP);
}
else {
properties.dropProductionControl(WellProducer::GRUP);
}
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 {
throw std::invalid_argument("Tried to set invalid control: " +
cmodeString + " for well: " +
wellNamePattern);
}
}
Refine semantics of WCONHIST implementation This commit splits Schedule::handleWCONProducer() into those parts that are specific to the individual keywords (WCONHIST/matching and WCONPROD/prediction) and those that are common to both. In particular we introduce two new helper functions matchingProperties() and predictionProperties() of which the first constructs a WellProductionProperties object specific to matching semantics and the latter constructs a similar object specifc to prediction. In the case of WCONHIST, the well always supports component rates at surface conditions ({O,W,G}RAT) as well as liquid rate (LRAT) and (total) reservoir volume rate (RESV). The prediction mode keeps the existing semantics of not supporting control modes for which the values have been defaulted. The final helper, function producerProperties(), dispatches to matchingProperties() or predictionProperties() depending on handleWCONProducer()'s 'isPredictionMode' flag and handles the record properties that are common to both WCONHIST and WCONPROD, including whether or not to assign a new active control mode. The end result is that handleWCONProducer() becomes a loop of keyword data records that 1) Determines the wells affected by a given record 2) Determines whether or not the wells are OPEN 3) Computes control mode properties (producerProperties()) 4) Assigns status and those properties to all affected wells This approach reorders the well loop compared to the previous implementation which computed separate WellProductionProperties for each well.
2014-06-27 00:17:56 +02:00
well->setStatus( currentStep , status );
well->setProductionProperties(currentStep, properties);
}
}
2013-10-25 17:28:56 +02:00
}
void Schedule::handleWCONHIST(DeckKeywordConstPtr keyword, size_t currentStep) {
handleWCONProducer(keyword, currentStep, false);
}
void Schedule::handleWCONPROD(DeckKeywordConstPtr keyword, size_t currentStep) {
handleWCONProducer(keyword, currentStep, true);
}
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& wellNamePattern = record->getItem("WELL")->getTrimmedString(0);
std::vector<WellPtr> wells = getWells(wellNamePattern);
for (auto wellIter=wells.begin(); wellIter != wells.end(); ++wellIter) {
WellPtr well = *wellIter;
WellInjector::TypeEnum injectorType = WellInjector::TypeFromString( record->getItem("TYPE")->getTrimmedString(0) );
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
well->setStatus( currentStep , status );
WellInjectionProperties properties(well->getInjectionPropertiesCopy(currentStep));
2014-08-25 11:56:17 +02:00
properties.injectorType = injectorType;
properties.predictionMode = true;
2014-08-25 11:56:17 +02:00
if (!record->getItem("RATE")->defaultApplied(0)) {
2014-08-25 11:56:17 +02:00
properties.surfaceInjectionRate = convertInjectionRateToSI(record->getItem("RATE")->getRawDouble(0) , injectorType, *deck->getActiveUnitSystem());
properties.addInjectionControl(WellInjector::RATE);
2014-08-25 11:56:17 +02:00
} else
properties.dropInjectionControl(WellInjector::RATE);
if (!record->getItem("RESV")->defaultApplied(0)) {
2014-08-25 11:56:17 +02:00
properties.reservoirInjectionRate = convertInjectionRateToSI(record->getItem("RESV")->getRawDouble(0) , injectorType, *deck->getActiveUnitSystem());
properties.addInjectionControl(WellInjector::RESV);
2014-08-25 11:56:17 +02:00
} else
properties.dropInjectionControl(WellInjector::RESV);
if (!record->getItem("THP")->defaultApplied(0)) {
2014-08-25 11:56:17 +02:00
properties.THPLimit = record->getItem("THP")->getSIDouble(0);
properties.addInjectionControl(WellInjector::THP);
2014-08-25 11:56:17 +02:00
} else
properties.dropInjectionControl(WellInjector::THP);
2014-08-25 11:56:17 +02:00
/*
What a mess; there is a sensible default BHP limit
defined, so the BHPLimit can be safely set
unconditionally - but should we make BHP control
available based on that default value - currently we
do not do that.
*/
properties.BHPLimit = record->getItem("BHP")->getSIDouble(0);
if (!record->getItem("BHP")->defaultApplied(0)) {
properties.addInjectionControl(WellInjector::BHP);
2014-08-25 11:56:17 +02:00
} else
properties.dropInjectionControl(WellInjector::BHP);
if (well->isAvailableForGroupControl(currentStep))
properties.addInjectionControl(WellInjector::GRUP);
else
properties.dropInjectionControl(WellInjector::GRUP);
{
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);
}
}
}
void Schedule::handleWCONINJH(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);
// convert injection rates to SI
2014-09-19 14:58:37 +02:00
WellInjector::TypeEnum injectorType = WellInjector::TypeFromString( record->getItem("TYPE")->getTrimmedString(0));
double injectionRate = record->getItem("RATE")->getRawDouble(0);
2014-09-19 14:58:37 +02:00
injectionRate = convertInjectionRateToSI(injectionRate, injectorType, *deck->getActiveUnitSystem());
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
well->setStatus( currentStep , status );
WellInjectionProperties properties(well->getInjectionPropertiesCopy(currentStep));
2014-09-19 14:58:37 +02:00
properties.injectorType = injectorType;
properties.surfaceInjectionRate = injectionRate;
2014-09-19 14:58:37 +02:00
// History matches are usually rate controled. Here, we assume it.
properties.addInjectionControl(WellInjector::RATE);
2014-09-19 16:51:02 +02:00
properties.controlMode = WellInjector::RATE;
properties.predictionMode = false;
well->setInjectionProperties(currentStep, properties);
}
}
void Schedule::handleWELOPEN(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);
for (size_t i=2; i<7; i++) {
if (record->getItem(i)->getInt(0) > 0 ) {
throw std::logic_error("Error processing WELOPEN keyword, specifying specific connections is not supported yet.");
}
}
WellCommon::StatusEnum status = WellCommon::StatusFromString( record->getItem("STATUS")->getTrimmedString(0));
well->setStatus(currentStep, status);
}
}
void Schedule::handleGCONINJE(DeckConstPtr deck, DeckKeywordConstPtr keyword, size_t currentStep) {
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& groupName = record->getItem("GROUP")->getTrimmedString(0);
GroupPtr group = getGroup(groupName);
{
Phase::PhaseEnum phase = Phase::PhaseEnumFromString( record->getItem("PHASE")->getTrimmedString(0) );
group->setInjectionPhase( currentStep , phase );
}
{
GroupInjection::ControlEnum controlMode = GroupInjection::ControlEnumFromString( record->getItem("CONTROL_MODE")->getTrimmedString(0) );
group->setInjectionControlMode( currentStep , controlMode );
}
Phase::PhaseEnum wellPhase = Phase::PhaseEnumFromString( record->getItem("PHASE")->getTrimmedString(0));
// calculate SI injection rates for the group
double surfaceInjectionRate = record->getItem("SURFACE_TARGET")->getRawDouble(0);
surfaceInjectionRate = convertInjectionRateToSI(surfaceInjectionRate, wellPhase, *deck->getActiveUnitSystem());
double reservoirInjectionRate = record->getItem("RESV_TARGET")->getRawDouble(0);
reservoirInjectionRate = convertInjectionRateToSI(reservoirInjectionRate, wellPhase, *deck->getActiveUnitSystem());
group->setSurfaceMaxRate( currentStep , surfaceInjectionRate);
group->setReservoirMaxRate( currentStep , reservoirInjectionRate);
group->setTargetReinjectFraction( currentStep , record->getItem("REINJ_TARGET")->getSIDouble(0));
group->setTargetVoidReplacementFraction( currentStep , record->getItem("VOIDAGE_TARGET")->getSIDouble(0));
group->setProductionGroup(currentStep, false);
}
}
2013-11-20 17:07:49 +01:00
void Schedule::handleGCONPROD(DeckKeywordConstPtr keyword, size_t currentStep) {
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& groupName = record->getItem("GROUP")->getTrimmedString(0);
2013-11-20 17:07:49 +01:00
GroupPtr group = getGroup(groupName);
{
GroupProduction::ControlEnum controlMode = GroupProduction::ControlEnumFromString( record->getItem("CONTROL_MODE")->getTrimmedString(0) );
2013-11-20 17:07:49 +01:00
group->setProductionControlMode( currentStep , controlMode );
}
group->setOilTargetRate( currentStep , record->getItem("OIL_TARGET")->getSIDouble(0));
group->setGasTargetRate( currentStep , record->getItem("GAS_TARGET")->getSIDouble(0));
group->setWaterTargetRate( currentStep , record->getItem("WATER_TARGET")->getSIDouble(0));
group->setLiquidTargetRate( currentStep , record->getItem("LIQUID_TARGET")->getSIDouble(0));
2013-11-20 17:07:49 +01:00
{
GroupProductionExceedLimit::ActionEnum exceedAction = GroupProductionExceedLimit::ActionEnumFromString(record->getItem("EXCEED_PROC")->getTrimmedString(0) );
2013-11-20 17:07:49 +01:00
group->setProductionExceedLimitAction( currentStep , exceedAction );
}
group->setProductionGroup(currentStep, true);
2013-11-20 17:07:49 +01:00
}
}
void Schedule::handleCOMPDAT(DeckKeywordConstPtr keyword , size_t currentStep) {
std::map<std::string , std::vector< CompletionPtr> > completionMapList = Completion::completionsFromCOMPDATKeyword( keyword );
std::map<std::string , std::vector< CompletionPtr> >::iterator iter;
for( iter= completionMapList.begin(); iter != completionMapList.end(); iter++) {
const std::string wellName = iter->first;
WellPtr well = getWell(wellName);
well->addCompletions(currentStep, iter->second);
}
}
void Schedule::handleWGRUPCON(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);
2014-02-19 15:43:42 +01:00
bool availableForGroupControl = convertEclipseStringToBool(record->getItem("GROUP_CONTROLLED")->getTrimmedString(0));
2014-02-19 15:43:42 +01:00
well->setAvailableForGroupControl(currentStep, availableForGroupControl);
well->setGuideRate(currentStep, record->getItem("GUIDE_RATE")->getRawDouble(0));
if (!record->getItem("PHASE")->defaultApplied(0)) {
std::string guideRatePhase = record->getItem("PHASE")->getTrimmedString(0);
well->setGuideRatePhase(currentStep, GuideRate::GuideRatePhaseEnumFromString(guideRatePhase));
} else
well->setGuideRatePhase(currentStep, GuideRate::UNDEFINED);
well->setGuideRateScalingFactor(currentStep, record->getItem("SCALING_FACTOR")->getRawDouble(0));
}
}
void Schedule::handleGRUPTREE(DeckKeywordConstPtr keyword, size_t currentStep) {
GroupTreePtr currentTree = m_rootGroupTree->get(currentStep);
GroupTreePtr newTree = currentTree->deepCopy();
for (size_t recordNr = 0; recordNr < keyword->size(); recordNr++) {
DeckRecordConstPtr record = keyword->getRecord(recordNr);
const std::string& childName = record->getItem("CHILD_GROUP")->getTrimmedString(0);
const std::string& parentName = record->getItem("PARENT_GROUP")->getTrimmedString(0);
newTree->updateTree(childName, parentName);
if (!hasGroup(parentName))
addGroup( parentName , currentStep );
if (!hasGroup(childName))
addGroup( childName , currentStep );
}
m_rootGroupTree->add(currentStep, newTree);
}
2013-10-25 17:28:56 +02:00
TimeMapConstPtr Schedule::getTimeMap() const {
return m_timeMap;
}
GroupTreePtr Schedule::getGroupTree(size_t timeStep) const {
return m_rootGroupTree->get(timeStep);
}
void Schedule::addWell(const std::string& wellName, DeckRecordConstPtr record, size_t timeStep) {
// We change from eclipse's 1 - n, to a 0 - n-1 solution
int headI = record->getItem("HEAD_I")->getInt(0) - 1;
int headJ = record->getItem("HEAD_J")->getInt(0) - 1;
Phase::PhaseEnum preferredPhase = Phase::PhaseEnumFromString(record->getItem("PHASE")->getTrimmedString(0));
WellPtr well;
if (!record->getItem("REF_DEPTH")->defaultApplied(0)) {
double refDepth = record->getItem("REF_DEPTH")->getSIDouble(0);
well = std::make_shared<Well>(wellName, headI, headJ, refDepth, preferredPhase, m_timeMap , timeStep);
} else {
well = std::make_shared<Well>(wellName, headI, headJ, preferredPhase, m_timeMap , timeStep);
}
m_wells.insert( wellName , well);
}
size_t Schedule::numWells() const {
return m_wells.size();
}
bool Schedule::hasWell(const std::string& wellName) const {
return m_wells.hasKey( wellName );
}
WellPtr Schedule::getWell(const std::string& wellName) const {
return m_wells.get( wellName );
}
std::vector<WellConstPtr> Schedule::getWells() const {
return getWells(m_timeMap->size()-1);
}
std::vector<WellConstPtr> Schedule::getWells(size_t timeStep) const {
if (timeStep >= m_timeMap->size()) {
throw std::invalid_argument("Timestep to large");
}
std::vector<WellConstPtr> wells;
for (auto iter = m_wells.begin(); iter != m_wells.end(); ++iter) {
WellConstPtr well = *iter;
if (well->hasBeenDefined(timeStep)) {
wells.push_back(well);
}
}
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;
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);
}
GroupPtr group(new Group(groupName, m_timeMap , timeStep));
m_groups[ groupName ] = group;
}
size_t Schedule::numGroups() const {
return m_groups.size();
}
bool Schedule::hasGroup(const std::string& groupName) const {
return m_groups.find(groupName) != m_groups.end();
}
GroupPtr Schedule::getGroup(const std::string& groupName) const {
if (hasGroup(groupName)) {
return m_groups.at(groupName);
} else
throw std::invalid_argument("Group: " + groupName + " does not exist");
}
void Schedule::addWellToGroup( GroupPtr newGroup , WellPtr well , size_t timeStep) {
const std::string currentGroupName = well->getGroupName(timeStep);
if (currentGroupName != "") {
GroupPtr currentGroup = getGroup( currentGroupName );
currentGroup->delWell( timeStep , well->name());
}
well->setGroupName(timeStep , newGroup->name());
newGroup->addWell(timeStep , well);
}
double Schedule::convertInjectionRateToSI(double rawRate, WellInjector::TypeEnum wellType, const Opm::UnitSystem &unitSystem) const {
switch (wellType) {
case WellInjector::MULTI:
// multi-phase controlled injectors are a really funny
// construct in Eclipse: the quantity controlled for is
// not physically meaningful, i.e. Eclipse adds up
// MCFT/day and STB/day.
throw std::logic_error("There is no generic way to handle multi-phase injectors at this level!");
case WellInjector::OIL:
case WellInjector::WATER:
return rawRate * unitSystem.parse("LiquidVolume/Time")->getSIScaling();
case WellInjector::GAS:
return rawRate * unitSystem.parse("GasVolume/Time")->getSIScaling();
default:
throw std::logic_error("Unknown injector type");
}
}
double Schedule::convertInjectionRateToSI(double rawRate, Phase::PhaseEnum wellPhase, const Opm::UnitSystem &unitSystem) const {
switch (wellPhase) {
case Phase::OIL:
case Phase::WATER:
return rawRate * unitSystem.parse("LiquidVolume/Time")->getSIScaling();
case Phase::GAS:
return rawRate * unitSystem.parse("GasVolume/Time")->getSIScaling();
default:
throw std::logic_error("Unknown injection phase");
}
}
2014-02-19 15:43:42 +01:00
bool Schedule::convertEclipseStringToBool(const std::string& eclipseString) {
std::string lowerTrimmed = boost::algorithm::to_lower_copy(eclipseString);
boost::algorithm::trim(lowerTrimmed);
if (lowerTrimmed == "y" || lowerTrimmed == "yes") {
return true;
}
else if (lowerTrimmed == "n" || lowerTrimmed == "no") {
return false;
}
else throw std::invalid_argument("String " + eclipseString + " not recognized as a boolean-convertible string.");
}
2013-10-25 17:28:56 +02:00
}