RFT ensemble refactoring

* Compute average MD for intersections with a cell
* Create extractor for simulation well
* Remove rftReader from RifDataSourceForRftPlt
* Add function compute measured depth for RFT cells based on well path geometry
* Move statistics reader to well ensemble curve set
* Make sure both TVD and MD are cached if possible
* Add selection of grid case to use for estimation of measured depth (MD)
Add "Grid Model For MD" where the user can select a grid model. This grid model is propagated to a hidden field in EnsembleCurveSet. The grid model is then applied to RifReaderEnsembleStatisticsRft owned by EnsembleCurveSet
This commit is contained in:
Magne Sjaastad 2023-09-04 10:08:30 +02:00 committed by GitHub
parent fe17b211b8
commit 7a782cec66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 627 additions and 428 deletions

View File

@ -18,11 +18,16 @@
#include "RiaExtractionTools.h"
#include "RiaSimWellBranchTools.h"
#include "RigWellPath.h"
#include "RimEclipseCase.h"
#include "RimMainPlotCollection.h"
#include "RimSimWellInView.h"
#include "RimTools.h"
#include "RimWellLogPlotCollection.h"
#include "RimWellPathCollection.h"
//--------------------------------------------------------------------------------------------------
///
@ -37,6 +42,22 @@ RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateWellLogExtractor( Ri
return wlPlotCollection->findOrCreateExtractor( wellPath, eclipseCase );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateWellLogExtractor( const QString& wellName, RimEclipseCase* eclipseCase )
{
if ( !eclipseCase ) return nullptr;
if ( auto wellPathCollection = RimTools::wellPathCollection() )
{
auto wellPath = wellPathCollection->tryFindMatchingWellPath( wellName );
return RiaExtractionTools::findOrCreateWellLogExtractor( wellPath, eclipseCase );
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -71,6 +92,33 @@ RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateSimWellExtractor( co
return wlPlotCollection->findOrCreateSimWellExtractor( simWell->name, caseUserDescription, wellPathGeom, eclipseCase->eclipseCaseData() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigEclipseWellLogExtractor* RiaExtractionTools::findOrCreateSimWellExtractor( RimEclipseCase* eclipseCase,
const QString& simWellName,
bool useBranchDetection,
int branchIndex )
{
if ( !eclipseCase ) return nullptr;
auto wlPlotCollection = wellLogPlotCollection();
if ( !wlPlotCollection ) return nullptr;
std::vector<const RigWellPath*> wellPaths = RiaSimWellBranchTools::simulationWellBranches( simWellName, useBranchDetection );
if ( wellPaths.empty() ) return nullptr;
branchIndex = RiaSimWellBranchTools::clampBranchIndex( simWellName, branchIndex, useBranchDetection );
if ( branchIndex >= static_cast<int>( wellPaths.size() ) ) return nullptr;
auto wellPathBranch = wellPaths[branchIndex];
return wlPlotCollection->findOrCreateSimWellExtractor( simWellName,
QString( "Find or create sim well extractor" ),
wellPathBranch,
eclipseCase->eclipseCaseData() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -36,11 +36,18 @@ class QString;
//==================================================================================================
namespace RiaExtractionTools
{
RigEclipseWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimEclipseCase* eclipseCase );
RigGeoMechWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimGeoMechCase* geomCase, int partId = 0 );
RigEclipseWellLogExtractor* findOrCreateSimWellExtractor( const RimSimWellInView* simWell, const RigWellPath* wellPathGeom );
RimWellLogPlotCollection* wellLogPlotCollection();
// Eclipse
RigEclipseWellLogExtractor* findOrCreateWellLogExtractor( const QString& wellName, RimEclipseCase* eclipseCase );
RigEclipseWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimEclipseCase* eclipseCase );
// GeoMech
RigGeoMechWellLogExtractor* findOrCreateWellLogExtractor( RimWellPath* wellPath, RimGeoMechCase* geomCase, int partId = 0 );
// Simulation wells
RigEclipseWellLogExtractor* findOrCreateSimWellExtractor( const RimSimWellInView* simWell, const RigWellPath* wellPathGeom );
RigEclipseWellLogExtractor*
findOrCreateSimWellExtractor( RimEclipseCase* eclipseCase, const QString& simWellName, bool useBranchDetection, int branchIndex );
}; // namespace RiaExtractionTools

View File

@ -356,7 +356,7 @@ RimWellLogRftCurve* RicWellLogTools::addRftCurve( RimWellLogTrack* plotTrack, co
if ( simWell && resultCase )
{
curve->setEclipseResultCase( resultCase );
curve->setEclipseCase( resultCase );
curve->setDefaultAddress( simWell->name() );
plotTrack->setFormationCase( resultCase );
@ -364,7 +364,7 @@ RimWellLogRftCurve* RicWellLogTools::addRftCurve( RimWellLogTrack* plotTrack, co
}
else if ( resultCase )
{
curve->setEclipseResultCase( resultCase );
curve->setEclipseCase( resultCase );
auto wellNames = resultCase->rftReader()->wellNames();
if ( !wellNames.empty() )

View File

@ -18,7 +18,6 @@
#include "RifDataSourceForRftPlt.h"
#include "RifReaderEclipseRft.h"
#include "RigEclipseCaseData.h"
#include "RimEclipseCase.h"
@ -230,37 +229,6 @@ auto RifDataSourceForRftPlt::operator<=>( const RifDataSourceForRftPlt& addr2 )
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RifDataSourceForRftPlt::rftReader() const
{
if ( m_sourceType == SourceType::GRID_MODEL_CELL_DATA || m_sourceType == SourceType::RFT_SIM_WELL_DATA )
{
// TODO: Consider changing to RimEclipseResultCase to avoid casting
auto eclResCase = dynamic_cast<RimEclipseResultCase*>( eclCase() );
if ( eclResCase ) return eclResCase->rftReader();
}
else if ( m_sourceType == SourceType::SUMMARY_RFT )
{
if ( m_summaryCase ) return m_summaryCase->rftReader();
}
else if ( m_sourceType == SourceType::ENSEMBLE_RFT )
{
if ( m_ensemble ) return m_ensemble->rftStatisticsReader();
}
else if ( m_sourceType == SourceType::OBSERVED_FMU_RFT )
{
if ( m_observedFmuRftData ) return m_observedFmuRftData->rftReader();
}
else if ( m_sourceType == SourceType::OBSERVED_PRESSURE_DEPTH )
{
if ( m_pressureDepthData ) return m_pressureDepthData->rftReader();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -31,7 +31,6 @@
class RimWellLogFile;
class RimEclipseCase;
class RifReaderRftInterface;
class RimSummaryCase;
class RimSummaryCaseCollection;
class RimObservedFmuRftData;
@ -64,8 +63,7 @@ public:
RifDataSourceForRftPlt( RimObservedFmuRftData* observedFmuRftData );
RifDataSourceForRftPlt( RimPressureDepthData* pressureDepthData );
SourceType sourceType() const;
RifReaderRftInterface* rftReader() const;
SourceType sourceType() const;
RimEclipseCase* eclCase() const;
RimSummaryCase* summaryCase() const;

View File

@ -246,19 +246,17 @@ void RifReaderEclipseRft::values( const RifEclipseRftAddress& rftAddress, std::v
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseRft::cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices )
std::vector<caf::VecIjk> RifReaderEclipseRft::cellIndices( const QString& wellName, const QDateTime& timeStep )
{
CVF_ASSERT( indices );
if ( !m_ecl_rft_file )
{
open();
}
indices->clear();
int index = indexFromAddress( wellName, timeStep );
if ( index < 0 ) return {};
int index = indexFromAddress( rftAddress );
if ( index < 0 ) return;
std::vector<caf::VecIjk> indices;
ecl_rft_node_type* node = ecl_rft_file_iget_node( m_ecl_rft_file, index );
@ -268,8 +266,10 @@ void RifReaderEclipseRft::cellIndices( const RifEclipseRftAddress& rftAddress, s
ecl_rft_node_iget_ijk( node, cellIdx, &i, &j, &k );
caf::VecIjk ijk( (size_t)i, (size_t)j, (size_t)k );
indices->push_back( ijk );
indices.push_back( ijk );
}
return indices;
}
//--------------------------------------------------------------------------------------------------
@ -453,3 +453,19 @@ int RifReaderEclipseRft::indexFromAddress( const RifEclipseRftAddress& rftAddres
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RifReaderEclipseRft::indexFromAddress( const QString& wellName, const QDateTime& timeStep ) const
{
for ( const auto& [rftAddr, nodeIdx] : m_rftAddressToLibeclNodeIdx )
{
if ( rftAddr.wellName() == wellName && rftAddr.timeStep() == timeStep )
{
return nodeIdx;
}
}
return -1;
}

View File

@ -45,7 +45,7 @@ public:
std::set<RifEclipseRftAddress> eclipseRftAddresses() override;
void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) override;
void cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices ) override;
std::vector<caf::VecIjk> cellIndices( const QString& wellName, const QDateTime& timeStep ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName ) override;
std::set<QDateTime> availableTimeSteps( const QString& wellName,
@ -60,6 +60,7 @@ public:
private:
void open();
int indexFromAddress( const RifEclipseRftAddress& rftAddress ) const;
int indexFromAddress( const QString& wellName, const QDateTime& timeStep ) const;
private:
// NOLINTBEGIN(modernize-use-using)

View File

@ -18,20 +18,23 @@
#include "RifReaderEnsembleStatisticsRft.h"
#include "RiaCurveMerger.h"
#include "RiaWeightedMeanCalculator.h"
#include "RiaExtractionTools.h"
#include "RigStatisticsMath.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimTools.h"
#include "cafAssert.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderEnsembleStatisticsRft::RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection )
RifReaderEnsembleStatisticsRft::RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection,
RimEclipseCase* eclipseCase )
: m_summaryCaseCollection( summaryCaseCollection )
, m_eclipseCase( eclipseCase )
{
}
@ -40,6 +43,8 @@ RifReaderEnsembleStatisticsRft::RifReaderEnsembleStatisticsRft( const RimSummary
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress> RifReaderEnsembleStatisticsRft::eclipseRftAddresses()
{
if ( !m_summaryCaseCollection ) return {};
std::set<RifEclipseRftAddress> allAddresses;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -78,7 +83,10 @@ std::set<RifEclipseRftAddress> RifReaderEnsembleStatisticsRft::eclipseRftAddress
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values )
{
CAF_ASSERT( rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::TVD ||
if ( !m_summaryCaseCollection ) return;
CAF_ASSERT( rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::MD ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::TVD ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_MEAN ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P10 ||
rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50 ||
@ -88,7 +96,7 @@ void RifReaderEnsembleStatisticsRft::values( const RifEclipseRftAddress& rftAddr
auto it = m_cachedValues.find( rftAddress );
if ( it == m_cachedValues.end() )
{
calculateStatistics( rftAddress );
calculateStatistics( rftAddress.wellName(), rftAddress.timeStep() );
}
*values = m_cachedValues[rftAddress];
}
@ -98,6 +106,8 @@ void RifReaderEnsembleStatisticsRft::values( const RifEclipseRftAddress& rftAddr
//--------------------------------------------------------------------------------------------------
std::set<QDateTime> RifReaderEnsembleStatisticsRft::availableTimeSteps( const QString& wellName )
{
if ( !m_summaryCaseCollection ) return {};
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -116,6 +126,8 @@ std::set<QDateTime> RifReaderEnsembleStatisticsRft::availableTimeSteps( const QS
std::set<QDateTime> RifReaderEnsembleStatisticsRft::availableTimeSteps( const QString& wellName,
const RifEclipseRftAddress::RftWellLogChannelType& wellLogChannelName )
{
if ( !m_summaryCaseCollection ) return {};
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -135,6 +147,8 @@ std::set<QDateTime>
RifReaderEnsembleStatisticsRft::availableTimeSteps( const QString& wellName,
const std::set<RifEclipseRftAddress::RftWellLogChannelType>& relevantChannels )
{
if ( !m_summaryCaseCollection ) return {};
std::set<QDateTime> allTimeSteps;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -152,6 +166,8 @@ std::set<QDateTime>
//--------------------------------------------------------------------------------------------------
std::set<RifEclipseRftAddress::RftWellLogChannelType> RifReaderEnsembleStatisticsRft::availableWellLogChannels( const QString& wellName )
{
if ( !m_summaryCaseCollection ) return {};
std::set<RifEclipseRftAddress::RftWellLogChannelType> allWellLogChannels;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -170,6 +186,8 @@ std::set<RifEclipseRftAddress::RftWellLogChannelType> RifReaderEnsembleStatistic
//--------------------------------------------------------------------------------------------------
std::set<QString> RifReaderEnsembleStatisticsRft::wellNames()
{
if ( !m_summaryCaseCollection ) return {};
std::set<QString> allWellNames;
for ( auto summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
@ -185,47 +203,110 @@ std::set<QString> RifReaderEnsembleStatisticsRft::wellNames()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::calculateStatistics( const RifEclipseRftAddress& rftAddress )
void RifReaderEnsembleStatisticsRft::calculateStatistics( const QString& wellName, const QDateTime& timeStep )
{
const QString& wellName = rftAddress.wellName();
const QDateTime& timeStep = rftAddress.timeStep();
RifEclipseRftAddress depthAddress =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::TVD );
RifEclipseRftAddress pressAddress =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::PRESSURE );
if ( !m_summaryCaseCollection ) return;
RifEclipseRftAddress p10Address =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P10 );
RifEclipseRftAddress p50Address =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50 );
RifEclipseRftAddress p90Address =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P90 );
RifEclipseRftAddress meanAddress =
RifEclipseRftAddress::createAddress( wellName, timeStep, RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_MEAN );
using ChannelType = RifEclipseRftAddress::RftWellLogChannelType;
RifEclipseRftAddress pressAddress = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::PRESSURE );
RifEclipseRftAddress tvdAddress = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::TVD );
RiaCurveMerger<double> curveMerger;
RiaWeightedMeanCalculator<size_t> dataSetSizeCalc;
for ( RimSummaryCase* summaryCase : m_summaryCaseCollection->allSummaryCases() )
RigEclipseWellLogExtractor* extractor = RiaExtractionTools::findOrCreateWellLogExtractor( wellName, m_eclipseCase );
if ( extractor )
{
RifReaderRftInterface* reader = summaryCase->rftReader();
if ( reader )
// Create a well log extractor if a well path and an Eclipse case is defined
// Use the extractor to compute measured depth for RFT cells
// The TVD values is extracted from the first summary case
RifEclipseRftAddress mdAddress = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::MD );
RiaCurveMerger<double> curveMerger;
RiaWeightedMeanCalculator<size_t> dataSetSizeCalc;
std::vector<double> tvdDepthsForFirstRftCase;
for ( RimSummaryCase* summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
std::vector<double> depths;
auto reader = summaryCase->rftReader();
if ( !reader ) continue;
std::vector<double> pressures;
reader->values( depthAddress, &depths );
reader->values( pressAddress, &pressures );
if ( !depths.empty() && !pressures.empty() )
if ( tvdDepthsForFirstRftCase.empty() )
{
dataSetSizeCalc.addValueAndWeight( depths.size(), 1.0 );
curveMerger.addCurveData( depths, pressures );
reader->values( tvdAddress, &tvdDepthsForFirstRftCase );
}
std::vector<double> measuredDepths = reader->computeMeasuredDepth( wellName, timeStep, extractor );
if ( !measuredDepths.empty() && !pressures.empty() )
{
dataSetSizeCalc.addValueAndWeight( measuredDepths.size(), 1.0 );
curveMerger.addCurveData( measuredDepths, pressures );
}
}
}
curveMerger.computeInterpolatedValues( false );
clearData( wellName, timeStep );
extractStatisticsFromCurveMerger( wellName, timeStep, mdAddress, curveMerger, dataSetSizeCalc );
if ( m_cachedValues[mdAddress].size() == tvdDepthsForFirstRftCase.size() )
{
// The number of RFT cells can vary between realizations in some cases. TVD depth is only given if the number of RFT cells is
// identical between realizations.
m_cachedValues[tvdAddress] = tvdDepthsForFirstRftCase;
}
}
else
{
// Compute statistics based on TVD depths. No measured depth can be estimated.
// This concept works well for vertical wells, but does not work for horizontal wells.
RiaCurveMerger<double> curveMerger;
RiaWeightedMeanCalculator<size_t> dataSetSizeCalc;
RifEclipseRftAddress tvdAddress = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::TVD );
for ( RimSummaryCase* summaryCase : m_summaryCaseCollection->allSummaryCases() )
{
auto reader = summaryCase->rftReader();
if ( !reader ) continue;
std::vector<double> pressures;
reader->values( pressAddress, &pressures );
std::vector<double> tvdDepths;
reader->values( tvdAddress, &tvdDepths );
if ( !tvdDepths.empty() && !pressures.empty() )
{
dataSetSizeCalc.addValueAndWeight( tvdDepths.size(), 1.0 );
curveMerger.addCurveData( tvdDepths, pressures );
}
}
extractStatisticsFromCurveMerger( wellName, timeStep, tvdAddress, curveMerger, dataSetSizeCalc );
}
}
//--------------------------------------------------------------------------------------------------
/// Compute statistics for values, either based on measured depth or TVD
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::extractStatisticsFromCurveMerger( const QString& wellName,
const QDateTime& timeStep,
RifEclipseRftAddress depthAddress,
RiaCurveMerger<double>& curveMerger,
RiaWeightedMeanCalculator<size_t>& dataSetSizeCalc )
{
using ChannelType = RifEclipseRftAddress::RftWellLogChannelType;
CAF_ASSERT( depthAddress.wellLogChannel() == ChannelType::MD || depthAddress.wellLogChannel() == ChannelType::TVD );
auto p10Address = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::PRESSURE_P10 );
auto p50Address = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::PRESSURE_P50 );
auto p90Address = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::PRESSURE_P90 );
auto meanAddress = RifEclipseRftAddress::createAddress( wellName, timeStep, ChannelType::PRESSURE_MEAN );
clearCache( wellName, timeStep );
curveMerger.computeInterpolatedValues( false );
const std::vector<double>& allDepths = curveMerger.allXValues();
if ( !allDepths.empty() )
@ -259,7 +340,7 @@ void RifReaderEnsembleStatisticsRft::calculateStatistics( const RifEclipseRftAdd
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEnsembleStatisticsRft::clearData( const QString& wellName, const QDateTime& timeStep )
void RifReaderEnsembleStatisticsRft::clearCache( const QString& wellName, const QDateTime& timeStep )
{
for ( auto it = m_cachedValues.begin(); it != m_cachedValues.end(); )
{

View File

@ -20,14 +20,18 @@
#include "RifReaderEclipseRft.h"
#include "RiaCurveMerger.h"
#include "RiaWeightedMeanCalculator.h"
#include "cvfObject.h"
class RimSummaryCaseCollection;
class RimEclipseCase;
class RifReaderEnsembleStatisticsRft : public RifReaderRftInterface, public cvf::Object
{
public:
RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection );
RifReaderEnsembleStatisticsRft( const RimSummaryCaseCollection* summaryCaseCollection, RimEclipseCase* eclipseCase );
std::set<RifEclipseRftAddress> eclipseRftAddresses() override;
void values( const RifEclipseRftAddress& rftAddress, std::vector<double>* values ) override;
@ -41,11 +45,19 @@ public:
std::set<QString> wellNames() override;
private:
void calculateStatistics( const RifEclipseRftAddress& rftAddress );
void clearData( const QString& wellName, const QDateTime& timeStep );
void calculateStatistics( const QString& wellName, const QDateTime& timeStep );
void extractStatisticsFromCurveMerger( const QString& wellName,
const QDateTime& timeStep,
RifEclipseRftAddress depthAddress,
RiaCurveMerger<double>& curveMerger,
RiaWeightedMeanCalculator<size_t>& dataSetSizeCalc );
void clearCache( const QString& wellName, const QDateTime& timeStep );
private:
const RimSummaryCaseCollection* m_summaryCaseCollection;
RimEclipseCase* m_eclipseCase;
std::map<RifEclipseRftAddress, std::vector<double>> m_cachedValues;
};

View File

@ -272,40 +272,44 @@ std::set<QString> RifReaderOpmRft::wellNames()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderOpmRft::cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices )
std::vector<caf::VecIjk> RifReaderOpmRft::cellIndices( const QString& wellName, const QDateTime& timeStep )
{
if ( !openFiles() ) return;
if ( !openFiles() ) return {};
auto wellName = rftAddress.wellName().toStdString();
auto stdWellName = wellName.toStdString();
auto date = rftAddress.timeStep().date();
auto date = timeStep.date();
int y = date.year();
int m = date.month();
int d = date.day();
std::vector<caf::VecIjk> indices;
try
{
auto resultNameI = "CONIPOS";
auto dataI = m_opm_rft->getRft<int>( resultNameI, wellName, y, m, d );
auto dataI = m_opm_rft->getRft<int>( resultNameI, stdWellName, y, m, d );
auto resultNameJ = "CONJPOS";
auto dataJ = m_opm_rft->getRft<int>( resultNameJ, wellName, y, m, d );
auto dataJ = m_opm_rft->getRft<int>( resultNameJ, stdWellName, y, m, d );
auto resultNameK = "CONKPOS";
auto dataK = m_opm_rft->getRft<int>( resultNameK, wellName, y, m, d );
auto dataK = m_opm_rft->getRft<int>( resultNameK, stdWellName, y, m, d );
if ( !dataI.empty() && ( dataI.size() == dataJ.size() ) && ( dataI.size() == dataK.size() ) )
{
for ( size_t n = 0; n < dataI.size(); n++ )
{
// NB: Transform to zero-based cell indices
indices->push_back( caf::VecIjk( dataI[n] - 1, dataJ[n] - 1, dataK[n] - 1 ) );
indices.push_back( caf::VecIjk( dataI[n] - 1, dataJ[n] - 1, dataK[n] - 1 ) );
}
}
}
catch ( ... )
{
}
return indices;
}
//--------------------------------------------------------------------------------------------------

View File

@ -50,7 +50,7 @@ public:
std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) override;
std::set<QString> wellNames() override;
void cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices ) override;
std::vector<caf::VecIjk> cellIndices( const QString& wellName, const QDateTime& timeStep ) override;
std::map<int, int> branchIdsAndOneBasedIndices( const QString& wellName, const QDateTime& timeStep, RiaDefines::RftBranchType branchType );

View File

@ -15,8 +15,17 @@
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifReaderRftInterface.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseWellLogExtractor.h"
#include "RigMainGrid.h"
#include "RigWellPath.h"
#include "RigWellPathGeometryTools.h"
#include "cafVecIjk.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -34,9 +43,104 @@ std::set<RifEclipseRftAddress> RifReaderRftInterface::eclipseRftAddresses( const
return matchingAddresses;
}
//--------------------------------------------------------------------------------------------------
// Compute average measured depth for cell based on grid intersections for cells. If the well path geometry do not contain measured depth
// for a grid cell, the measured depth is estimated based on existing geometry for the well path.
//--------------------------------------------------------------------------------------------------
std::vector<double>
RifReaderRftInterface::computeMeasuredDepth( const QString& wellName, const QDateTime& timeStep, RigEclipseWellLogExtractor* eclExtractor )
{
if ( !eclExtractor ) return {};
if ( !eclExtractor->caseData() ) return {};
if ( eclExtractor->cellIntersectionMDs().empty() ) return {};
auto mainGrid = eclExtractor->caseData()->mainGrid();
if ( !mainGrid ) return {};
std::vector<double> avgMeasuredDepthForCells;
std::vector<double> tvdValuesToEstimate;
auto cellIjk = cellIndices( wellName, timeStep );
for ( const caf::VecIjk& ijk : cellIjk )
{
auto globalCellIndex = mainGrid->cellIndexFromIJK( ijk.i(), ijk.j(), ijk.k() );
auto avgMd = eclExtractor->averageMdForCell( globalCellIndex );
if ( avgMd.has_value() )
{
avgMeasuredDepthForCells.push_back( avgMd.value() );
}
else
{
// The RFT cell is not part of cells intersected by well path
// Use the TVD of cell center to estimate measured depth
avgMeasuredDepthForCells.push_back( std::numeric_limits<double>::infinity() );
auto center = mainGrid->cell( globalCellIndex ).center();
tvdValuesToEstimate.push_back( -center.z() );
}
}
if ( !tvdValuesToEstimate.empty() )
{
auto wellPathMd = eclExtractor->wellPathGeometry()->measuredDepths();
auto wellPathTvd = eclExtractor->wellPathGeometry()->trueVerticalDepths();
// Estimate measured depth for cells that do not have measured depth
auto estimatedMeasuredDepth = RigWellPathGeometryTools::interpolateMdFromTvd( wellPathMd, wellPathTvd, tvdValuesToEstimate );
double previousMd = std::numeric_limits<double>::infinity();
// Replace infinity MD values with estimated MD values based on well path geometry
// previousMd contains the last known measured depth value as we move along the well path
size_t estimatedIndex = 0;
for ( auto& measuredDepth : avgMeasuredDepthForCells )
{
if ( measuredDepth == std::numeric_limits<double>::infinity() )
{
// No measured depth for cell is found, try to estimate MD based on MD for previous cell
if ( estimatedIndex < estimatedMeasuredDepth.size() )
{
double estimatedMd = estimatedMeasuredDepth[estimatedIndex++];
if ( previousMd != std::numeric_limits<double>::infinity() )
{
if ( previousMd < estimatedMd )
{
// The estimated MD is larger than previous MD, use the estimated MD
measuredDepth = estimatedMd;
}
else
{
// The estimated MD is smaller than previous MD, use the previous MD + 1.0
measuredDepth = previousMd + 1.0;
}
}
else
{
// We do not have a valid previous MD, use the estimated MD
measuredDepth = estimatedMd;
}
}
else
{
measuredDepth = previousMd + 1.0;
}
}
// Assign the current MD as previous MD to be used for next estimated MD
previousMd = measuredDepth;
}
}
return avgMeasuredDepthForCells;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderRftInterface::cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices )
std::vector<caf::VecIjk> RifReaderRftInterface::cellIndices( const QString& wellName, const QDateTime& timeStep )
{
return {};
}

View File

@ -31,6 +31,8 @@ namespace caf
class VecIjk;
};
class RigEclipseWellLogExtractor;
class RifReaderRftInterface
{
public:
@ -46,5 +48,9 @@ public:
virtual std::set<RifEclipseRftAddress::RftWellLogChannelType> availableWellLogChannels( const QString& wellName ) = 0;
virtual std::set<QString> wellNames() = 0;
virtual void cellIndices( const RifEclipseRftAddress& rftAddress, std::vector<caf::VecIjk>* indices );
// To be moved into Rig structures
std::vector<double> computeMeasuredDepth( const QString& wellName, const QDateTime& timeStep, RigEclipseWellLogExtractor* extractor );
// TODO: Move to protected or private
virtual std::vector<caf::VecIjk> cellIndices( const QString& wellName, const QDateTime& timeStep );
};

View File

@ -597,6 +597,18 @@ std::set<QDateTime> RimWellPlotTools::availableSimWellTimesteps( RimEclipseCase*
return availebleTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RimWellPlotTools::rftReaderInterface( RimEclipseCase* eclipseCase )
{
auto eclResCase = dynamic_cast<RimEclipseResultCase*>( eclipseCase );
if ( eclResCase ) return eclResCase->rftReader();
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -608,7 +620,7 @@ RiaRftPltCurveDefinition RimWellPlotTools::curveDefFromCurve( const RimWellLogCu
if ( rftCurve != nullptr )
{
RimEclipseResultCase* rftCase = dynamic_cast<RimEclipseResultCase*>( rftCurve->eclipseResultCase() );
RimEclipseResultCase* rftCase = dynamic_cast<RimEclipseResultCase*>( rftCurve->eclipseCase() );
RimSummaryCase* rftSummaryCase = rftCurve->summaryCase();
RimSummaryCaseCollection* rftEnsemble = rftCurve->ensemble();
RimObservedFmuRftData* rftFmuData = rftCurve->observedFmuRftData();
@ -739,9 +751,10 @@ std::set<RiaRftPltCurveDefinition>
for ( const RifDataSourceForRftPlt& addr : selectedSourcesExpanded )
{
if ( addr.sourceType() == RifDataSourceForRftPlt::SourceType::RFT_SIM_WELL_DATA && addr.rftReader() )
auto rftReader = rftReaderInterface( addr.eclCase() );
if ( addr.sourceType() == RifDataSourceForRftPlt::SourceType::RFT_SIM_WELL_DATA && rftReader )
{
std::set<QDateTime> rftTimes = addr.rftReader()->availableTimeSteps( simWellName, interestingRFTResults );
std::set<QDateTime> rftTimes = rftReader->availableTimeSteps( simWellName, interestingRFTResults );
for ( const QDateTime& time : rftTimes )
{
if ( selectedTimeStepSet.count( time ) )
@ -1149,21 +1162,26 @@ std::map<QDateTime, std::set<RifDataSourceForRftPlt>>
}
}
}
hasObservedData = !observedTimeStepsWithSources.empty();
}
if ( hasRftData )
{
for ( const auto& source : selSources )
{
if ( source.sourceType() == RifDataSourceForRftPlt::SourceType::RFT_SIM_WELL_DATA && source.rftReader() )
auto rftReader = rftReaderInterface( source.eclCase() );
if ( source.sourceType() == RifDataSourceForRftPlt::SourceType::RFT_SIM_WELL_DATA && rftReader )
{
std::set<QDateTime> rftTimes = source.rftReader()->availableTimeSteps( simWellName, interestingRFTResults );
std::set<QDateTime> rftTimes = rftReader->availableTimeSteps( simWellName, interestingRFTResults );
for ( const QDateTime& date : rftTimes )
{
rftTimeStepsWithSources[date].insert( source );
}
}
}
hasRftData = !rftTimeStepsWithSources.empty();
}
if ( hasGridData )
@ -1181,6 +1199,8 @@ std::map<QDateTime, std::set<RifDataSourceForRftPlt>>
}
}
}
hasGridData = !gridTimestepsWithSources.empty();
}
if ( hasSummaryRftData )
@ -1198,6 +1218,8 @@ std::map<QDateTime, std::set<RifDataSourceForRftPlt>>
}
}
}
hasSummaryRftData = !summaryRftTimeStepsWithSources.empty();
}
if ( hasEnsembleData )
@ -1214,34 +1236,36 @@ std::map<QDateTime, std::set<RifDataSourceForRftPlt>>
}
}
}
hasEnsembleData = !ensembleTimeStepsWithSources.empty();
}
// 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;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> timestepsToShowWithSources;
std::map<QDateTime, std::set<RifDataSourceForRftPlt>> timeBaseline;
if ( hasObservedData )
{
timeBaseline = &observedTimeStepsWithSources;
timeBaseline = observedTimeStepsWithSources;
}
else if ( hasRftData )
{
timeBaseline = &rftTimeStepsWithSources;
timeBaseline = rftTimeStepsWithSources;
}
else if ( hasSummaryRftData )
{
timeBaseline = &summaryRftTimeStepsWithSources;
timeBaseline = summaryRftTimeStepsWithSources;
}
else if ( hasEnsembleData )
{
timeBaseline = &ensembleTimeStepsWithSources;
timeBaseline = ensembleTimeStepsWithSources;
}
if ( timeBaseline )
if ( !timeBaseline.empty() )
{
std::set<QDateTime> baseTimeSteps;
for ( const auto& dateSourceSetPair : *timeBaseline )
for ( const auto& dateSourceSetPair : timeBaseline )
baseTimeSteps.insert( dateSourceSetPair.first );
std::set<QDateTime> rftTimeSteps;

View File

@ -43,6 +43,7 @@ class RimPressureDepthData;
class RiuWellRftPlot;
class RigEclipseCaseData;
class RigEclipseResultAddress;
class RifReaderRftInterface;
//==================================================================================================
///
@ -153,4 +154,6 @@ private:
static std::set<QDateTime> findMatchingOrAdjacentTimeSteps( const std::set<QDateTime>& baseTimeLine,
const std::set<QDateTime>& availableTimeSteps );
static std::set<QDateTime> availableSimWellTimesteps( RimEclipseCase* eclCase, const QString& simWellName, bool addFirstReportTimeStep );
static RifReaderRftInterface* rftReaderInterface( RimEclipseCase* eclipseCase );
};

