///////////////////////////////////////////////////////////////////////////////// // // 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 "RimWellRftPlot.h" #include "RiaColorTables.h" #include "RiaColorTools.h" #include "RiaDateStringParser.h" #include "RiaPlotDefines.h" #include "RiaSimWellBranchTools.h" #include "RifReaderEclipseRft.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" #include "RigSimWellData.h" #include "RigWellPath.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseResultCase.h" #include "RimEclipseResultDefinition.h" #include "RimEnsembleCurveSetColorManager.h" #include "RimObservedFmuRftData.h" #include "RimOilField.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" #include "RimSummaryCaseCollection.h" #include "RimTools.h" #include "RimWellLogExtractionCurve.h" #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" #include "RimWellLogFileCurve.h" #include "RimWellLogPlot.h" #include "RimWellLogPlotNameConfig.h" #include "RimWellLogRftCurve.h" #include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" #include "RimWellPlotTools.h" #include "RimWellPltPlot.h" #include "RiuAbstractLegendFrame.h" #include "RiuAbstractOverlayContentFrame.h" #include "RiuDraggableOverlayFrame.h" #include "RiuQwtPlotCurveDefines.h" #include "RiuQwtPlotWidget.h" #include "cafPdmUiListEditor.h" #include "cafPdmUiTreeOrdering.h" #include "cafPdmUiTreeSelectionEditor.h" #include #include #include CAF_PDM_SOURCE_INIT( RimWellRftPlot, "WellRftPlot" ); using ColorMode = RimEnsembleCurveSetColorManager::ColorMode; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const char RimWellRftPlot::PLOT_NAME_QFORMAT_STRING[] = "RFT: %1"; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellRftPlot::RimWellRftPlot() : RimWellLogPlot() { CAF_PDM_InitObject( "RFT Plot", ":/RFTPlot16x16.png" ); CAF_PDM_InitField( &m_showStatisticsCurves, "ShowStatisticsCurves", true, "Show Statistics Curves" ); CAF_PDM_InitField( &m_showEnsembleCurves, "ShowEnsembleCurves", true, "Show Ensemble Curves" ); CAF_PDM_InitField( &m_showErrorInObservedData, "ShowErrorObserved", true, "Show Observed Data Error" ); CAF_PDM_InitFieldNoDefault( &m_wellLogPlot_OBSOLETE, "WellLog", "Well Log" ); m_wellLogPlot_OBSOLETE.uiCapability()->setUiTreeHidden( true ); m_wellLogPlot_OBSOLETE.xmlCapability()->setIOWritable( false ); m_depthType = RiaDefines::DepthTypeEnum::TRUE_VERTICAL_DEPTH; CAF_PDM_InitFieldNoDefault( &m_wellPathNameOrSimWellName, "WellName", "Well Name" ); CAF_PDM_InitField( &m_branchIndex, "BranchIndex", 0, "Branch Index" ); CAF_PDM_InitField( &m_branchDetection, "BranchDetection", true, "Branch Detection", "", "Compute branches based on how simulation well cells are organized", "" ); CAF_PDM_InitFieldNoDefault( &m_selectedSources, "Sources", "Sources" ); m_selectedSources.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); m_selectedSources.xmlCapability()->disableIO(); m_selectedSources.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_selectedSources.uiCapability()->setAutoAddingOptionFromValue( false ); CAF_PDM_InitFieldNoDefault( &m_selectedTimeSteps, "TimeSteps", "Time Steps" ); m_selectedTimeSteps.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() ); m_selectedTimeSteps.xmlCapability()->disableIO(); m_selectedTimeSteps.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); m_selectedTimeSteps.uiCapability()->setAutoAddingOptionFromValue( false ); CAF_PDM_InitFieldNoDefault( &m_wellPathCollection, "WellPathCollection", "Well Path Collection" ); m_wellPathCollection.uiCapability()->setUiHidden( true ); m_wellPathCollection.xmlCapability()->disableIO(); m_wellPathCollection = RimProject::current()->activeOilField()->wellPathCollection(); CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSets, "EnsembleCurveSets", "Ensemble Curve Sets" ); // 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. setAvailableDepthTypes( { RiaDefines::DepthTypeEnum::MEASURED_DEPTH, RiaDefines::DepthTypeEnum::TRUE_VERTICAL_DEPTH } ); m_nameConfig->setCustomName( "RFT Plot" ); setNamingMethod( RiaDefines::ObjectNamingMethod::CUSTOM ); m_plotLegendsHorizontal = false; setPlotTitleVisible( true ); this->setAsPlotMdiWindow(); m_isOnLoad = true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellRftPlot::~RimWellRftPlot() { removeMdiWindowFromMdiArea(); deleteViewWidget(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::applyCurveAppearance( RimWellLogCurve* curve ) { applyCurveColor( curve ); RiaRftPltCurveDefinition curveDef = RimWellPlotTools::curveDefFromCurve( curve ); RiuQwtPlotCurveDefines::LineStyleEnum lineStyle = RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID; RiuPlotCurveSymbol::PointSymbolEnum currentSymbol = RiuPlotCurveSymbol::SYMBOL_NONE; if ( curveDef.address().sourceType() != RifDataSourceForRftPlt::ENSEMBLE_RFT ) { currentSymbol = m_timeStepSymbols[curveDef.timeStep()]; } bool isObservedData = curveDef.address().sourceType() == RifDataSourceForRftPlt::OBSERVED || curveDef.address().sourceType() == RifDataSourceForRftPlt::OBSERVED_FMU_RFT; // Observed data lineStyle = isObservedData ? RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_NONE : RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID; curve->setSymbol( currentSymbol ); curve->setLineStyle( lineStyle ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::applyCurveColor( RimWellLogCurve* curve ) { cvf::Color3f color = findCurveColor( curve ); curve->setColor( color ); curve->setSymbolEdgeColor( color ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::updateFormationsOnPlot() const { if ( plotCount() > 0 ) { RimProject* proj = RimProject::current(); RimWellPath* wellPath = proj->wellPathByName( m_wellPathNameOrSimWellName ); RimCase* formationNamesCase = nullptr; RimWellLogTrack* track = dynamic_cast( plotByIndex( 0 ) ); if ( track ) { formationNamesCase = track->formationNamesCase(); if ( !formationNamesCase ) { /// Set default case. Todo : Use the first of the selected cases in the plot std::vector cases; proj->allCases( cases ); if ( !cases.empty() ) { formationNamesCase = cases[0]; } } if ( wellPath ) { track->setAndUpdateWellPathFormationNamesData( formationNamesCase, wellPath ); } else { track->setAndUpdateSimWellFormationNamesAndBranchData( formationNamesCase, associatedSimWellName(), m_branchIndex, m_branchDetection ); } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimWellRftPlot::associatedSimWellName() const { return RimWellPlotTools::simWellName( m_wellPathNameOrSimWellName ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::applyInitialSelections() { std::map wellSources = findWellSources(); if ( m_wellPathNameOrSimWellName == "None" && !wellSources.empty() ) { m_wellPathNameOrSimWellName = wellSources.begin()->first; } std::vector sourcesToSelect; const QString simWellName = associatedSimWellName(); for ( RimEclipseResultCase* const rftCase : RimWellPlotTools::rftCasesForWell( simWellName ) ) { sourcesToSelect.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::RFT, rftCase ) ); } for ( RimEclipseResultCase* const gridCase : RimWellPlotTools::gridCasesForWell( simWellName ) ) { sourcesToSelect.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::GRID, gridCase ) ); } for ( RimSummaryCaseCollection* const ensemble : RimWellPlotTools::rftEnsemblesForWell( simWellName ) ) { sourcesToSelect.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::ENSEMBLE_RFT, ensemble ) ); } std::vector wellLogFiles = RimWellPlotTools::wellLogFilesContainingPressure( m_wellPathNameOrSimWellName ); if ( !wellLogFiles.empty() ) { for ( RimWellLogFile* const wellLogFile : wellLogFiles ) { sourcesToSelect.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED, wellLogFile ) ); } } for ( RimObservedFmuRftData* const observedFmuRftData : RimWellPlotTools::observedFmuRftDataForWell( m_wellPathNameOrSimWellName ) ) { sourcesToSelect.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED_FMU_RFT, observedFmuRftData ) ); } m_selectedSources = sourcesToSelect; { std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); auto relevantTimeSteps = RimWellPlotTools::calculateRelevantTimeStepsFromCases( m_wellPathNameOrSimWellName, m_selectedSources, channelTypesToUse ); if ( !relevantTimeSteps.empty() ) { std::vector timeStepVector; // If we have RFT data from multiple sources, relevant time steps end up with a small number of time steps // If this is the case, pre-select all time steps const size_t maxCountToPreSelect = 3; if ( relevantTimeSteps.size() <= maxCountToPreSelect ) { for ( const auto& item : relevantTimeSteps ) timeStepVector.push_back( item.first ); } else { // If only one RFT source is available, we might get a large number of time steps causing performance // issues Only select the first available time step timeStepVector.push_back( relevantTimeSteps.begin()->first ); } m_selectedTimeSteps = timeStepVector; } } createEnsembleCurveSets(); syncCurvesFromUiSelection(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::updateEditorsFromPreviousSelection() { std::set previousSources( m_selectedSources().begin(), m_selectedSources().end() ); std::set previousTimeSteps( m_selectedTimeSteps().begin(), m_selectedTimeSteps().end() ); m_selectedSources.v().clear(); m_selectedTimeSteps.v().clear(); auto dataSourceOptions = calculateValueOptions( &m_selectedSources ); for ( const auto& dataSourceOption : dataSourceOptions ) { if ( dataSourceOption.level() == 1 ) { RifDataSourceForRftPlt dataSource = dataSourceOption.value().value(); if ( previousSources.count( dataSource ) ) { m_selectedSources.v().push_back( dataSource ); } } } // This has to happen after the m_selectedSources is filled // because the available time steps is dependent on the selected sources. auto timeStepOptions = calculateValueOptions( &m_selectedTimeSteps ); for ( const auto& timeStepOption : timeStepOptions ) { QDateTime timeStep = timeStepOption.value().toDateTime(); if ( previousTimeSteps.count( timeStep ) ) { m_selectedTimeSteps.v().push_back( timeStep ); } } if ( m_selectedTimeSteps.v().empty() && !timeStepOptions.empty() ) { QDateTime timeStep = timeStepOptions.first().value().toDateTime(); m_selectedTimeSteps.v().push_back( timeStep ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::updateEditorsFromCurves() { std::set selectedSources; std::set selectedTimeSteps; std::map> selectedTimeStepsMap; for ( const RiaRftPltCurveDefinition& curveDef : curveDefsFromCurves() ) { if ( curveDef.address().sourceType() == RifDataSourceForRftPlt::OBSERVED ) selectedSources.insert( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED ) ); else if ( curveDef.address().sourceType() == RifDataSourceForRftPlt::SUMMARY_RFT ) { selectedSources.insert( RifDataSourceForRftPlt( RifDataSourceForRftPlt::ENSEMBLE_RFT, curveDef.address().ensemble() ) ); } else selectedSources.insert( curveDef.address() ); auto newTimeStepMap = std::map>{ { curveDef.timeStep(), std::set{ curveDef.address() } } }; RimWellPlotTools::addTimeStepsToMap( selectedTimeStepsMap, newTimeStepMap ); selectedTimeSteps.insert( curveDef.timeStep() ); } m_selectedSources = std::vector( selectedSources.begin(), selectedSources.end() ); m_selectedTimeSteps = std::vector( selectedTimeSteps.begin(), selectedTimeSteps.end() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::syncCurvesFromUiSelection() { RimWellLogTrack* plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( !plotTrack ) return; std::set allCurveDefs = selectedCurveDefs(); std::set curveDefsInPlot = curveDefsFromCurves(); std::set curvesToDelete; std::set newCurveDefs; if ( allCurveDefs.size() < curveDefsInPlot.size() ) { // Determine which curves to delete from plot std::set deleteCurveDefs; std::set_difference( curveDefsInPlot.begin(), curveDefsInPlot.end(), allCurveDefs.begin(), allCurveDefs.end(), std::inserter( deleteCurveDefs, deleteCurveDefs.end() ) ); for ( RimWellLogCurve* const curve : plotTrack->curves() ) { RiaRftPltCurveDefinition curveDef = RimWellPlotTools::curveDefFromCurve( curve ); if ( deleteCurveDefs.count( curveDef ) > 0 ) { curvesToDelete.insert( curve ); } } } else { // Determine which curves are new since last time std::set_difference( allCurveDefs.begin(), allCurveDefs.end(), curveDefsInPlot.begin(), curveDefsInPlot.end(), std::inserter( newCurveDefs, newCurveDefs.end() ) ); } updateCurvesInPlot( allCurveDefs, newCurveDefs, curvesToDelete ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set RimWellRftPlot::selectedCurveDefs() const { std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); return RimWellPlotTools::curveDefsFromTimesteps( m_wellPathNameOrSimWellName, m_selectedTimeSteps.v(), true, selectedSourcesExpanded(), channelTypesToUse ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set RimWellRftPlot::curveDefsFromCurves() const { std::set curveDefs; RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( plotTrack ) { for ( RimWellLogCurve* const curve : plotTrack->curves() ) { curveDefs.insert( RimWellPlotTools::curveDefFromCurve( curve ) ); } } return curveDefs; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::updateCurvesInPlot( const std::set& allCurveDefs, const std::set& curveDefsToAdd, const std::set& curvesToDelete ) { const QString simWellName = associatedSimWellName(); RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( !plotTrack ) return; // Delete curves plotTrack->deleteAllCurves(); defineCurveColorsAndSymbols( allCurveDefs ); std::set ensemblesWithSummaryCurves; // Add new curves for ( const RiaRftPltCurveDefinition& curveDefToAdd : allCurveDefs ) { if ( curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::RFT ) { auto curve = new RimWellLogRftCurve(); plotTrack->addCurve( curve ); auto rftCase = curveDefToAdd.address().eclCase(); curve->setEclipseResultCase( dynamic_cast( rftCase ) ); RifEclipseRftAddress address = RifEclipseRftAddress::createAddress( simWellName, curveDefToAdd.timeStep(), RifEclipseRftAddress::RftWellLogChannelType::PRESSURE ); curve->setRftAddress( address ); curve->setZOrder( 1 ); curve->setSimWellBranchData( m_branchDetection, m_branchIndex ); applyCurveAppearance( curve ); } else if ( curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::OBSERVED_FMU_RFT ) { auto curve = new RimWellLogRftCurve(); curve->setErrorBarsVisible( m_showErrorInObservedData ); plotTrack->addCurve( curve ); auto observedFmuRftData = curveDefToAdd.address().observedFmuRftData(); curve->setObservedFmuRftData( observedFmuRftData ); RifEclipseRftAddress address = RifEclipseRftAddress::createAddress( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep(), RifEclipseRftAddress::RftWellLogChannelType::PRESSURE ); curve->setRftAddress( address ); curve->setZOrder( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_SINGLE_CURVE_OBSERVED ) ); applyCurveAppearance( curve ); } else if ( m_showEnsembleCurves && curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::SUMMARY_RFT ) { auto curve = new RimWellLogRftCurve(); plotTrack->addCurve( curve ); auto rftCase = curveDefToAdd.address().summaryCase(); curve->setSummaryCase( rftCase ); curve->setEnsemble( curveDefToAdd.address().ensemble() ); curve->setObservedFmuRftData( this->findObservedFmuData( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() ) ); RifEclipseRftAddress address = RifEclipseRftAddress::createAddress( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep(), RifEclipseRftAddress::RftWellLogChannelType::PRESSURE ); curve->setRftAddress( address ); curve->setZOrder( 1 ); applyCurveAppearance( curve ); bool isFirstSummaryCurveInEnsemble = ensemblesWithSummaryCurves.count( curveDefToAdd.address().ensemble() ) == 0u; curve->setShowInLegend( isFirstSummaryCurveInEnsemble ); ensemblesWithSummaryCurves.insert( curveDefToAdd.address().ensemble() ); } else if ( m_showStatisticsCurves && curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::ENSEMBLE_RFT ) { RimSummaryCaseCollection* ensemble = curveDefToAdd.address().ensemble(); std::set rftAddresses = ensemble->rftStatisticsReader()->eclipseRftAddresses( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() ); for ( const auto& rftAddress : rftAddresses ) { if ( rftAddress.wellLogChannel() == RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50 ) { // Default statistics curves are P10, P50, P90 and mean // It is not common to use P50 for ensemble RFT, so skip display of P50 to avoid confusion with mean // https://github.com/OPM/ResInsight/issues/5238 continue; } if ( rftAddress.wellLogChannel() != RifEclipseRftAddress::RftWellLogChannelType::TVD ) { auto curve = new RimWellLogRftCurve(); plotTrack->addCurve( curve ); curve->setEnsemble( ensemble ); curve->setRftAddress( rftAddress ); curve->setObservedFmuRftData( this->findObservedFmuData( m_wellPathNameOrSimWellName, curveDefToAdd.timeStep() ) ); curve->setZOrder( RiuQwtPlotCurveDefines::zDepthForIndex( RiuQwtPlotCurveDefines::ZIndex::Z_ENSEMBLE_STAT_CURVE ) ); applyCurveAppearance( curve ); auto symbol = statisticsCurveSymbolFromAddress( rftAddress ); RiuPlotCurveSymbol::LabelPosition labelPos = statisticsLabelPosFromAddress( rftAddress ); curve->setSymbol( symbol ); curve->setSymbolLabelPosition( labelPos ); curve->setSymbolSize( curve->symbolSize() + 3 ); curve->setSymbolSkipDistance( 150 ); curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID ); QString uiText = caf::AppEnum::uiText( rftAddress.wellLogChannel() ); QString label = uiText.replace( ": Pressure", "" ); curve->setSymbolLabel( label ); curve->setLineThickness( 3 ); } } } else if ( curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::GRID ) { auto curve = new RimWellLogExtractionCurve(); plotTrack->addCurve( curve ); cvf::Color3f curveColor = RiaColorTables::wellLogPlotPaletteColors().cycledColor3f( plotTrack->curveCount() ); curve->setColor( curveColor ); curve->setFromSimulationWellName( simWellName, m_branchIndex, m_branchDetection ); // Fetch cases and time steps auto gridCase = curveDefToAdd.address().eclCase(); if ( gridCase != nullptr ) { // Case curve->setCase( gridCase ); curve->setEclipseResultVariable( "PRESSURE" ); // Time step std::vector timeSteps = gridCase->eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->timeStepDates(); int currentTimeStepIndex = -1; for ( size_t tsIdx = 0; tsIdx < timeSteps.size(); ++tsIdx ) { if ( timeSteps[tsIdx] == curveDefToAdd.timeStep() ) { currentTimeStepIndex = static_cast( tsIdx ); break; } } curve->setCurrentTimeStep( currentTimeStepIndex ); curve->setZOrder( 0 ); applyCurveAppearance( curve ); } } else if ( curveDefToAdd.address().sourceType() == RifDataSourceForRftPlt::OBSERVED ) { RimWellLogFile* const wellLogFile = curveDefToAdd.address().wellLogFile(); RimWellPath* const wellPath = RimWellPlotTools::wellPathFromWellLogFile( wellLogFile ); if ( wellLogFile != nullptr ) { RimWellLogFileChannel* pressureChannel = RimWellPlotTools::getPressureChannelFromWellFile( wellLogFile ); auto curve = new RimWellLogFileCurve(); plotTrack->addCurve( curve ); curve->setWellPath( wellPath ); curve->setWellLogFile( wellLogFile ); curve->setWellLogChannelName( pressureChannel->name() ); curve->setZOrder( 2 ); applyCurveAppearance( curve ); } } } if ( depthType() == RiaDefines::DepthTypeEnum::MEASURED_DEPTH ) { assignWellPathToExtractionCurves(); } RimWellLogPlot::onLoadDataAndUpdate(); if ( plotTrack->curveCount() ) { zoomAll(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellRftPlot::selectedSourcesExpanded() const { std::vector sources; for ( const RifDataSourceForRftPlt& addr : m_selectedSources() ) { if ( addr.sourceType() == RifDataSourceForRftPlt::OBSERVED ) { for ( RimWellLogFile* const wellLogFile : RimWellPlotTools::wellLogFilesContainingPressure( m_wellPathNameOrSimWellName ) ) { sources.push_back( RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED, wellLogFile ) ); } } else sources.push_back( addr ); } return sources; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const QString& RimWellRftPlot::simWellOrWellPathName() const { return m_wellPathNameOrSimWellName.v(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::setSimWellOrWellPathName( const QString& currWellName ) { m_wellPathNameOrSimWellName = currWellName; if ( m_wellPathNameOrSimWellName().isEmpty() ) { m_wellPathNameOrSimWellName = "None"; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimWellRftPlot::branchIndex() const { return m_branchIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const char* RimWellRftPlot::plotNameFormatString() { return PLOT_NAME_QFORMAT_STRING; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::deleteCurvesAssosicatedWithObservedData( const RimObservedFmuRftData* observedFmuRftData ) { for ( auto plot : plots() ) { RimWellLogTrack* const track = dynamic_cast( plot ); if ( track ) { auto curves = track->curves(); for ( auto curve : curves ) { RimWellLogRftCurve* rftCurve = dynamic_cast( curve ); if ( rftCurve && rftCurve->observedFmuRftData() == observedFmuRftData ) { track->removeCurve( rftCurve ); delete rftCurve; } } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RimWellRftPlot::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) { QList options = RimWellLogPlot::calculateValueOptions( fieldNeedingOptions ); const QString simWellName = associatedSimWellName(); if ( fieldNeedingOptions == &m_wellPathNameOrSimWellName ) { options.push_back( caf::PdmOptionItemInfo( "None", "None" ) ); std::map wellSources = findWellSources(); for ( const auto& wellName : wellSources ) { const QStringList& tags = wellName.second; QString uiText = wellName.first; if ( !tags.empty() ) { uiText += QString( " (%1)" ).arg( wellName.second.join( ", " ) ); } options.push_back( caf::PdmOptionItemInfo( uiText, wellName.first ) ); } } else if ( fieldNeedingOptions == &m_selectedSources ) { const std::vector rftCases = RimWellPlotTools::rftCasesForWell( simWellName ); if ( !rftCases.empty() ) { options.push_back( caf::PdmOptionItemInfo::createHeader( RifDataSourceForRftPlt::sourceTypeUiText( RifDataSourceForRftPlt::RFT ), true ) ); for ( const auto& rftCase : rftCases ) { auto addr = RifDataSourceForRftPlt( RifDataSourceForRftPlt::RFT, rftCase ); auto item = caf::PdmOptionItemInfo( rftCase->caseUserDescription(), QVariant::fromValue( addr ) ); item.setLevel( 1 ); options.push_back( item ); } } const std::vector rftEnsembles = RimWellPlotTools::rftEnsemblesForWell( m_wellPathNameOrSimWellName ); if ( !rftEnsembles.empty() ) { options.push_back( caf::PdmOptionItemInfo::createHeader( RifDataSourceForRftPlt::sourceTypeUiText( RifDataSourceForRftPlt::ENSEMBLE_RFT ), true ) ); for ( RimSummaryCaseCollection* rftEnsemble : rftEnsembles ) { auto addr = RifDataSourceForRftPlt( RifDataSourceForRftPlt::ENSEMBLE_RFT, rftEnsemble ); auto item = caf::PdmOptionItemInfo( rftEnsemble->name(), QVariant::fromValue( addr ) ); item.setLevel( 1 ); options.push_back( item ); } } const std::vector gridCases = RimWellPlotTools::gridCasesForWell( simWellName ); if ( !gridCases.empty() ) { options.push_back( caf::PdmOptionItemInfo::createHeader( RifDataSourceForRftPlt::sourceTypeUiText( RifDataSourceForRftPlt::GRID ), true ) ); for ( const auto& gridCase : gridCases ) { auto addr = RifDataSourceForRftPlt( RifDataSourceForRftPlt::GRID, gridCase ); auto item = caf::PdmOptionItemInfo( gridCase->caseUserDescription(), QVariant::fromValue( addr ) ); item.setLevel( 1 ); options.push_back( item ); } } if ( !RimWellPlotTools::wellLogFilesContainingPressure( m_wellPathNameOrSimWellName ).empty() ) { options.push_back( caf::PdmOptionItemInfo::createHeader( RifDataSourceForRftPlt::sourceTypeUiText( RifDataSourceForRftPlt::OBSERVED ), true ) ); auto addr = RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED ); auto item = caf::PdmOptionItemInfo( "Observed Data", QVariant::fromValue( addr ) ); item.setLevel( 1 ); options.push_back( item ); } const std::vector observedFmuRftCases = RimWellPlotTools::observedFmuRftDataForWell( m_wellPathNameOrSimWellName ); if ( !observedFmuRftCases.empty() ) { options.push_back( caf::PdmOptionItemInfo::createHeader( RifDataSourceForRftPlt::sourceTypeUiText( RifDataSourceForRftPlt::OBSERVED_FMU_RFT ), true ) ); for ( const auto& observedFmuRftCase : observedFmuRftCases ) { auto addr = RifDataSourceForRftPlt( RifDataSourceForRftPlt::OBSERVED_FMU_RFT, observedFmuRftCase ); auto item = caf::PdmOptionItemInfo( observedFmuRftCase->name(), QVariant::fromValue( addr ) ); item.setLevel( 1 ); options.push_back( item ); } } } else if ( fieldNeedingOptions == &m_selectedTimeSteps ) { std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); RimWellPlotTools::calculateValueOptionsForTimeSteps( m_wellPathNameOrSimWellName, selectedSourcesExpanded(), channelTypesToUse, options ); } else if ( fieldNeedingOptions == &m_branchIndex ) { auto simulationWellBranches = RiaSimWellBranchTools::simulationWellBranches( simWellName, m_branchDetection ); options = RiaSimWellBranchTools::valueOptionsForBranchIndexField( simulationWellBranches ); } return options; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { RimWellLogPlot::fieldChangedByUi( changedField, oldValue, newValue ); if ( changedField == &m_wellPathNameOrSimWellName ) { m_nameConfig->setCustomName( QString( plotNameFormatString() ).arg( m_wellPathNameOrSimWellName ) ); m_branchIndex = 0; RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( plotTrack ) { plotTrack->deleteAllCurves(); } createEnsembleCurveSets(); updateEditorsFromPreviousSelection(); updateFormationsOnPlot(); syncCurvesFromUiSelection(); } else if ( changedField == &m_branchIndex || changedField == &m_branchDetection ) { const QString simWellName = associatedSimWellName(); m_branchIndex = RiaSimWellBranchTools::clampBranchIndex( simWellName, m_branchIndex, m_branchDetection ); createEnsembleCurveSets(); updateFormationsOnPlot(); syncCurvesFromUiSelection(); } else if ( changedField == &m_selectedSources || changedField == &m_selectedTimeSteps ) { updateFormationsOnPlot(); syncCurvesFromUiSelection(); this->updateConnectedEditors(); } else if ( changedField == &m_showStatisticsCurves || changedField == &m_showEnsembleCurves || changedField == &m_showErrorInObservedData ) { updateFormationsOnPlot(); syncCurvesFromUiSelection(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName ) { for ( RimWellRftEnsembleCurveSet* curveSet : m_ensembleCurveSets() ) { bool isSelected = false; for ( RimSummaryCaseCollection* selectedCurveSet : selectedEnsembles() ) { if ( curveSet->ensemble() == selectedCurveSet ) { isSelected = true; break; } } if ( isSelected ) { uiTreeOrdering.add( curveSet ); } } uiTreeOrdering.skipRemainingChildren( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { uiOrdering.add( &m_wellPathNameOrSimWellName ); uiOrdering.add( &m_showStatisticsCurves ); uiOrdering.add( &m_showEnsembleCurves ); uiOrdering.add( &m_showErrorInObservedData ); bool ensembleDataSelected = !selectedEnsembles().empty(); m_showStatisticsCurves.uiCapability()->setUiReadOnly( !ensembleDataSelected ); m_showEnsembleCurves.uiCapability()->setUiReadOnly( !ensembleDataSelected ); RiaSimWellBranchTools::appendSimWellBranchFieldsIfRequiredFromWellName( &uiOrdering, m_wellPathNameOrSimWellName, m_branchDetection, m_branchIndex ); caf::PdmUiGroup* sourcesGroup = uiOrdering.addNewGroupWithKeyword( "Sources", "Sources" ); sourcesGroup->add( &m_selectedSources ); caf::PdmUiGroup* timeStepsGroup = uiOrdering.addNewGroupWithKeyword( "Time Steps", "TimeSteps" ); timeStepsGroup->add( &m_selectedTimeSteps ); if ( plotCount() > 0 ) { RimWellLogTrack* const track = dynamic_cast( plotByIndex( 0 ) ); if ( track ) { track->uiOrderingForRftPltFormations( uiOrdering ); track->uiOrderingForPropertyAxisSettings( uiOrdering ); caf::PdmUiGroup* depthGroup = uiOrdering.addNewGroup( "Depth Axis Settings" ); uiOrderingForDepthAxis( uiConfigName, *depthGroup ); caf::PdmUiGroup* plotLayoutGroup = uiOrdering.addNewGroup( "Plot Layout" ); plotLayoutGroup->setCollapsedByDefault(); RimWellLogPlot::uiOrderingForAutoName( uiConfigName, *plotLayoutGroup ); RimPlotWindow::uiOrderingForLegendsAndFonts( uiConfigName, uiOrdering ); plotLayoutGroup->add( &m_depthOrientation ); } } uiOrdering.skipRemainingFields( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map RimWellRftPlot::findWellSources() { std::map wellNames; RimProject* proj = RimProject::current(); if ( proj != nullptr ) { const std::vector simWellNames = proj->simulationWellNames(); std::set simWellsAssociatedWithWellPath; // Observed wells for ( RimWellPath* const wellPath : proj->allWellPaths() ) { wellNames[wellPath->name()].push_back( "Well Path" ); if ( !wellPath->associatedSimulationWellName().isEmpty() ) { simWellsAssociatedWithWellPath.insert( wellPath->associatedSimulationWellName() ); } } // Sim wells not associated with well path for ( const QString& simWellName : simWellNames ) { if ( simWellsAssociatedWithWellPath.count( simWellName ) == 0 ) { wellNames[simWellName].push_back( "Sim.Well" ); } } const std::vector rftEnsembles = RimWellPlotTools::rftEnsembles(); // Ensemble RFT wells { for ( RimSummaryCaseCollection* summaryCaseColl : rftEnsembles ) { std::set wellsWithRftData = summaryCaseColl->wellsWithRftData(); for ( const QString& wellName : wellsWithRftData ) { wellNames[wellName].push_back( "Ensemble" ); } } } // Observed FMU RFT wells const std::vector allRftFmuData = RimWellPlotTools::observedFmuRftData(); if ( !allRftFmuData.empty() ) { for ( RimObservedFmuRftData* rftFmuData : allRftFmuData ) { for ( const QString& wellName : rftFmuData->wells() ) { wellNames[wellName].push_back( "Observed" ); } } } } return wellNames; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::onLoadDataAndUpdate() { if ( m_isOnLoad ) { if ( plotCount() > 0 ) { RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( plotTrack ) { plotTrack->setAnnotationType( RiaDefines::RegionAnnotationType::FORMATION_ANNOTATIONS ); } } m_isOnLoad = false; } updateMdiWindowVisibility(); updateFormationsOnPlot(); if ( depthType() == RiaDefines::DepthTypeEnum::MEASURED_DEPTH ) { assignWellPathToExtractionCurves(); } RimWellLogPlot::onLoadDataAndUpdate(); createEnsembleCurveSets(); updateEditorsFromCurves(); // Update of curve color must happen here when loading data from project file, as the curve color is blended by the // background color. The background color is taken from the viewer. RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( plotTrack && plotTrack->viewer() ) { syncCurvesFromUiSelection(); for ( auto c : plotTrack->curves() ) { applyCurveColor( c ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::initAfterRead() { if ( m_wellLogPlot_OBSOLETE ) { RimWellLogPlot& wellLogPlot = dynamic_cast( *this ); wellLogPlot = std::move( *m_wellLogPlot_OBSOLETE.value() ); delete m_wellLogPlot_OBSOLETE; m_wellLogPlot_OBSOLETE = nullptr; } RimWellLogPlot::initAfterRead(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimWellRftPlot::showErrorBarsForObservedData() const { return m_showErrorInObservedData(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::onLegendDefinitionChanged() { syncCurvesFromUiSelection(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimWellRftPlot::useUndoRedoForFieldChanged() { // m_selectedSources use data types that are not compatible with caf // consider rewrite to caf object using ptrfield instead of pdmpointer return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::assignWellPathToExtractionCurves() { RimProject* proj = RimProject::current(); RimWellPath* wellPath = proj->wellPathByName( m_wellPathNameOrSimWellName ); if ( wellPath ) { RimWellLogTrack* const plotTrack = dynamic_cast( plotByIndex( 0 ) ); if ( plotTrack ) { for ( RimWellLogCurve* curve : plotTrack->curves() ) { auto extractionCurve = dynamic_cast( curve ); if ( extractionCurve ) { extractionCurve->setTrajectoryType( RimWellLogExtractionCurve::WELL_PATH ); extractionCurve->setWellPath( wellPath ); } } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPlotCurveSymbol::PointSymbolEnum RimWellRftPlot::statisticsCurveSymbolFromAddress( const RifEclipseRftAddress& address ) { switch ( address.wellLogChannel() ) { case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P10: return RiuPlotCurveSymbol::SYMBOL_TRIANGLE; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50: return RiuPlotCurveSymbol::SYMBOL_DOWN_TRIANGLE; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P90: return RiuPlotCurveSymbol::SYMBOL_LEFT_TRIANGLE; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_MEAN: return RiuPlotCurveSymbol::SYMBOL_RIGHT_TRIANGLE; } return RiuPlotCurveSymbol::SYMBOL_RIGHT_TRIANGLE; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPlotCurveSymbol::LabelPosition RimWellRftPlot::statisticsLabelPosFromAddress( const RifEclipseRftAddress& address ) { switch ( address.wellLogChannel() ) { case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P10: return RiuPlotCurveSymbol::LabelLeftOfSymbol; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P50: return RiuPlotCurveSymbol::LabelAboveSymbol; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_P90: return RiuPlotCurveSymbol::LabelRightOfSymbol; case RifEclipseRftAddress::RftWellLogChannelType::PRESSURE_MEAN: return RiuPlotCurveSymbol::LabelBelowSymbol; } return RiuPlotCurveSymbol::LabelAboveSymbol; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimWellRftPlot::findCurveColor( RimWellLogCurve* curve ) { RiaRftPltCurveDefinition curveDef = RimWellPlotTools::curveDefFromCurve( curve ); cvf::Color3f curveColor; if ( curveDef.address().sourceType() == RifDataSourceForRftPlt::SUMMARY_RFT ) { RimWellRftEnsembleCurveSet* ensembleCurveSet = findEnsembleCurveSet( curveDef.address().ensemble() ); if ( ensembleCurveSet && ensembleCurveSet->colorMode() == ColorMode::BY_ENSEMBLE_PARAM ) { curveColor = ensembleCurveSet->caseColor( curveDef.address().summaryCase() ); } else { RifDataSourceForRftPlt sourceAddress( RifDataSourceForRftPlt::ENSEMBLE_RFT, curveDef.address().ensemble() ); curveColor = m_dataSourceColors[sourceAddress]; } if ( m_showStatisticsCurves ) { if ( plotByIndex( 0 ) && plotByIndex( 0 )->plotWidget() ) { cvf::Color3f backgroundColor = RiaColorTools::fromQColorTo3f( plotByIndex( 0 )->plotWidget()->backgroundColor() ); curveColor = RiaColorTools::blendCvfColors( backgroundColor, curveColor, 1, 2 ); } } } else { curveColor = m_dataSourceColors[curveDef.address()]; } return curveColor; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::defineCurveColorsAndSymbols( const std::set& allCurveDefs ) { m_dataSourceColors.clear(); m_timeStepSymbols.clear(); // Clear all ensemble legends RiuQwtPlotWidget* viewer = nullptr; RimWellLogTrack* track = dynamic_cast( plotByIndex( 0 ) ); if ( track ) viewer = track->viewer(); for ( const auto& ensembleLegendPair : m_ensembleLegendFrames ) { if ( viewer && ensembleLegendPair.second ) { viewer->removeOverlayFrame( ensembleLegendPair.second ); delete ensembleLegendPair.second; } } auto ensembles = selectedEnsembles(); for ( RimWellRftEnsembleCurveSet* curveSet : m_ensembleCurveSets() ) { CAF_ASSERT( curveSet ); auto ensemble_it = std::find_if( ensembles.begin(), ensembles.end(), [&curveSet]( const RimSummaryCaseCollection* ensemble ) { return curveSet->ensemble() == ensemble; } ); if ( ensemble_it != ensembles.end() ) { curveSet->initializeLegend(); if ( viewer && curveSet->legendConfig()->showLegend() && curveSet->colorMode() == ColorMode::BY_ENSEMBLE_PARAM && !curveSet->currentEnsembleParameter().isEmpty() ) { if ( !m_ensembleLegendFrames[curveSet] ) { auto m = new RiuDraggableOverlayFrame( viewer->getParentForOverlay(), viewer->overlayMargins() ); m->setContentFrame( curveSet->legendConfig()->makeLegendFrame() ); m_ensembleLegendFrames[curveSet] = m; } viewer->addOverlayFrame( m_ensembleLegendFrames[curveSet] ); } } } std::vector colorTable; RiaColorTables::summaryCurveDefaultPaletteColors().color3fArray().toStdVector( &colorTable ); std::vector symbolTable = { RiuPlotCurveSymbol::SYMBOL_ELLIPSE, RiuPlotCurveSymbol::SYMBOL_RECT, RiuPlotCurveSymbol::SYMBOL_DIAMOND, RiuPlotCurveSymbol::SYMBOL_CROSS, RiuPlotCurveSymbol::SYMBOL_XCROSS, RiuPlotCurveSymbol::SYMBOL_STAR1 }; // Add new curves for ( const RiaRftPltCurveDefinition& curveDefToAdd : allCurveDefs ) { auto colorTableIndex = m_dataSourceColors.size(); auto symbolTableIndex = m_timeStepSymbols.size(); const RifDataSourceForRftPlt& address = curveDefToAdd.address(); RifDataSourceForRftPlt colorAddress = address; if ( address.sourceType() == RifDataSourceForRftPlt::SUMMARY_RFT ) { colorAddress = RifDataSourceForRftPlt( RifDataSourceForRftPlt::ENSEMBLE_RFT, address.ensemble() ); } if ( !m_dataSourceColors.count( colorAddress ) ) { colorTableIndex = colorTableIndex % colorTable.size(); m_dataSourceColors[colorAddress] = colorTable[colorTableIndex]; } if ( address.sourceType() != RifDataSourceForRftPlt::ENSEMBLE_RFT ) { if ( !m_timeStepSymbols.count( curveDefToAdd.timeStep() ) ) { symbolTableIndex = symbolTableIndex % symbolTable.size(); m_timeStepSymbols[curveDefToAdd.timeStep()] = symbolTable[symbolTableIndex]; } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimWellRftPlot::selectedEnsembles() const { std::vector ensembleSets; for ( const RifDataSourceForRftPlt& dataSource : m_selectedSources() ) { if ( dataSource.ensemble() != nullptr ) { ensembleSets.push_back( dataSource.ensemble() ); } } return ensembleSets; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::createEnsembleCurveSets() { const std::vector rftEnsembles = RimWellPlotTools::rftEnsemblesForWell( m_wellPathNameOrSimWellName ); // First delete any curve sets not belonging to the given rftEnsembles std::vector curveSetsToDelete; for ( RimWellRftEnsembleCurveSet* curveSet : m_ensembleCurveSets() ) { if ( std::find( rftEnsembles.begin(), rftEnsembles.end(), curveSet->ensemble() ) == rftEnsembles.end() ) { curveSetsToDelete.push_back( curveSet ); } } for ( RimWellRftEnsembleCurveSet* curveSet : curveSetsToDelete ) { m_ensembleCurveSets.removeChild( curveSet ); delete curveSet; } // Then add curve set for any ensembles we haven't already added for ( RimSummaryCaseCollection* ensemble : rftEnsembles ) { auto it = std::find_if( m_ensembleCurveSets.begin(), m_ensembleCurveSets.end(), [ensemble]( const RimWellRftEnsembleCurveSet* curveSet ) { return curveSet->ensemble() == ensemble; } ); if ( it == m_ensembleCurveSets.end() ) { RimWellRftEnsembleCurveSet* curveSet = new RimWellRftEnsembleCurveSet; curveSet->setEnsemble( ensemble ); m_ensembleCurveSets.push_back( curveSet ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimWellRftEnsembleCurveSet* RimWellRftPlot::findEnsembleCurveSet( RimSummaryCaseCollection* ensemble ) const { for ( RimWellRftEnsembleCurveSet* curveSet : m_ensembleCurveSets() ) { if ( ensemble == curveSet->ensemble() ) { return curveSet; } } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimObservedFmuRftData* RimWellRftPlot::findObservedFmuData( const QString& wellPathName, const QDateTime& timeStep ) const { auto allObservedDataForWell = RimWellPlotTools::observedFmuRftDataForWell( wellPathName ); for ( auto observedData : allObservedDataForWell ) { if ( observedData->rftReader()->availableTimeSteps( wellPathName ).count( timeStep ) ) { return observedData; } } return nullptr; }