ResInsight/ApplicationLibCode/ProjectDataModel/Flow/RimWellPlotTools.cpp
2022-06-27 19:25:27 +02:00

1245 lines
50 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight 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.
//
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimWellPlotTools.h"
#include "RiaQDateTimeTools.h"
#include "RiaWellNameComparer.h"
#include "RifReaderEclipseRft.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigSimWellData.h"
#include "RimEclipseCase.h"
#include "RimEclipseResultCase.h"
#include "RimObservedDataCollection.h"
#include "RimObservedFmuRftData.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimWellLogExtractionCurve.h"
#include "RimWellLogFile.h"
#include "RimWellLogFileChannel.h"
#include "RimWellLogFileCurve.h"
#include "RimWellLogRftCurve.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include <regex>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::set<QString> RimWellPlotTools::PRESSURE_DATA_NAMES = { "PRESSURE", "PRES_FORM" };
const std::set<QString> RimWellPlotTools::OIL_CHANNEL_NAMES = { "QOZT", "QOIL", "^.*\\D_QOIL" };
const std::set<QString> RimWellPlotTools::GAS_CHANNEL_NAMES = { "QGZT", "QGAS", "^.*\\D_QGAS" };
const std::set<QString> RimWellPlotTools::WATER_CHANNEL_NAMES = { "QWZT", "QWAT", "^.*\\D_QWAT" };
const std::set<QString> RimWellPlotTools::TOTAL_CHANNEL_NAMES = { "QTZT", "QTOT", "^.*\\D_QTOT" };
std::set<QString> RimWellPlotTools::FLOW_DATA_NAMES = {};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class StaticFieldsInitializer
{
public:
StaticFieldsInitializer()
{
// Init static list
RimWellPlotTools::FLOW_DATA_NAMES.insert( RimWellPlotTools::OIL_CHANNEL_NAMES.begin(),
RimWellPlotTools::OIL_CHANNEL_NAMES.end() );
RimWellPlotTools::FLOW_DATA_NAMES.insert( RimWellPlotTools::GAS_CHANNEL_NAMES.begin(),
RimWellPlotTools::GAS_CHANNEL_NAMES.end() );
RimWellPlotTools::FLOW_DATA_NAMES.insert( RimWellPlotTools::WATER_CHANNEL_NAMES.begin(),
RimWellPlotTools::WATER_CHANNEL_NAMES.end() );
RimWellPlotTools::FLOW_DATA_NAMES.insert( RimWellPlotTools::TOTAL_CHANNEL_NAMES.begin(),
RimWellPlotTools::TOTAL_CHANNEL_NAMES.end() );
}
} staticFieldsInitializer;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasPressureData( const RimWellLogFile* wellLogFile )
{
for ( RimWellLogFileChannel* const wellLogChannel : wellLogFile->wellLogChannels() )
{
if ( isPressureChannel( wellLogChannel ) ) return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasPressureData( RimWellPath* wellPath )
{
for ( RimWellLogFile* const wellLogFile : wellPath->wellLogFiles() )
{
if ( hasPressureData( wellLogFile ) )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<RigEclipseResultAddress, QString>
RimWellPlotTools::pressureResultDataInfo( const RigEclipseCaseData* eclipseCaseData )
{
if ( eclipseCaseData != nullptr )
{
for ( const auto& pressureDataName : PRESSURE_DATA_NAMES )
{
if ( eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
->hasResultEntry(
RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, pressureDataName ) ) )
{
return std::make_pair( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, pressureDataName ),
pressureDataName );
}
}
}
return std::make_pair( RigEclipseResultAddress(), "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isPressureChannel( RimWellLogFileChannel* channel )
{
for ( const auto& pressureDataName : PRESSURE_DATA_NAMES )
{
if ( QString::compare( channel->name(), pressureDataName, Qt::CaseInsensitive ) == 0 ) return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasPressureData( RimEclipseResultCase* gridCase )
{
return pressureResultDataInfo( gridCase->eclipseCaseData() ).first.isValid();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasFlowData( const RimWellLogFile* wellLogFile )
{
for ( RimWellLogFileChannel* const wellLogChannel : wellLogFile->wellLogChannels() )
{
if ( isFlowChannel( wellLogChannel ) ) return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasFlowData( const RimWellPath* wellPath )
{
for ( RimWellLogFile* const wellLogFile : wellPath->wellLogFiles() )
{
if ( hasFlowData( wellLogFile ) )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasAssociatedWellPath( const QString& wellName )
{
RimProject* proj = RimProject::current();
RimWellPath* wellPath = proj->wellPathByName( wellName );
return wellPath != nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isFlowChannel( RimWellLogFileChannel* channel )
{
return tryMatchChannelName( FLOW_DATA_NAMES, channel->name() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isOilFlowChannel( const QString& channelName )
{
return tryMatchChannelName( OIL_CHANNEL_NAMES, channelName );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isGasFlowChannel( const QString& channelName )
{
return tryMatchChannelName( GAS_CHANNEL_NAMES, channelName );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isWaterFlowChannel( const QString& channelName )
{
return tryMatchChannelName( WATER_CHANNEL_NAMES, channelName );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::isTotalFlowChannel( const QString& channelName )
{
return tryMatchChannelName( TOTAL_CHANNEL_NAMES, channelName );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::hasFlowData( RimEclipseResultCase* gridCase )
{
const RigEclipseCaseData* const eclipseCaseData = gridCase->eclipseCaseData();
for ( const QString& channelName : FLOW_DATA_NAMES )
{
if ( eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
->hasResultEntry( RigEclipseResultAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, channelName ) ) )
{
return true;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
FlowPhase RimWellPlotTools::flowPhaseFromChannelName( const QString& channelName )
{
if ( tryMatchChannelName( OIL_CHANNEL_NAMES, channelName ) ) return FLOW_PHASE_OIL;
if ( tryMatchChannelName( GAS_CHANNEL_NAMES, channelName ) ) return FLOW_PHASE_GAS;
if ( tryMatchChannelName( WATER_CHANNEL_NAMES, channelName ) ) return FLOW_PHASE_WATER;
if ( tryMatchChannelName( TOTAL_CHANNEL_NAMES, channelName ) ) return FLOW_PHASE_TOTAL;
return FLOW_PHASE_NONE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPlotTools::addTimeStepsToMap( std::map<QDateTime, std::set<RifDataSourceForRftPlt>>& destMap,
const std::map<QDateTime, std::set<RifDataSourceForRftPlt>>& timeStepsToAdd )
{
for ( const auto& timeStepPair : timeStepsToAdd )
{
if ( timeStepPair.first.isValid() )
{
auto addresses = timeStepPair.second;
destMap[timeStepPair.first].insert( addresses.begin(), addresses.end() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimWellLogFile*> RimWellPlotTools::wellLogFilesContainingPressure( const QString& wellPathNameOrSimWellName )
{
std::vector<RimWellLogFile*> wellLogFiles;
const RimProject* const project = RimProject::current();
std::vector<RimWellPath*> wellPaths = project->allWellPaths();
for ( auto wellPath : wellPaths )
{
if ( !wellPathNameOrSimWellName.isEmpty() &&
( wellPathNameOrSimWellName == wellPath->associatedSimulationWellName() ||
wellPathNameOrSimWellName == wellPath->name() ) )
{
const std::vector<RimWellLogFile*> files = wellPath->wellLogFiles();
for ( RimWellLogFile* file : files )
{
if ( hasPressureData( file ) )
{
wellLogFiles.push_back( file );
}
}
}
}
return wellLogFiles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellLogFileChannel* RimWellPlotTools::getPressureChannelFromWellFile( const RimWellLogFile* wellLogFile )
{
if ( wellLogFile != nullptr )
{
for ( RimWellLogFileChannel* const channel : wellLogFile->wellLogChannels() )
{
if ( isPressureChannel( channel ) )
{
return channel;
}
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimWellLogFile*> RimWellPlotTools::wellLogFilesContainingFlow( const QString& wellPathName )
{
std::vector<RimWellLogFile*> wellLogFiles;
const RimProject* const project = RimProject::current();
std::vector<RimWellPath*> wellPaths = project->allWellPaths();
for ( auto wellPath : wellPaths )
{
if ( wellPath->name() == wellPathName )
{
std::vector<RimWellLogFile*> files = wellPath->wellLogFiles();
for ( RimWellLogFile* file : files )
{
if ( hasFlowData( file ) )
{
wellLogFiles.push_back( file );
}
}
}
}
return wellLogFiles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPath* RimWellPlotTools::wellPathFromWellLogFile( const RimWellLogFile* wellLogFile )
{
RimProject* const project = RimProject::current();
for ( const auto& oilField : project->oilFields )
{
for ( const auto& wellPath : oilField->wellPathCollection()->allWellPaths() )
{
for ( RimWellLogFile* const file : wellPath->wellLogFiles() )
{
if ( file == wellLogFile )
{
return wellPath;
}
}
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEclipseResultCase*> RimWellPlotTools::gridCasesForWell( const QString& simWellName )
{
std::vector<RimEclipseResultCase*> cases;
const RimProject* project = RimProject::current();
for ( RimEclipseCase* eclCase : project->eclipseCases() )
{
RimEclipseResultCase* resultCase = dynamic_cast<RimEclipseResultCase*>( eclCase );
if ( resultCase != nullptr )
{
if ( eclCase->eclipseCaseData()->findSimWellData( simWellName ) )
{
cases.push_back( resultCase );
break;
}
}
}
return cases;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimEclipseResultCase*> RimWellPlotTools::rftCasesForWell( const QString& simWellName )
{
std::vector<RimEclipseResultCase*> cases;
const RimProject* project = RimProject::current();
for ( RimEclipseCase* eclCase : project->eclipseCases() )
{
RimEclipseResultCase* resultCase = dynamic_cast<RimEclipseResultCase*>( eclCase );
if ( resultCase && resultCase->rftReader() && resultCase->rftReader()->wellNames().count( simWellName ) )
{
cases.push_back( resultCase );
}
}
return cases;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCaseCollection*> RimWellPlotTools::rftEnsemblesForWell( const QString& simWellName )
{
const RimProject* project = RimProject::current();
std::vector<RimSummaryCaseCollection*> allSummaryCaseCollections = project->summaryGroups();
std::vector<RimSummaryCaseCollection*> rftEnsembles;
for ( RimSummaryCaseCollection* summaryCaseColl : allSummaryCaseCollections )
{
if ( summaryCaseColl && summaryCaseColl->isEnsemble() &&
!summaryCaseColl->rftTimeStepsForWell( simWellName ).empty() )
{
rftEnsembles.push_back( summaryCaseColl );
}
}
return rftEnsembles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSummaryCaseCollection*> RimWellPlotTools::rftEnsembles()
{
const RimProject* project = RimProject::current();
std::vector<RimSummaryCaseCollection*> allSummaryCaseCollections = project->summaryGroups();
std::vector<RimSummaryCaseCollection*> rftEnsembles;
for ( RimSummaryCaseCollection* summaryCaseColl : allSummaryCaseCollections )
{
if ( summaryCaseColl && summaryCaseColl->isEnsemble() && !summaryCaseColl->wellsWithRftData().empty() )
{
rftEnsembles.push_back( summaryCaseColl );
}
}
return rftEnsembles;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimObservedFmuRftData*> RimWellPlotTools::observedFmuRftDataForWell( const QString& simWellName )
{
std::vector<RimObservedFmuRftData*> observedDataForWell;
std::vector<RimObservedFmuRftData*> allObservedData = observedFmuRftData();
for ( RimObservedFmuRftData* observedData : allObservedData )
{
if ( observedData->hasWell( simWellName ) )
{
observedDataForWell.push_back( observedData );
}
}
return observedDataForWell;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimObservedFmuRftData*> RimWellPlotTools::observedFmuRftData()
{
const RimProject* project = RimProject::current();
RimObservedDataCollection* observedDataCollection =
project->activeOilField() ? project->activeOilField()->observedDataCollection() : nullptr;
if ( observedDataCollection )
{
return observedDataCollection->allObservedFmuRftData();
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> RimWellPlotTools::timeStepsMapFromGridCase( RimEclipseCase* gridCase )
{
const RigEclipseCaseData* const eclipseCaseData = gridCase->eclipseCaseData();
std::pair<RigEclipseResultAddress, QString> resultDataInfo = pressureResultDataInfo( eclipseCaseData );
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> timeStepsMap;
if ( resultDataInfo.first.isValid() )
{
for ( const QDateTime& timeStep :
eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->timeStepDates( resultDataInfo.first ) )
{
if ( timeStepsMap.count( timeStep ) == 0 )
{
timeStepsMap.insert( std::make_pair( timeStep, std::set<RifDataSourceForRftPlt>() ) );
}
timeStepsMap[timeStep].insert( RifDataSourceForRftPlt( RifDataSourceForRftPlt::GRID, gridCase ) );
}
}
return timeStepsMap;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RimWellPlotTools::findMatchingOrAdjacentTimeSteps( const std::set<QDateTime>& baseTimeLine,
const std::set<QDateTime>& availableTimeSteps )
{
std::set<QDateTime> resultTimeSteps;
for ( const QDateTime& baseTimeStep : baseTimeLine )
{
auto itToEqualOrLargerTime = availableTimeSteps.lower_bound( baseTimeStep );
if ( itToEqualOrLargerTime != availableTimeSteps.end() )
{
resultTimeSteps.insert( *itToEqualOrLargerTime );
if ( *itToEqualOrLargerTime != baseTimeStep && itToEqualOrLargerTime != availableTimeSteps.begin() )
{
// Found a larger time, then add the timestep before it as the adjacent timestep before the base timestep
itToEqualOrLargerTime--;
resultTimeSteps.insert( *itToEqualOrLargerTime );
}
}
}
// The above will only work if there are at least one available timestep equal or after any of the basetimeline
// times. If no timesteps matched but we have some, add the last available because the above code missed it.
if ( !resultTimeSteps.size() && baseTimeLine.size() && availableTimeSteps.size() )
{
resultTimeSteps.insert( *availableTimeSteps.rbegin() );
}
return resultTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RimWellPlotTools::availableSimWellTimesteps( RimEclipseCase* eclCase,
const QString& simWellName,
bool addFirstReportTimestep )
{
if ( !eclCase || !eclCase->eclipseCaseData() ) return {};
std::set<QDateTime> availebleTimeSteps;
const RigSimWellData* simWell = eclCase->eclipseCaseData()->findSimWellData( simWellName );
if ( simWell )
{
std::vector<QDateTime> allTimeSteps =
eclCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->timeStepDates();
for ( size_t tsIdx = 0; tsIdx < allTimeSteps.size(); ++tsIdx )
{
if ( simWell->hasWellResult( tsIdx ) || ( addFirstReportTimestep && tsIdx == 0 ) )
{
availebleTimeSteps.insert( allTimeSteps[tsIdx] );
}
}
}
return availebleTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaRftPltCurveDefinition RimWellPlotTools::curveDefFromCurve( const RimWellLogCurve* curve )
{
const RimWellLogRftCurve* rftCurve = dynamic_cast<const RimWellLogRftCurve*>( curve );
const RimWellLogExtractionCurve* gridCurve = dynamic_cast<const RimWellLogExtractionCurve*>( curve );
const RimWellLogFileCurve* wellLogFileCurve = dynamic_cast<const RimWellLogFileCurve*>( curve );
if ( rftCurve != nullptr )
{
RimEclipseResultCase* rftCase = dynamic_cast<RimEclipseResultCase*>( rftCurve->eclipseResultCase() );
RimSummaryCase* rftSummaryCase = rftCurve->summaryCase();
RimSummaryCaseCollection* rftEnsemble = rftCurve->ensemble();
RimObservedFmuRftData* rftFmuData = rftCurve->observedFmuRftData();
const RifEclipseRftAddress rftAddress = rftCurve->rftAddress();
const QString& wellName = rftAddress.wellName();
const QDateTime& timeStep = rftAddress.timeStep();
if ( rftCase != nullptr )
{
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::RFT, rftCase ),
wellName,
timeStep );
}
else if ( rftSummaryCase != nullptr )
{
rftSummaryCase->firstAncestorOrThisOfTypeAsserted( rftEnsemble );
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::SUMMARY_RFT,
rftSummaryCase,
rftEnsemble ),
wellName,
timeStep );
}
else if ( rftEnsemble != nullptr )
{
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::ENSEMBLE_RFT, rftEnsemble ),
wellName,
timeStep );
}
else if ( rftFmuData != nullptr )
{
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED_FMU_RFT, rftFmuData ),
wellName,
timeStep );
}
}
else if ( gridCurve != nullptr )
{
RimEclipseResultCase* gridCase = dynamic_cast<RimEclipseResultCase*>( gridCurve->rimCase() );
if ( gridCase != nullptr )
{
size_t timeStepIndex = gridCurve->currentTimeStep();
const std::map<QDateTime, std::set<RifDataSourceForRftPlt>>& timeStepsMap =
timeStepsMapFromGridCase( gridCase );
auto timeStepsVector =
std::vector<std::pair<QDateTime, std::set<RifDataSourceForRftPlt>>>( timeStepsMap.begin(),
timeStepsMap.end() );
if ( timeStepIndex < timeStepsMap.size() )
{
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::GRID, gridCase ),
gridCurve->wellName(),
timeStepsVector[timeStepIndex].first );
}
}
}
else if ( wellLogFileCurve != nullptr )
{
RimWellLogFile* const wellLogFile = wellLogFileCurve->wellLogFile();
if ( wellLogFile != nullptr )
{
const QDateTime date = wellLogFile->date();
if ( date.isValid() )
{
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED, wellLogFile ),
wellLogFile->wellName(),
date );
}
}
}
return RiaRftPltCurveDefinition( RifDataSourceForRftPlt(), QString(), QDateTime() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPath* RimWellPlotTools::wellPathByWellPathNameOrSimWellName( const QString& wellPathNameOrSimwellName )
{
RimProject* proj = RimProject::current();
RimWellPath* wellPath = proj->wellPathByName( wellPathNameOrSimwellName );
return wellPath != nullptr ? wellPath : proj->wellPathFromSimWellName( wellPathNameOrSimwellName );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellPlotTools::simWellName( const QString& wellPathNameOrSimWellName )
{
RimWellPath* wellPath = wellPathByWellPathNameOrSimWellName( wellPathNameOrSimWellName );
return wellPath != nullptr ? wellPath->associatedSimulationWellName() : wellPathNameOrSimWellName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellPlotTools::tryMatchChannelName( const std::set<QString>& channelNames, const QString& channelNameToMatch )
{
auto itr = std::find_if( channelNames.begin(), channelNames.end(), [&]( const QString& channelName ) {
if ( channelName.startsWith( '^' ) )
{
std::regex pattern( channelName.toStdString() );
return std::regex_match( channelNameToMatch.toStdString(), pattern );
}
else
{
return (bool)channelName.contains( channelNameToMatch, Qt::CaseInsensitive );
}
} );
return itr != channelNames.end();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::set<RiaRftPltCurveDefinition>
RimWellPlotTools::curveDefsFromTimesteps( const QString& wellPathNameOrSimWellName,
const std::vector<QDateTime>& selectedTimeSteps,
bool firstSimWellTimeStepIsValid,
const std::vector<RifDataSourceForRftPlt>& selectedSourcesExpanded,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& interestingRFTResults )
{
std::set<RiaRftPltCurveDefinition> curveDefs;
std::set<QDateTime> selectedTimeStepSet( selectedTimeSteps.begin(), selectedTimeSteps.end() );
const QString simWellName = RimWellPlotTools::simWellName( wellPathNameOrSimWellName );
for ( const RifDataSourceForRftPlt& addr : selectedSourcesExpanded )
{
if ( addr.sourceType() == RifDataSourceForRftPlt::RFT && addr.rftReader() )
{
std::set<QDateTime> rftTimes = addr.rftReader()->availableTimeSteps( simWellName, interestingRFTResults );
for ( const QDateTime& time : rftTimes )
{
if ( selectedTimeStepSet.count( time ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( addr, simWellName, time ) );
}
}
}
else if ( addr.sourceType() == RifDataSourceForRftPlt::GRID && addr.eclCase() )
{
std::set<QDateTime> timeSteps =
RimWellPlotTools::availableSimWellTimesteps( addr.eclCase(), simWellName, firstSimWellTimeStepIsValid );
for ( const QDateTime& time : timeSteps )
{
if ( selectedTimeStepSet.count( time ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( addr, simWellName, time ) );
}
}
}
else if ( addr.sourceType() == RifDataSourceForRftPlt::OBSERVED )
{
if ( addr.wellLogFile() )
{
if ( selectedTimeStepSet.count( addr.wellLogFile()->date() ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( addr, simWellName, addr.wellLogFile()->date() ) );
}
}
}
else if ( addr.sourceType() == RifDataSourceForRftPlt::OBSERVED_FMU_RFT )
{
RimObservedFmuRftData* observedFmuRftData = addr.observedFmuRftData();
if ( observedFmuRftData && observedFmuRftData->rftReader() )
{
std::set<QDateTime> timeSteps =
observedFmuRftData->rftReader()->availableTimeSteps( wellPathNameOrSimWellName );
for ( const QDateTime& time : timeSteps )
{
if ( selectedTimeStepSet.count( time ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( addr, wellPathNameOrSimWellName, time ) );
}
}
}
}
else if ( addr.ensemble() )
{
// Add individual summary curves
for ( RimSummaryCase* summaryCase : addr.ensemble()->allSummaryCases() )
{
if ( summaryCase && summaryCase->rftReader() )
{
RifDataSourceForRftPlt summaryAddr( RifDataSourceForRftPlt::SUMMARY_RFT, summaryCase, addr.ensemble() );
std::set<QDateTime> timeSteps =
summaryCase->rftReader()->availableTimeSteps( wellPathNameOrSimWellName );
for ( const QDateTime& time : timeSteps )
{
if ( selectedTimeStepSet.count( time ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( summaryAddr, wellPathNameOrSimWellName, time ) );
}
}
}
}
// Add statistics curves
if ( addr.sourceType() == RifDataSourceForRftPlt::ENSEMBLE_RFT )
{
std::set<QDateTime> statTimeSteps = addr.ensemble()->rftTimeStepsForWell( wellPathNameOrSimWellName );
for ( const QDateTime& time : statTimeSteps )
{
if ( selectedTimeStepSet.count( time ) )
{
curveDefs.insert( RiaRftPltCurveDefinition( addr, wellPathNameOrSimWellName, time ) );
}
}
}
}
}
return curveDefs;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellPlotTools::flowPlotAxisTitle( RimWellLogFile::WellFlowCondition condition,
RiaDefines::EclipseUnitSystem unitSystem )
{
QString axisTitle;
if ( condition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR )
{
QString unitText = RimWellPlotTools::flowUnitText( condition, unitSystem );
axisTitle = "Reservoir Flow Rate " + unitText;
}
else
{
QString unitText = RimWellPlotTools::flowUnitText( condition, unitSystem );
axisTitle = "Surface Flow Rate " + unitText;
}
return axisTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString flowConditionReservoirUnitText( RiaDefines::EclipseUnitSystem unitSystem )
{
QString unitText;
switch ( unitSystem )
{
case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
unitText = "[m<sup>3</sup>/day]";
break;
case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
unitText = "[Brl/day]";
break;
case RiaDefines::EclipseUnitSystem::UNITS_LAB:
unitText = "[cm<sup>3</sup>/hr]";
break;
default:
break;
}
return unitText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellPlotTools::flowUnitText( RimWellLogFile::WellFlowCondition condition,
RiaDefines::EclipseUnitSystem unitSystem )
{
QString unitText;
if ( condition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR )
{
unitText = flowConditionReservoirUnitText( unitSystem );
}
else
{
switch ( unitSystem )
{
case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
unitText = "[Liquid Sm<sup>3</sup>/day], [Gas kSm<sup>3</sup>/day]";
break;
case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
unitText = "[Liquid BBL/day], [Gas BOE/day]";
break;
case RiaDefines::EclipseUnitSystem::UNITS_LAB:
unitText = "[cm<sup>3</sup>/hr]";
break;
default:
break;
}
}
return unitText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimWellPlotTools::curveUnitText( RimWellLogFile::WellFlowCondition condition,
RiaDefines::EclipseUnitSystem unitSystem,
FlowPhase flowPhase )
{
QString unitText;
if ( condition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR )
{
unitText = flowConditionReservoirUnitText( unitSystem );
}
else
{
switch ( unitSystem )
{
case RiaDefines::EclipseUnitSystem::UNITS_METRIC:
switch ( flowPhase )
{
case FLOW_PHASE_GAS:
unitText = "[kSm<sup>3</sup>/day]";
break;
case FLOW_PHASE_WATER: // Intentionally fall through, water and oil have same unit
case FLOW_PHASE_OIL:
unitText = "[Sm<sup>3</sup>/day]";
break;
default:
unitText = "[Liquid Sm<sup>3</sup>/day], [Gas kSm<sup>3</sup>/day]";
break;
}
break;
case RiaDefines::EclipseUnitSystem::UNITS_FIELD:
switch ( flowPhase )
{
case FLOW_PHASE_GAS:
unitText = "[BOE/day]";
break;
case FLOW_PHASE_WATER: // Intentionally fall through, water and oil have same unit
case FLOW_PHASE_OIL:
unitText = "[BBL/day]";
break;
default:
unitText = "[Liquid BBL/day], [Gas BOE/day]";
break;
}
break;
case RiaDefines::EclipseUnitSystem::UNITS_LAB:
unitText = "[cm<sup>3</sup>/hr]";
break;
default:
break;
}
}
return unitText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> RimWellPlotTools::calculateRelevantTimeStepsFromCases(
const QString& wellPathNameOrSimWellName,
const std::vector<RifDataSourceForRftPlt>& selSources,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& interestingRFTResults )
{
bool addFirstTimestep = ( interestingRFTResults.count( RifEclipseRftAddress::RftWellLogChannelType::PRESSURE ) == 1 );
const QString simWellName = RimWellPlotTools::simWellName( wellPathNameOrSimWellName );
bool hasObservedData = false;
bool hasRftData = false;
bool hasGridData = false;
bool hasEnsembleData = false;
bool hasSummaryRftData = false;
for ( const auto& source : selSources )
{
switch ( source.sourceType() )
{
case RifDataSourceForRftPlt::RFT:
hasRftData = true;
break;
case RifDataSourceForRftPlt::GRID:
hasGridData = true;
break;
case RifDataSourceForRftPlt::OBSERVED:
case RifDataSourceForRftPlt::OBSERVED_FMU_RFT:
hasObservedData = true;
break;
case RifDataSourceForRftPlt::SUMMARY_RFT:
hasSummaryRftData = true;
break;
case RifDataSourceForRftPlt::ENSEMBLE_RFT:
hasEnsembleData = true;
break;
}
}
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> observedTimeStepsWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> rftTimeStepsWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> gridTimestepsWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> summaryRftTimeStepsWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> ensembleTimeStepsWithSources;
if ( hasObservedData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::OBSERVED && source.wellLogFile() )
{
observedTimeStepsWithSources[source.wellLogFile()->date()].insert( source );
}
else if ( source.sourceType() == RifDataSourceForRftPlt::OBSERVED_FMU_RFT && source.observedFmuRftData() )
{
std::set<QDateTime> rftFmuTimes =
source.observedFmuRftData()->rftReader()->availableTimeSteps( wellPathNameOrSimWellName );
for ( const QDateTime& date : rftFmuTimes )
{
observedTimeStepsWithSources[date].insert( source );
}
}
}
}
if ( hasRftData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::RFT && source.rftReader() )
{
std::set<QDateTime> rftTimes = source.rftReader()->availableTimeSteps( simWellName, interestingRFTResults );
for ( const QDateTime& date : rftTimes )
{
rftTimeStepsWithSources[date].insert( source );
}
}
}
}
if ( hasGridData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::GRID && source.eclCase() )
{
std::set<QDateTime> wellTimeSteps =
RimWellPlotTools::availableSimWellTimesteps( source.eclCase(), simWellName, addFirstTimestep );
for ( const QDateTime& date : wellTimeSteps )
{
gridTimestepsWithSources[date].insert( source );
}
}
}
}
if ( hasSummaryRftData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::SUMMARY_RFT && source.summaryCase() &&
source.summaryCase()->rftReader() )
{
std::set<QDateTime> wellTimeSteps =
source.summaryCase()->rftReader()->availableTimeSteps( wellPathNameOrSimWellName );
for ( const QDateTime& date : wellTimeSteps )
{
summaryRftTimeStepsWithSources[date].insert( source );
}
}
}
}
if ( hasEnsembleData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::ENSEMBLE_RFT && source.ensemble() )
{
std::set<QDateTime> wellTimeSteps = source.ensemble()->rftTimeStepsForWell( wellPathNameOrSimWellName );
for ( const QDateTime& date : wellTimeSteps )
{
ensembleTimeStepsWithSources[date].insert( source );
}
}
}
}
// If we have a time baseline add the equal or adjacent grid timesteps
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> timestepsToShowWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>>* timeBaseline = nullptr;
if ( hasObservedData )
{
timeBaseline = &observedTimeStepsWithSources;
}
else if ( hasRftData )
{
timeBaseline = &rftTimeStepsWithSources;
}
else if ( hasSummaryRftData )
{
timeBaseline = &summaryRftTimeStepsWithSources;
}
else if ( hasEnsembleData )
{
timeBaseline = &ensembleTimeStepsWithSources;
}
if ( timeBaseline )
{
std::set<QDateTime> baseTimeSteps;
for ( const auto& dateSourceSetPair : *timeBaseline )
baseTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> rftTimeSteps;
for ( const auto& dateSourceSetPair : rftTimeStepsWithSources )
rftTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> gridTimeSteps;
for ( const auto& dateSourceSetPair : gridTimestepsWithSources )
gridTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> summaryRftTimeSteps;
for ( const auto& dateSourceSetPair : summaryRftTimeStepsWithSources )
summaryRftTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> ensembleRftTimeSteps;
for ( const auto& dateSourceSetPair : ensembleTimeStepsWithSources )
ensembleRftTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> filteredRftTimeSteps =
RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, rftTimeSteps );
std::set<QDateTime> filteredGridTimeSteps =
RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, gridTimeSteps );
std::set<QDateTime> filteredEnsembleRftTimeSteps =
RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, ensembleRftTimeSteps );
if ( addFirstTimestep && gridTimeSteps.size() )
{
filteredGridTimeSteps.insert( *gridTimeSteps.begin() );
}
// Fill final map
timestepsToShowWithSources = observedTimeStepsWithSources;
std::set<QDateTime>& allFilteredTimesteps = filteredRftTimeSteps;
allFilteredTimesteps.insert( filteredEnsembleRftTimeSteps.begin(), filteredEnsembleRftTimeSteps.end() );
allFilteredTimesteps.insert( filteredGridTimeSteps.begin(), filteredGridTimeSteps.end() );
for ( const QDateTime& time : allFilteredTimesteps )
{
auto rftTimeSourceSetIt = rftTimeStepsWithSources.find( time );
if ( rftTimeSourceSetIt != rftTimeStepsWithSources.end() )
{
std::set<RifDataSourceForRftPlt>& sourceSet = rftTimeSourceSetIt->second;
timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() );
}
auto gridTimeSourceSetIt = gridTimestepsWithSources.find( time );
if ( gridTimeSourceSetIt != gridTimestepsWithSources.end() )
{
std::set<RifDataSourceForRftPlt>& sourceSet = gridTimeSourceSetIt->second;
timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() );
}
auto summaryRftTimeSourceSetIt = summaryRftTimeStepsWithSources.find( time );
if ( summaryRftTimeSourceSetIt != summaryRftTimeStepsWithSources.end() )
{
std::set<RifDataSourceForRftPlt>& sourceSet = summaryRftTimeSourceSetIt->second;
timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() );
}
auto ensembleRftTimeSourceSetIt = ensembleTimeStepsWithSources.find( time );
if ( ensembleRftTimeSourceSetIt != ensembleTimeStepsWithSources.end() )
{
std::set<RifDataSourceForRftPlt>& sourceSet = ensembleRftTimeSourceSetIt->second;
timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() );
}
}
}
else
{
timestepsToShowWithSources = gridTimestepsWithSources;
}
return timestepsToShowWithSources;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellPlotTools::calculateValueOptionsForTimeSteps(
const QString& wellPathNameOrSimWellName,
const std::vector<RifDataSourceForRftPlt>& selSources,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& interestingRFTResults,
QList<caf::PdmOptionItemInfo>& options )
{
auto timestepsToShowWithSources =
calculateRelevantTimeStepsFromCases( wellPathNameOrSimWellName, selSources, interestingRFTResults );
// Create formatted options of all the time steps
QString dateFormatString;
{
std::vector<QDateTime> allTimeSteps;
for ( const std::pair<const QDateTime, std::set<RifDataSourceForRftPlt>>& timeStepPair : timestepsToShowWithSources )
{
allTimeSteps.push_back( timeStepPair.first );
}
dateFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates( allTimeSteps );
}
for ( const std::pair<const QDateTime, std::set<RifDataSourceForRftPlt>>& timeStepPair : timestepsToShowWithSources )
{
QString optionText = RiaQDateTimeTools::toStringUsingApplicationLocale( timeStepPair.first, dateFormatString );
bool hasObs = false;
bool hasRft = false;
bool hasGrid = false;
bool hasEnsemble = false;
for ( const auto& source : timeStepPair.second )
{
switch ( source.sourceType() )
{
case RifDataSourceForRftPlt::OBSERVED:
case RifDataSourceForRftPlt::OBSERVED_FMU_RFT:
hasObs = true;
break;
case RifDataSourceForRftPlt::RFT:
hasRft = true;
break;
case RifDataSourceForRftPlt::GRID:
hasGrid = true;
break;
case RifDataSourceForRftPlt::ENSEMBLE_RFT:
hasEnsemble = true;
break;
}
}
QStringList optionTags;
if ( hasObs ) optionTags << "O";
if ( hasRft ) optionTags << "R";
if ( hasGrid ) optionTags << "G";
if ( hasEnsemble ) optionTags << "E";
optionText += QString( " \t[%1]" ).arg( optionTags.join( ", " ) );
options.push_back( caf::PdmOptionItemInfo( optionText, timeStepPair.first ) );
}
}