View File

@ -295,20 +295,16 @@ class RigRftResultPointCalculator : public RigResultPointCalculator
public:
RigRftResultPointCalculator( const QString& wellPathName, RimEclipseResultCase* eclCase, QDateTime m_timeStep )
{
RifEclipseRftAddress gasRateAddress = RifEclipseRftAddress::createAddress( RimWellPlotTools::simWellName( wellPathName ),
m_timeStep,
RifEclipseRftAddress::RftWellLogChannelType::GRAT );
RifEclipseRftAddress oilRateAddress = RifEclipseRftAddress::createAddress( RimWellPlotTools::simWellName( wellPathName ),
m_timeStep,
RifEclipseRftAddress::RftWellLogChannelType::ORAT );
RifEclipseRftAddress watRateAddress = RifEclipseRftAddress::createAddress( RimWellPlotTools::simWellName( wellPathName ),
m_timeStep,
RifEclipseRftAddress::RftWellLogChannelType::WRAT );
const auto wellNameForRft = RimWellPlotTools::simWellName( wellPathName );
std::vector<caf::VecIjk> rftIndices;
eclCase->rftReader()->cellIndices( gasRateAddress, &rftIndices );
if ( rftIndices.empty() ) eclCase->rftReader()->cellIndices( oilRateAddress, &rftIndices );
if ( rftIndices.empty() ) eclCase->rftReader()->cellIndices( watRateAddress, &rftIndices );
RifEclipseRftAddress gasRateAddress =
RifEclipseRftAddress::createAddress( wellNameForRft, m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::GRAT );
RifEclipseRftAddress oilRateAddress =
RifEclipseRftAddress::createAddress( wellNameForRft, m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::ORAT );
RifEclipseRftAddress watRateAddress =
RifEclipseRftAddress::createAddress( wellNameForRft, m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::WRAT );
std::vector<caf::VecIjk> rftIndices = eclCase->rftReader()->cellIndices( wellNameForRft, m_timeStep );
if ( rftIndices.empty() ) return;
std::vector<double> gasRates;

View File

@ -18,10 +18,14 @@
#include "RimWellRftEnsembleCurveSet.h"
#include "RifReaderEnsembleStatisticsRft.h"
#include "RimEclipseCase.h"
#include "RimEnsembleCurveSetColorManager.h"
#include "RimRegularLegendConfig.h"
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimTools.h"
#include "RimWellRftPlot.h"
#include "RiuQwtPlotWidget.h"
@ -59,6 +63,9 @@ RimWellRftEnsembleCurveSet::RimWellRftEnsembleCurveSet()
m_ensembleLegendConfig = new RimRegularLegendConfig();
m_ensembleLegendConfig->setColorLegend(
RimRegularLegendConfig::mapToColorLegend( RimEnsembleCurveSetColorManager::DEFAULT_ENSEMBLE_COLOR_RANGE ) );
CAF_PDM_InitFieldNoDefault( &m_eclipseCase, "EclipseResultCase", "Eclipse Result Case" );
m_eclipseCase.uiCapability()->setUiHidden( true );
}
//--------------------------------------------------------------------------------------------------
@ -76,9 +83,14 @@ RimSummaryCaseCollection* RimWellRftEnsembleCurveSet::ensemble() const
return m_ensemble;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellRftEnsembleCurveSet::setEnsemble( RimSummaryCaseCollection* ensemble )
{
m_ensemble = ensemble;
clearEnsembleStatistics();
}
//--------------------------------------------------------------------------------------------------
@ -150,6 +162,22 @@ std::vector<QString> RimWellRftEnsembleCurveSet::parametersWithVariation() const
return std::vector<QString>( paramSet.begin(), paramSet.end() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellRftEnsembleCurveSet::clearEnsembleStatistics()
{
m_statisticsEclipseRftReader = new RifReaderEnsembleStatisticsRft( m_ensemble(), m_eclipseCase() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellRftEnsembleCurveSet::initAfterRead()
{
clearEnsembleStatistics();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -177,6 +205,31 @@ RigEnsembleParameter::Type RimWellRftEnsembleCurveSet::currentEnsembleParameterT
return RigEnsembleParameter::TYPE_NONE;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellRftEnsembleCurveSet::setEclipseCase( RimEclipseCase* eclipseCase )
{
m_eclipseCase = eclipseCase;
clearEnsembleStatistics();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseCase* RimWellRftEnsembleCurveSet::eclipseCase() const
{
return m_eclipseCase();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RimWellRftEnsembleCurveSet::statisticsEclipseRftReader()
{
return m_statisticsEclipseRftReader.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -188,6 +241,10 @@ void RimWellRftEnsembleCurveSet::fieldChangedByUi( const caf::PdmFieldHandle* ch
rftPlot->syncCurvesFromUiSelection();
rftPlot->updateConnectedEditors();
}
else if ( changedField == &m_eclipseCase )
{
clearEnsembleStatistics();
}
}
//--------------------------------------------------------------------------------------------------
@ -203,6 +260,12 @@ QList<caf::PdmOptionItemInfo> RimWellRftEnsembleCurveSet::calculateValueOptions(
options.push_back( caf::PdmOptionItemInfo( param, param ) );
}
}
else if ( fieldNeedingOptions == &m_eclipseCase )
{
RimTools::caseOptionItems( &options );
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
}
return options;
}
@ -218,6 +281,9 @@ void RimWellRftEnsembleCurveSet::defineUiOrdering( QString uiConfigName, caf::Pd
{
colorsGroup->add( &m_ensembleParameter );
}
uiOrdering.add( &m_eclipseCase );
uiOrdering.skipRemainingFields( true );
}

View File

@ -32,6 +32,9 @@
class RiuCvfOverlayItemWidget;
class RimSummaryCaseCollection;
class RimEclipseCase;
class RifReaderEnsembleStatisticsRft;
class RifReaderRftInterface;
class RimWellRftEnsembleCurveSet : public caf::PdmObject
{
@ -57,6 +60,11 @@ public:
RimRegularLegendConfig* legendConfig();
RigEnsembleParameter::Type currentEnsembleParameterType() const;
void setEclipseCase( RimEclipseCase* eclipseCase );
RimEclipseCase* eclipseCase() const;
RifReaderRftInterface* statisticsEclipseRftReader();
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
@ -69,11 +77,18 @@ protected:
private:
QString ensembleName() const;
std::vector<QString> parametersWithVariation() const;
void clearEnsembleStatistics();
private:
caf::PdmPtrField<RimEclipseCase*> m_eclipseCase;
caf::PdmPtrField<RimSummaryCaseCollection*> m_ensemble;
caf::PdmProxyValueField<QString> m_ensembleName;
caf::PdmField<ColorModeEnum> m_ensembleColorMode;
caf::PdmField<QString> m_ensembleParameter;
caf::PdmChildField<RimRegularLegendConfig*> m_ensembleLegendConfig;
cvf::ref<RifReaderEnsembleStatisticsRft> m_statisticsEclipseRftReader;
protected:
void initAfterRead() override;
};

View File

@ -59,6 +59,7 @@
#include "RimWellPathCollection.h"
#include "RimWellPlotTools.h"
#include "RimWellPltPlot.h"
#include "RimWellRftEnsembleCurveSet.h"
#include "RiuAbstractLegendFrame.h"
#include "RiuAbstractOverlayContentFrame.h"
@ -123,6 +124,10 @@ RimWellRftPlot::RimWellRftPlot()
m_selectedTimeSteps.uiCapability()->setAutoAddingOptionFromValue( false );
CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSets, "EnsembleCurveSets", "Ensemble Curve Sets" );
CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSetEclipseCase,
"EclipseResultCase",
"Grid Model For MD",
"Grid model used to compute measured depth using well path geometry" );
// TODO: may want to support TRUE_VERTICAL_DEPTH_RKB in the future
// It was developed for regular well log plots and requires some more work for RFT plots.
@ -496,7 +501,7 @@ void RimWellRftPlot::updateCurvesInPlot( const std::set<RiaRftPltCurveDefinition
plotTrack->addCurve( curve );
auto rftCase = curveDefToAdd.address().eclCase();
curve->setEclipseResultCase( dynamic_cast<RimEclipseResultCase*>( rftCase ) );
curve->setEclipseCase( rftCase );
RifEclipseRftAddress address = RifEclipseRftAddress::createAddress( simWellName,
curveDefToAdd.timeStep(),
@ -534,8 +539,8 @@ void RimWellRftPlot::updateCurvesInPlot( const std::set<RiaRftPltCurveDefinition
{
auto curve = new RimWellLogRftCurve();
plotTrack->addCurve( curve );
auto rftCase = curveDefToAdd.address().summaryCase();
curve->setSummaryCase( rftCase );
auto summaryCase = curveDefToAdd.address().summaryCase();
curve->setSummaryCase( summaryCase );
curve->setEnsemble( curveDefToAdd.address().ensemble() );
curve->setObservedFmuRftData( findObservedFmuData( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() ) );
RifEclipseRftAddress address = RifEclipseRftAddress::createAddress( m_wellPathNameOrSimWellName,
@ -545,7 +550,13 @@ void RimWellRftPlot::updateCurvesInPlot( const std::set<RiaRftPltCurveDefinition
// A summary case address can optionally contain an Eclipse case used to compute the TVD/MD for a well path
// https://github.com/OPM/ResInsight/issues/10501
curve->setEclipseResultCase( dynamic_cast<RimEclipseResultCase*>( curveDefToAdd.address().eclCase() ) );
auto eclipeCase = curveDefToAdd.address().eclCase();
if ( curveDefToAdd.address().ensemble() )
{
auto curveSet = findEnsembleCurveSet( curveDefToAdd.address().ensemble() );
if ( curveSet ) eclipeCase = curveSet->eclipseCase();
}
curve->setEclipseCase( eclipeCase );
double zValue = 1.0;
if ( !curveDefToAdd.address().ensemble() )
@ -565,9 +576,11 @@ void RimWellRftPlot::updateCurvesInPlot( const std::set<RiaRftPltCurveDefinition
}
else if ( m_showStatisticsCurves && curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::SourceType::ENSEMBLE_RFT )
{
RimSummaryCaseCollection* ensemble = curveDefToAdd.address().ensemble();
RimSummaryCaseCollection* ensemble = curveDefToAdd.address().ensemble();
auto curveSet = findEnsembleCurveSet( ensemble );
std::set<RifEclipseRftAddress> rftAddresses =
ensemble->rftStatisticsReader()->eclipseRftAddresses( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() );
curveSet->statisticsEclipseRftReader()->eclipseRftAddresses( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() );
for ( const auto& rftAddress : rftAddresses )
{
if ( rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50 )
@ -584,6 +597,7 @@ void RimWellRftPlot::updateCurvesInPlot( const std::set<RiaRftPltCurveDefinition
auto curve = new RimWellLogRftCurve();
plotTrack->addCurve( curve );
curve->setEnsemble( ensemble );
curve->setEclipseCase( curveSet->eclipseCase() );
curve->setRftAddress( rftAddress );
curve->setObservedFmuRftData( findObservedFmuData( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() ) );
curve->setZOrder( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_ENSEMBLE_STAT_CURVE ) );
@ -795,6 +809,13 @@ QList<caf::PdmOptionItemInfo> RimWellRftPlot::calculateValueOptions( const caf::
options = RiaSimWellBranchTools::valueOptionsForBranchIndexField( simulationWellBranches );
}
else if ( fieldNeedingOptions == &m_ensembleCurveSetEclipseCase )
{
RimTools::caseOptionItems( &options );
options.push_front( caf::PdmOptionItemInfo( "None", nullptr ) );
}
return options;
}
@ -968,6 +989,17 @@ void RimWellRftPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
updateFormationsOnPlot();
syncCurvesFromUiSelection();
}
else if ( changedField == &m_ensembleCurveSetEclipseCase )
{
for ( RimWellRftEnsembleCurveSet* curveSet : m_ensembleCurveSets() )
{
curveSet->setEclipseCase( m_ensembleCurveSetEclipseCase );
}
createEnsembleCurveSets();
updateFormationsOnPlot();
syncCurvesFromUiSelection();
}
}
//--------------------------------------------------------------------------------------------------
@ -1016,6 +1048,11 @@ void RimWellRftPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering&
caf::PdmUiGroup* sourcesGroup = uiOrdering.addNewGroupWithKeyword( "Sources", "Sources" );
sourcesGroup->add( &m_selectedSources );
if ( !m_ensembleCurveSets.empty() )
{
uiOrdering.add( &m_ensembleCurveSetEclipseCase );
}
caf::PdmUiGroup* timeStepsGroup = uiOrdering.addNewGroupWithKeyword( "Time Steps", "TimeSteps" );
timeStepsGroup->add( &m_selectedTimeSteps );

View File

@ -92,6 +92,8 @@ public:
bool showErrorBarsForObservedData() const;
void onLegendDefinitionChanged();
RimWellRftEnsembleCurveSet* findEnsembleCurveSet( RimSummaryCaseCollection* ensemble ) const;
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) override;
@ -138,7 +140,6 @@ private:
std::vector<RimSummaryCaseCollection*> selectedEnsembles() const;
void createEnsembleCurveSets();
RimWellRftEnsembleCurveSet* findEnsembleCurveSet( RimSummaryCaseCollection* ensemble ) const;
private:
friend class RimWellRftEnsembleCurveSet;
@ -153,7 +154,9 @@ private:
caf::PdmField<std::vector<RifDataSourceForRftPlt>> m_selectedSources;
caf::PdmField<std::vector<QDateTime>> m_selectedTimeSteps;
caf::PdmChildArrayField<RimWellRftEnsembleCurveSet*> m_ensembleCurveSets;
caf::PdmChildArrayField<RimWellRftEnsembleCurveSet*> m_ensembleCurveSets;
caf::PdmPtrField<RimEclipseCase*> m_ensembleCurveSetEclipseCase;
std::map<RimWellRftEnsembleCurveSet*, QPointer<RiuDraggableOverlayFrame>> m_ensembleLegendFrames;
std::map<RifDataSourceForRftPlt, cvf::Color3f> m_dataSourceColors;

View File

@ -28,6 +28,9 @@
#include "RicfCommandObject.h"
#include "RifReaderRftInterface.h"
#include "RifSummaryReaderInterface.h"
#include "RimAnalysisPlotDataEntry.h"
#include "RimDerivedEnsembleCaseCollection.h"
#include "RimEnsembleCurveSet.h"
@ -36,10 +39,6 @@
#include "RimSummaryCalculationCollection.h"
#include "RimSummaryCase.h"
#include "RifReaderEclipseRft.h"
#include "RifReaderEnsembleStatisticsRft.h"
#include "RifSummaryReaderInterface.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmUiTreeOrdering.h"
@ -135,8 +134,6 @@ RimSummaryCaseCollection::RimSummaryCaseCollection()
m_dataVectorFolders->uiCapability()->setUiTreeHidden( true );
m_dataVectorFolders.xmlCapability()->disableIO();
m_statisticsEclipseRftReader = new RifReaderEnsembleStatisticsRft( this );
m_commonAddressCount = 0;
}
@ -406,14 +403,6 @@ std::set<QDateTime> RimSummaryCaseCollection::rftTimeStepsForWell( const QString
return allTimeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RimSummaryCaseCollection::rftStatisticsReader()
{
return m_statisticsEclipseRftReader.p();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -39,8 +39,6 @@
#include <utility>
#include <vector>
class RifReaderRftInterface;
class RifReaderEnsembleStatisticsRft;
class RimSummaryCase;
class RimSummaryAddressCollection;
class RiaSummaryAddressAnalyzer;
@ -74,12 +72,11 @@ public:
virtual std::set<RifEclipseSummaryAddress> ensembleSummaryAddresses() const;
virtual std::set<time_t> ensembleTimeSteps() const;
std::set<QString> wellsWithRftData() const;
std::set<QDateTime> rftTimeStepsForWell( const QString& wellName ) const;
RifReaderRftInterface* rftStatisticsReader();
void setEnsembleId( int ensembleId );
int ensembleId() const;
bool hasEnsembleParameters() const;
std::set<QString> wellsWithRftData() const;
std::set<QDateTime> rftTimeStepsForWell( const QString& wellName ) const;
void setEnsembleId( int ensembleId );
int ensembleId() const;
bool hasEnsembleParameters() const;
std::vector<RigEnsembleParameter> variationSortedEnsembleParameters( bool excludeNoVariation = false ) const;
std::vector<std::pair<RigEnsembleParameter, double>> correlationSortedEnsembleParameters( const RifEclipseSummaryAddress& address ) const;
@ -147,8 +144,7 @@ private:
caf::PdmField<bool> m_isEnsemble;
caf::PdmChildField<RimSummaryAddressCollection*> m_dataVectorFolders;
cvf::ref<RifReaderEnsembleStatisticsRft> m_statisticsEclipseRftReader;
caf::PdmField<int> m_ensembleId;
caf::PdmField<int> m_ensembleId;
size_t m_commonAddressCount; // if different address count among cases, set to 0

View File

@ -382,7 +382,7 @@ void RimWellLogCurveCommonDataSource::analyseCurvesAndTracks( const std::vector<
else if ( rftCurve )
{
if ( rftCurve->summaryCase() ) m_uniqueSummaryCases.insert( rftCurve->summaryCase() );
if ( rftCurve->eclipseResultCase() ) m_uniqueCases.insert( rftCurve->eclipseResultCase() );
if ( rftCurve->eclipseCase() ) m_uniqueCases.insert( rftCurve->eclipseCase() );
m_uniqueWellNames.insert( rftCurve->wellName() );
auto adr = rftCurve->rftAddress();

View File

@ -22,6 +22,7 @@
#include "RiaColorTools.h"
#include "RiaDefines.h"
#include "RiaEclipseUnitTools.h"
#include "RiaExtractionTools.h"
#include "RiaQDateTimeTools.h"
#include "RiaResultNames.h"
#include "RiaRftDefines.h"
@ -44,7 +45,6 @@
#include "RimDepthTrackPlot.h"
#include "RimEclipseResultCase.h"
#include "RimFileSummaryCase.h"
#include "RimMainPlotCollection.h"
#include "RimObservedFmuRftData.h"
#include "RimPressureDepthData.h"
#include "RimProject.h"
@ -53,7 +53,6 @@
#include "RimSummaryCaseCollection.h"
#include "RimTools.h"
#include "RimWellLogPlot.h"
#include "RimWellLogPlotCollection.h"
#include "RimWellLogTrack.h"
#include "RimWellPath.h"
#include "RimWellPlotTools.h"
@ -152,8 +151,8 @@ RimWellLogRftCurve::RimWellLogRftCurve()
{
CAF_PDM_InitObject( "Well Log RFT Curve", RimWellLogCurve::wellLogCurveIconName() );
CAF_PDM_InitFieldNoDefault( &m_eclipseResultCase, "CurveEclipseResultCase", "Eclipse Result Case" );
m_eclipseResultCase.uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitFieldNoDefault( &m_eclipseCase, "CurveEclipseResultCase", "Eclipse Result Case" );
m_eclipseCase.uiCapability()->setUiTreeChildrenHidden( true );
CAF_PDM_InitFieldNoDefault( &m_summaryCase, "CurveSummaryCase", "Summary Case" );
m_summaryCase.uiCapability()->setUiTreeChildrenHidden( true );
@ -265,17 +264,17 @@ void RimWellLogRftCurve::setSegmentBranchType( RiaDefines::RftBranchType branchT
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellLogRftCurve::setEclipseResultCase( RimEclipseResultCase* eclipseResultCase )
void RimWellLogRftCurve::setEclipseCase( RimEclipseCase* eclipseCase )
{
m_eclipseResultCase = eclipseResultCase;
m_eclipseCase = eclipseCase;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimEclipseResultCase* RimWellLogRftCurve::eclipseResultCase() const
RimEclipseCase* RimWellLogRftCurve::eclipseCase() const
{
return m_eclipseResultCase;
return m_eclipseCase;
}
//--------------------------------------------------------------------------------------------------
@ -527,9 +526,9 @@ std::map<QString, QString> RimWellLogRftCurve::createCurveNameKeyValueMap() cons
variableValueMap[RiaDefines::namingVariableResultType()] = "RFT";
QString caseText;
if ( m_eclipseResultCase )
if ( m_eclipseCase )
{
caseText = m_eclipseResultCase->caseUserDescription();
caseText = m_eclipseCase->caseUserDescription();
}
else if ( m_summaryCase && m_ensemble ) // Summary RFT curves have both ensemble and summary set
{
@ -649,7 +648,7 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot )
RimPlotCurve::updateCurvePresentation( updateParentPlot );
DerivedMDSource derivedMDSource = DerivedMDSource::NO_SOURCE;
QString axisPrefixText;
if ( m_autoCheckStateBasedOnCurveData() || isChecked() )
{
@ -659,7 +658,7 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot )
bool showErrorBarsInObservedData = rftPlot ? rftPlot->showErrorBarsForObservedData() : false;
m_showErrorBars = showErrorBarsInObservedData;
std::vector<double> measuredDepthVector = measuredDepthValues();
std::vector<double> measuredDepthVector = measuredDepthValues( axisPrefixText );
std::vector<double> tvDepthVector = tvDepthValues();
std::vector<double> values = xValues();
std::vector<double> errors = errorValues();
@ -682,13 +681,13 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot )
}
RiaDefines::EclipseUnitSystem unitSystem = RiaDefines::EclipseUnitSystem::UNITS_METRIC;
if ( m_eclipseResultCase )
if ( m_eclipseCase )
{
// TODO: If no grid data, but only RFT data is loaded, we do not have any way to
// detect unit
if ( m_eclipseResultCase->eclipseCaseData() )
if ( m_eclipseCase->eclipseCaseData() )
{
unitSystem = m_eclipseResultCase->eclipseCaseData()->unitsType();
unitSystem = m_eclipseCase->eclipseCaseData()->unitsType();
}
}
else if ( m_summaryCase )
@ -718,19 +717,14 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot )
if ( tvDepthVector.size() != measuredDepthVector.size() )
{
if ( deriveMeasuredDepthValuesFromWellPath( tvDepthVector, measuredDepthVector ) )
if ( deriveMeasuredDepthFromObservedData( tvDepthVector, measuredDepthVector ) )
{
derivedMDSource = DerivedMDSource::WELL_PATH;
}
else if ( deriveMeasuredDepthFromObservedData( tvDepthVector, measuredDepthVector ) )
{
derivedMDSource = DerivedMDSource::OBSERVED_DATA;
axisPrefixText = "OBS/";
}
}
if ( tvDepthVector.size() != measuredDepthVector.size() )
{
derivedMDSource = DerivedMDSource::NO_SOURCE;
measuredDepthVector = tvDepthVector;
}
@ -783,23 +777,7 @@ void RimWellLogRftCurve::onLoadDataAndUpdate( bool updateParentPlot )
RiuQwtPlotWidget* viewer = wellLogTrack->viewer();
if ( viewer )
{
QString text;
if ( derivedMDSource != DerivedMDSource::NO_SOURCE )
{
if ( derivedMDSource == DerivedMDSource::WELL_PATH )
{
text = "WELL/" + wellLogPlot->depthAxisTitle();
}
else
{
text = "OBS/" + wellLogPlot->depthAxisTitle();
}
}
else // Standard depth title set from plot
{
text = wellLogPlot->depthAxisTitle();
}
QString text = axisPrefixText + wellLogPlot->depthAxisTitle();
viewer->setAxisTitleText( wellLogPlot->depthAxis(), text );
}
@ -852,7 +830,7 @@ void RimWellLogRftCurve::defineUiOrdering( QString uiConfigName, caf::PdmUiOrder
RimPlotCurve::updateFieldUiState();
caf::PdmUiGroup* curveDataGroup = uiOrdering.addNewGroup( "Curve Data" );
curveDataGroup->add( &m_eclipseResultCase );
curveDataGroup->add( &m_eclipseCase );
curveDataGroup->add( &m_summaryCase );
curveDataGroup->add( &m_wellName );
curveDataGroup->add( &m_timeStep );
@ -894,7 +872,7 @@ QList<caf::PdmOptionItemInfo> RimWellLogRftCurve::calculateValueOptions( const c
if ( !options.empty() ) return options;
RifReaderRftInterface* reader = rftReader();
if ( fieldNeedingOptions == &m_eclipseResultCase )
if ( fieldNeedingOptions == &m_eclipseCase )
{
RimTools::caseOptionItems( &options );
@ -954,12 +932,10 @@ QList<caf::PdmOptionItemInfo> RimWellLogRftCurve::calculateValueOptions( const c
//--------------------------------------------------------------------------------------------------
void RimWellLogRftCurve::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
m_idxInWellPathToIdxInRftFile.clear();
bool loadData = false;
RimWellLogCurve::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_eclipseResultCase )
if ( changedField == &m_eclipseCase )
{
m_timeStep = QDateTime();
m_wellName = "";
@ -1027,11 +1003,6 @@ std::vector<QString> RimWellLogRftCurve::perPointLabels() const
//--------------------------------------------------------------------------------------------------
RifReaderRftInterface* RimWellLogRftCurve::rftReader() const
{
if ( m_eclipseResultCase() )
{
return m_eclipseResultCase()->rftReader();
}
if ( m_summaryCase() ) // Summary RFT curves have both summary and ensemble set. Prioritize summary for reader.
{
return m_summaryCase()->rftReader();
@ -1039,7 +1010,14 @@ RifReaderRftInterface* RimWellLogRftCurve::rftReader() const
if ( m_ensemble() )
{
return m_ensemble()->rftStatisticsReader();
auto wellLogPlot = firstAncestorOrThisOfType<RimWellRftPlot>();
auto curveSet = wellLogPlot->findEnsembleCurveSet( m_ensemble );
if ( curveSet )
{
return curveSet->statisticsEclipseRftReader();
}
return nullptr;
}
if ( m_observedFmuRftData() )
@ -1052,6 +1030,11 @@ RifReaderRftInterface* RimWellLogRftCurve::rftReader() const
return m_pressureDepthData()->rftReader();
}
if ( auto resultCase = dynamic_cast<RimEclipseResultCase*>( m_eclipseCase() ) )
{
return resultCase->rftReader();
}
return nullptr;
}
@ -1060,121 +1043,18 @@ RifReaderRftInterface* RimWellLogRftCurve::rftReader() const
//--------------------------------------------------------------------------------------------------
RigEclipseWellLogExtractor* RimWellLogRftCurve::extractor()
{
RifReaderRftInterface* reader = rftReader();
if ( !reader ) return nullptr;
auto mainPlotCollection = firstAncestorOrThisOfTypeAsserted<RimMainPlotCollection>();
RimWellLogPlotCollection* wellLogCollection = mainPlotCollection->wellLogPlotCollection();
if ( !wellLogCollection ) return nullptr;
RigEclipseWellLogExtractor* eclExtractor = nullptr;
RimProject* proj = RimProject::current();
RimWellPath* wellPath = proj->wellPathFromSimWellName( m_wellName() );
eclExtractor = wellLogCollection->findOrCreateExtractor( wellPath, m_eclipseResultCase );
if ( !eclExtractor && m_eclipseResultCase )
// The well path extractor has the best geometrical representation, so use this if found
if ( auto wellPathExtractor = RiaExtractionTools::findOrCreateWellLogExtractor( wellPath, m_eclipseCase ) )
{
QString simWellName = RimWellPlotTools::simWellName( m_wellName );
std::vector<const RigWellPath*> wellPaths = RiaSimWellBranchTools::simulationWellBranches( simWellName, m_branchDetection );
if ( wellPaths.empty() ) return nullptr;
m_branchIndex = RiaSimWellBranchTools::clampBranchIndex( simWellName, m_branchIndex, m_branchDetection );
auto wellPathBranch = wellPaths[m_branchIndex];
eclExtractor = wellLogCollection->findOrCreateSimWellExtractor( simWellName,
QString( "Find or create sim well extractor" ),
wellPathBranch,
m_eclipseResultCase->eclipseCaseData() );
return wellPathExtractor;
}
return eclExtractor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellLogRftCurve::createWellPathIdxToRftFileIdxMapping()
{
if ( !m_idxInWellPathToIdxInRftFile.empty() )
{
return true;
}
RigEclipseWellLogExtractor* eclExtractor = extractor();
if ( !eclExtractor ) return false;
std::vector<WellPathCellIntersectionInfo> intersections = eclExtractor->cellIntersectionInfosAlongWellPath();
if ( intersections.empty() ) return false;
std::map<size_t, size_t> globCellIndicesToIndexInWell;
for ( size_t idx = 0; idx < intersections.size(); idx++ )
{
globCellIndicesToIndexInWell[intersections[idx].globCellIndex] = idx;
}
RifEclipseRftAddress depthAddress =
RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::TVD );
std::vector<caf::VecIjk> rftIndices;
if ( !rftReader() ) return false;
rftReader()->cellIndices( depthAddress, &rftIndices );
const RigMainGrid* mainGrid = eclExtractor->caseData()->mainGrid();
for ( size_t idx = 0; idx < rftIndices.size(); idx++ )
{
caf::VecIjk ijkIndex = rftIndices[idx];
size_t globalCellIndex = mainGrid->cellIndexFromIJK( ijkIndex.i(), ijkIndex.j(), ijkIndex.k() );
if ( globCellIndicesToIndexInWell.find( globalCellIndex ) != globCellIndicesToIndexInWell.end() )
{
m_idxInWellPathToIdxInRftFile[globCellIndicesToIndexInWell[globalCellIndex]] = idx;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimWellLogRftCurve::rftFileIndex( size_t wellPathIndex )
{
if ( m_idxInWellPathToIdxInRftFile.empty() )
{
createWellPathIdxToRftFileIdxMapping();
}
if ( m_idxInWellPathToIdxInRftFile.find( wellPathIndex ) == m_idxInWellPathToIdxInRftFile.end() )
{
return cvf::UNDEFINED_SIZE_T;
}
return m_idxInWellPathToIdxInRftFile[wellPathIndex];
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RimWellLogRftCurve::sortedIndicesInRftFile()
{
if ( m_idxInWellPathToIdxInRftFile.empty() )
{
createWellPathIdxToRftFileIdxMapping();
}
std::vector<size_t> indices;
for ( auto& it : m_idxInWellPathToIdxInRftFile )
{
indices.push_back( it.second );
}
return indices;
// Use sim well extractor as fallback
QString simWellName = RimWellPlotTools::simWellName( m_wellName );
return RiaExtractionTools::findOrCreateSimWellExtractor( m_eclipseCase(), simWellName, m_branchDetection(), m_branchIndex() );
}
//--------------------------------------------------------------------------------------------------
@ -1202,23 +1082,6 @@ std::vector<double> RimWellLogRftCurve::xValues()
auto address = RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, m_wellLogChannelName() );
reader->values( address, &values );
bool wellPathExists = createWellPathIdxToRftFileIdxMapping();
if ( wellPathExists )
{
std::vector<double> valuesSorted;
for ( size_t idx : sortedIndicesInRftFile() )
{
if ( idx < values.size() )
{
valuesSorted.push_back( ( values.at( idx ) ) );
}
}
std::swap( valuesSorted, values );
}
}
if ( m_scaleFactor() != 1.0 )
@ -1260,51 +1123,35 @@ std::vector<double> RimWellLogRftCurve::tvDepthValues()
if ( !reader ) return values;
RifEclipseRftAddress depthAddress =
RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::TVD );
if ( m_rftDataType() == RftDataType::RFT_SEGMENT_DATA )
{
auto depthAddress = RifEclipseRftAddress::createBranchSegmentAddress( m_wellName(),
m_timeStep,
RiaDefines::segmentTvdDepthResultName(),
segmentBranchIndex(),
m_segmentBranchType() );
reader->values( depthAddress, &values );
return values;
depthAddress = RifEclipseRftAddress::createBranchSegmentAddress( m_wellName(),
m_timeStep,
RiaDefines::segmentTvdDepthResultName(),
segmentBranchIndex(),
m_segmentBranchType() );
}
auto depthAddress = RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::TVD );
reader->values( depthAddress, &values );
bool wellPathExists = createWellPathIdxToRftFileIdxMapping();
if ( wellPathExists )
{
std::vector<double> valuesSorted;
for ( size_t idx : sortedIndicesInRftFile() )
{
if ( idx < values.size() )
{
valuesSorted.push_back( ( values.at( idx ) ) );
}
}
return valuesSorted;
}
return values;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimWellLogRftCurve::measuredDepthValues()
std::vector<double> RimWellLogRftCurve::measuredDepthValues( QString& prefixText )
{
if ( m_rftDataType() == RftDataType::RFT_SEGMENT_DATA )
{
RifReaderRftInterface* reader = rftReader();
if ( reader )
{
prefixText = "SEGMENT/";
return RimRftTools::seglenstValues( reader, m_wellName(), m_timeStep, segmentBranchIndex(), m_segmentBranchType() );
}
return {};
@ -1320,6 +1167,8 @@ std::vector<double> RimWellLogRftCurve::measuredDepthValues()
RifEclipseRftAddress depthAddress =
RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::MD );
reader->values( depthAddress, &values );
prefixText = "OBS/";
return values;
}
@ -1329,59 +1178,24 @@ std::vector<double> RimWellLogRftCurve::measuredDepthValues()
return {};
}
std::vector<double> measuredDepthForCells;
RigEclipseWellLogExtractor* eclExtractor = extractor();
if ( !eclExtractor ) return {};
if ( !eclExtractor ) return measuredDepthForCells;
std::vector<double> measuredDepthForIntersections = eclExtractor->cellIntersectionMDs();
if ( measuredDepthForIntersections.empty() )
if ( auto reader = rftReader() )
{
return measuredDepthForCells;
}
prefixText = "WELL/";
std::vector<size_t> globCellIndices = eclExtractor->intersectedCellsGlobIdx();
RifEclipseRftAddress depthAddress =
RifEclipseRftAddress::createAddress( m_wellName(), m_timeStep, RifEclipseRftAddress::RftWellLogChannelType::MD );
for ( size_t i = 0; i < globCellIndices.size() - 1; i = i + 2 )
{
double sum = measuredDepthForIntersections[i] + measuredDepthForIntersections[i + 1];
std::vector<double> values;
reader->values( depthAddress, &values );
if ( !values.empty() ) return values;
measuredDepthForCells.push_back( sum / 2.0 );
}
return rftReader()->computeMeasuredDepth( m_wellName(), m_timeStep(), eclExtractor );
};
std::vector<double> measuredDepthForCellsWhichHasRftData;
for ( size_t i = 0; i < measuredDepthForCells.size(); i++ )
{
if ( rftFileIndex( i ) != cvf::UNDEFINED_SIZE_T )
{
measuredDepthForCellsWhichHasRftData.push_back( measuredDepthForCells[i] );
}
}
return measuredDepthForCellsWhichHasRftData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellLogRftCurve::deriveMeasuredDepthValuesFromWellPath( const std::vector<double>& tvDepthValues, std::vector<double>& derivedMDValues )
{
RimProject* proj = RimProject::current();
RimWellPath* wellPath = proj->wellPathByName( m_wellName );
if ( wellPath && wellPath->wellPathGeometry() )
{
const std::vector<double>& mdValuesOfWellPath = wellPath->wellPathGeometry()->measuredDepths();
const std::vector<double>& tvdValuesOfWellPath = wellPath->wellPathGeometry()->trueVerticalDepths();
derivedMDValues = RigWellPathGeometryTools::interpolateMdFromTvd( mdValuesOfWellPath, tvdValuesOfWellPath, tvDepthValues );
CVF_ASSERT( derivedMDValues.size() == tvDepthValues.size() );
return true;
}
return false;
return {};
}
//--------------------------------------------------------------------------------------------------

View File

@ -33,7 +33,7 @@
class RifReaderRftInterface;
class RigEclipseWellLogExtractor;
class RimEclipseResultCase;
class RimEclipseCase;
class RimObservedFmuRftData;
class RimSummaryCase;
class RimSummaryCaseCollection;
@ -55,15 +55,6 @@ public:
RFT_SEGMENT_DATA
};
private:
enum class DerivedMDSource
{
NO_SOURCE,
WELL_PATH,
SEGMENT,
OBSERVED_DATA
};
public:
RimWellLogRftCurve();
~RimWellLogRftCurve() override;
@ -80,8 +71,8 @@ public:
void setSegmentBranchIndex( int branchIndex );
void setSegmentBranchType( RiaDefines::RftBranchType branchType );
void setEclipseResultCase( RimEclipseResultCase* eclipseResultCase );
RimEclipseResultCase* eclipseResultCase() const;
void setEclipseCase( RimEclipseCase* eclipseCase );
RimEclipseCase* eclipseCase() const;
void setSummaryCase( RimSummaryCase* summaryCase );
RimSummaryCase* summaryCase() const;
@ -127,19 +118,15 @@ private:
RigEclipseWellLogExtractor* extractor();
bool createWellPathIdxToRftFileIdxMapping();
size_t rftFileIndex( size_t wellPathIndex );
std::vector<size_t> sortedIndicesInRftFile();
void updateWellChannelNameAndTimeStep();
void updateWellChannelNameAndTimeStep();
std::map<QString, QString> createCurveNameKeyValueMap() const;
std::vector<double> xValues();
std::vector<double> errorValues();
std::vector<double> tvDepthValues();
std::vector<double> measuredDepthValues();
std::vector<double> measuredDepthValues( QString& prefixText );
bool deriveMeasuredDepthValuesFromWellPath( const std::vector<double>& tvDepthValues, std::vector<double>& derivedMDValues );
bool deriveMeasuredDepthFromObservedData( const std::vector<double>& tvDepthValues, std::vector<double>& derivedMDValues );
int segmentBranchIndex() const;
@ -147,7 +134,7 @@ private:
static bool isSegmentResult( const QString& resultName );
private:
caf::PdmPtrField<RimEclipseResultCase*> m_eclipseResultCase;
caf::PdmPtrField<RimEclipseCase*> m_eclipseCase;
caf::PdmPtrField<RimSummaryCase*> m_summaryCase;
caf::PdmPtrField<RimSummaryCaseCollection*> m_ensemble;
caf::PdmPtrField<RimObservedFmuRftData*> m_observedFmuRftData;
@ -166,6 +153,5 @@ private:
caf::PdmField<int> m_segmentBranchIndex;
caf::PdmField<caf::AppEnum<RiaDefines::RftBranchType>> m_segmentBranchType;
std::map<size_t, size_t> m_idxInWellPathToIdxInRftFile;
caf::PdmField<caf::AppEnum<RifEclipseRftAddress::RftWellLogChannelType>> m_wellLogChannelName;
};

View File

@ -155,6 +155,29 @@ void RigWellLogExtractor::resampleIntersections( double maxDistanceBetweenInters
m_intersectedCellFaces = resampledIntersectedCellFaces;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<double> RigWellLogExtractor::averageMdForCell( size_t cellIndex ) const
{
std::vector<size_t> indicesForCell;
for ( size_t i = 0; i < m_intersectedCellsGlobIdx.size(); i++ )
{
if ( m_intersectedCellsGlobIdx[i] == cellIndex ) indicesForCell.emplace_back( i );
}
if ( indicesForCell.empty() ) return std::nullopt;
double sum = 0.0;
for ( const auto& i : indicesForCell )
{
sum += m_intersectionMeasuredDepths[i];
}
return sum / static_cast<double>( indicesForCell.size() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -73,6 +73,8 @@ public:
void resampleIntersections( double maxDistanceBetweenIntersections );
std::optional<double> averageMdForCell( size_t cellIndex ) const;
protected:
static void insertIntersectionsInMap( const std::vector<HexIntersectionInfo>& intersections,
cvf::Vec3d p1,