///////////////////////////////////////////////////////////////////////////////// // // 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 // 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 //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::set RimWellPlotTools::PRESSURE_DATA_NAMES = { "PRESSURE", "PRES_FORM" }; const std::set RimWellPlotTools::OIL_CHANNEL_NAMES = { "QOZT", "QOIL", "^.*\\D_QOIL" }; const std::set RimWellPlotTools::GAS_CHANNEL_NAMES = { "QGZT", "QGAS", "^.*\\D_QGAS" }; const std::set RimWellPlotTools::WATER_CHANNEL_NAMES = { "QWZT", "QWAT", "^.*\\D_QWAT" }; const std::set RimWellPlotTools::TOTAL_CHANNEL_NAMES = { "QTZT", "QTOT", "^.*\\D_QTOT" }; std::set 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 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>& destMap, const std::map>& timeStepsToAdd ) { for ( const auto& timeStepPair : timeStepsToAdd ) { if ( timeStepPair.first.isValid() ) { auto addresses = timeStepPair.second; destMap[timeStepPair.first].insert( addresses.begin(), addresses.end() ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::wellLogFilesContainingPressure( const QString& wellPathNameOrSimWellName ) { std::vector wellLogFiles; const RimProject* const project = RimProject::current(); std::vector wellPaths = project->allWellPaths(); for ( auto wellPath : wellPaths ) { if ( !wellPathNameOrSimWellName.isEmpty() && ( wellPathNameOrSimWellName == wellPath->associatedSimulationWellName() || wellPathNameOrSimWellName == wellPath->name() ) ) { const std::vector 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 RimWellPlotTools::wellLogFilesContainingFlow( const QString& wellPathName ) { std::vector wellLogFiles; const RimProject* const project = RimProject::current(); std::vector wellPaths = project->allWellPaths(); for ( auto wellPath : wellPaths ) { if ( wellPath->name() == wellPathName ) { std::vector 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 RimWellPlotTools::gridCasesForWell( const QString& simWellName ) { std::vector cases; const RimProject* project = RimProject::current(); for ( RimEclipseCase* eclCase : project->eclipseCases() ) { RimEclipseResultCase* resultCase = dynamic_cast( eclCase ); if ( resultCase != nullptr ) { if ( eclCase->eclipseCaseData()->findSimWellData( simWellName ) ) { cases.push_back( resultCase ); break; } } } return cases; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::rftCasesForWell( const QString& simWellName ) { std::vector cases; const RimProject* project = RimProject::current(); for ( RimEclipseCase* eclCase : project->eclipseCases() ) { RimEclipseResultCase* resultCase = dynamic_cast( eclCase ); if ( resultCase && resultCase->rftReader() && resultCase->rftReader()->wellNames().count( simWellName ) ) { cases.push_back( resultCase ); } } return cases; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::rftEnsemblesForWell( const QString& simWellName ) { const RimProject* project = RimProject::current(); std::vector allSummaryCaseCollections = project->summaryGroups(); std::vector rftEnsembles; for ( RimSummaryCaseCollection* summaryCaseColl : allSummaryCaseCollections ) { if ( summaryCaseColl && summaryCaseColl->isEnsemble() && !summaryCaseColl->rftTimeStepsForWell( simWellName ).empty() ) { rftEnsembles.push_back( summaryCaseColl ); } } return rftEnsembles; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::rftEnsembles() { const RimProject* project = RimProject::current(); std::vector allSummaryCaseCollections = project->summaryGroups(); std::vector rftEnsembles; for ( RimSummaryCaseCollection* summaryCaseColl : allSummaryCaseCollections ) { if ( summaryCaseColl && summaryCaseColl->isEnsemble() && !summaryCaseColl->wellsWithRftData().empty() ) { rftEnsembles.push_back( summaryCaseColl ); } } return rftEnsembles; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::observedFmuRftDataForWell( const QString& simWellName ) { std::vector observedDataForWell; std::vector allObservedData = observedFmuRftData(); for ( RimObservedFmuRftData* observedData : allObservedData ) { if ( observedData->hasWell( simWellName ) ) { observedDataForWell.push_back( observedData ); } } return observedDataForWell; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellPlotTools::observedFmuRftData() { const RimProject* project = RimProject::current(); RimObservedDataCollection* observedDataCollection = project->activeOilField() ? project->activeOilField()->observedDataCollection() : nullptr; if ( observedDataCollection ) { return observedDataCollection->allObservedFmuRftData(); } return {}; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map> RimWellPlotTools::timeStepsMapFromGridCase( RimEclipseCase* gridCase ) { const RigEclipseCaseData* const eclipseCaseData = gridCase->eclipseCaseData(); std::pair resultDataInfo = pressureResultDataInfo( eclipseCaseData ); std::map> 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() ) ); } timeStepsMap[timeStep].insert( RifDataSourceForRftPlt( RifDataSourceForRftPlt::GRID, gridCase ) ); } } return timeStepsMap; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set RimWellPlotTools::findMatchingOrAdjacentTimeSteps( const std::set& baseTimeLine, const std::set& availableTimeSteps ) { std::set 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 RimWellPlotTools::availableSimWellTimesteps( RimEclipseCase* eclCase, const QString& simWellName, bool addFirstReportTimestep ) { std::set availebleTimeSteps; if ( eclCase && eclCase->eclipseCaseData() ) { std::vector allTimeSteps = eclCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->timeStepDates(); const RigSimWellData* simWell = eclCase->eclipseCaseData()->findSimWellData( simWellName ); 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( curve ); const RimWellLogExtractionCurve* gridCurve = dynamic_cast( curve ); const RimWellLogFileCurve* wellLogFileCurve = dynamic_cast( curve ); if ( rftCurve != nullptr ) { RimEclipseResultCase* rftCase = dynamic_cast( 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( gridCurve->rimCase() ); if ( gridCase != nullptr ) { size_t timeStepIndex = gridCurve->currentTimeStep(); const std::map>& timeStepsMap = timeStepsMapFromGridCase( gridCase ); auto timeStepsVector = std::vector>>( 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& 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 RimWellPlotTools::curveDefsFromTimesteps( const QString& wellPathNameOrSimWellName, const std::vector& selectedTimeSteps, bool firstSimWellTimeStepIsValid, const std::vector& selectedSourcesExpanded, const std::set& interestingRFTResults ) { std::set curveDefs; std::set 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 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 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 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 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 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, RiaEclipseUnitTools::UnitSystem 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( RiaEclipseUnitTools::UnitSystem unitSystem ) { QString unitText; switch ( unitSystem ) { case RiaEclipseUnitTools::UnitSystem::UNITS_METRIC: unitText = "[m3/day]"; break; case RiaEclipseUnitTools::UnitSystem::UNITS_FIELD: unitText = "[Brl/day]"; break; case RiaEclipseUnitTools::UnitSystem::UNITS_LAB: unitText = "[cm3/hr]"; break; default: break; } return unitText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellPlotTools::flowUnitText( RimWellLogFile::WellFlowCondition condition, RiaEclipseUnitTools::UnitSystem unitSystem ) { QString unitText; if ( condition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR ) { unitText = flowConditionReservoirUnitText( unitSystem ); } else { switch ( unitSystem ) { case RiaEclipseUnitTools::UnitSystem::UNITS_METRIC: unitText = "[Liquid Sm3/day], [Gas kSm3/day]"; break; case RiaEclipseUnitTools::UnitSystem::UNITS_FIELD: unitText = "[Liquid BBL/day], [Gas BOE/day]"; break; case RiaEclipseUnitTools::UnitSystem::UNITS_LAB: unitText = "[cm3/hr]"; break; default: break; } } return unitText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellPlotTools::curveUnitText( RimWellLogFile::WellFlowCondition condition, RiaEclipseUnitTools::UnitSystem unitSystem, FlowPhase flowPhase ) { QString unitText; if ( condition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR ) { unitText = flowConditionReservoirUnitText( unitSystem ); } else { switch ( unitSystem ) { case RiaEclipseUnitTools::UnitSystem::UNITS_METRIC: switch ( flowPhase ) { case FLOW_PHASE_GAS: unitText = "[kSm3/day]"; break; case FLOW_PHASE_WATER: // Intentionally fall through, water and oil have same unit case FLOW_PHASE_OIL: unitText = "[Sm3/day]"; break; default: unitText = "[Liquid Sm3/day], [Gas kSm3/day]"; break; } break; case RiaEclipseUnitTools::UnitSystem::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 RiaEclipseUnitTools::UnitSystem::UNITS_LAB: unitText = "[cm3/hr]"; break; default: break; } } return unitText; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map> RimWellPlotTools::calculateRelevantTimeStepsFromCases( const QString& wellPathNameOrSimWellName, const std::vector& selSources, const std::set& interestingRFTResults ) { bool addFirstTimestep = ( interestingRFTResults.count( RifEclipseRftAddress::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> observedTimeStepsWithSources; std::map> rftTimeStepsWithSources; std::map> gridTimestepsWithSources; std::map> summaryRftTimeStepsWithSources; std::map> 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 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 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 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 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 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> timestepsToShowWithSources; std::map>* 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 baseTimeSteps; for ( const auto& dateSourceSetPair : *timeBaseline ) baseTimeSteps.insert( dateSourceSetPair.first ); std::set rftTimeSteps; for ( const auto& dateSourceSetPair : rftTimeStepsWithSources ) rftTimeSteps.insert( dateSourceSetPair.first ); std::set gridTimeSteps; for ( const auto& dateSourceSetPair : gridTimestepsWithSources ) gridTimeSteps.insert( dateSourceSetPair.first ); std::set summaryRftTimeSteps; for ( const auto& dateSourceSetPair : summaryRftTimeStepsWithSources ) summaryRftTimeSteps.insert( dateSourceSetPair.first ); std::set ensembleRftTimeSteps; for ( const auto& dateSourceSetPair : ensembleTimeStepsWithSources ) ensembleRftTimeSteps.insert( dateSourceSetPair.first ); std::set filteredRftTimeSteps = RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, rftTimeSteps ); std::set filteredGridTimeSteps = RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, gridTimeSteps ); std::set filteredEnsembleRftTimeSteps = RimWellPlotTools::findMatchingOrAdjacentTimeSteps( baseTimeSteps, ensembleRftTimeSteps ); if ( addFirstTimestep && gridTimeSteps.size() ) { filteredGridTimeSteps.insert( *gridTimeSteps.begin() ); } // Fill final map timestepsToShowWithSources = observedTimeStepsWithSources; std::set& 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& sourceSet = rftTimeSourceSetIt->second; timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() ); } auto gridTimeSourceSetIt = gridTimestepsWithSources.find( time ); if ( gridTimeSourceSetIt != gridTimestepsWithSources.end() ) { std::set& sourceSet = gridTimeSourceSetIt->second; timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() ); } auto summaryRftTimeSourceSetIt = summaryRftTimeStepsWithSources.find( time ); if ( summaryRftTimeSourceSetIt != summaryRftTimeStepsWithSources.end() ) { std::set& sourceSet = summaryRftTimeSourceSetIt->second; timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() ); } auto ensembleRftTimeSourceSetIt = ensembleTimeStepsWithSources.find( time ); if ( ensembleRftTimeSourceSetIt != ensembleTimeStepsWithSources.end() ) { std::set& sourceSet = ensembleRftTimeSourceSetIt->second; timestepsToShowWithSources[time].insert( sourceSet.begin(), sourceSet.end() ); } } } else { timestepsToShowWithSources = gridTimestepsWithSources; } return timestepsToShowWithSources; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellPlotTools::calculateValueOptionsForTimeSteps( const QString& wellPathNameOrSimWellName, const std::vector& selSources, const std::set& interestingRFTResults, QList& options ) { auto timestepsToShowWithSources = calculateRelevantTimeStepsFromCases( wellPathNameOrSimWellName, selSources, interestingRFTResults ); // Create formatted options of all the time steps QString dateFormatString; { std::vector allTimeSteps; for ( const std::pair>& timeStepPair : timestepsToShowWithSources ) { allTimeSteps.push_back( timeStepPair.first ); } dateFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates( allTimeSteps ); } for ( const std::pair>& 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 ) ); } }