///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2020- Equinor 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 "RimCorrelationPlotCollection.h" #include "Summary/RiaSummaryCurveDefinition.h" #include "Formations/RimWellFormationsCollection.h" #include "Formations/RimWellFormationsFile.h" #include "RimCorrelationMatrixPlot.h" #include "RimCorrelationPlot.h" #include "RimCorrelationReportPlot.h" #include "RimOilField.h" #include "RimParameterResultCrossPlot.h" #include "RimParameterRftCrossPlot.h" #include "RimProject.h" #include "RimRftCorrelationReportPlot.h" #include "RimRftCrossPlotTools.h" #include "RimSummaryEnsemble.h" #include "RimSummaryEnsembleTools.h" #include "RimWellRftEnsembleCurveSet.h" #include "RimWellRftPlot.h" #include "cafCmdFeatureMenuBuilder.h" CAF_PDM_SOURCE_INIT( RimCorrelationPlotCollection, "CorrelationPlotCollection" ); namespace { //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void applyBestCorrelatedParameterToCrossPlot( RimParameterResultCrossPlot* crossPlot, RimSummaryEnsemble* ensemble, const std::vector& curveDefsTornadoAndCrossPlot, std::time_t timeStep ) { if ( curveDefsTornadoAndCrossPlot.empty() ) return; auto correlationSortedEnsembleParameters = ensemble->correlationSortedEnsembleParameters( curveDefsTornadoAndCrossPlot.front().summaryAddressY(), timeStep ); if ( correlationSortedEnsembleParameters.empty() ) return; QString crossPlotEnsembleParameterName = correlationSortedEnsembleParameters.front().first.name; crossPlot->setEnsembleParameter( crossPlotEnsembleParameterName ); } } // namespace //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationPlotCollection::RimCorrelationPlotCollection() { CAF_PDM_InitObject( "Ensemble Correlation Plots", ":/CorrelationPlots16x16.png" ); CAF_PDM_InitFieldNoDefault( &m_correlationPlots, "CorrelationPlots", "Correlation Plots" ); CAF_PDM_InitFieldNoDefault( &m_correlationReports, "CorrelationReports", "Correlation Reports" ); CAF_PDM_InitFieldNoDefault( &m_rftCorrelationReports, "RftCorrelationReports", "RFT Correlation Reports" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationPlotCollection::~RimCorrelationPlotCollection() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationPlot* RimCorrelationPlotCollection::createCorrelationPlot( bool defaultToFirstEnsembleFopt ) { RimCorrelationPlot* plot = new RimCorrelationPlot(); plot->dockAsPlotWindow(); if ( defaultToFirstEnsembleFopt ) applyFirstEnsembleFieldAddressesToPlot( plot, { "FOPT" } ); plot->selectAllParameters(); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationPlot* RimCorrelationPlotCollection::createCorrelationPlot( RimSummaryEnsemble* ensemble, const QString& quantityName, std::time_t timeStep ) { RimCorrelationPlot* plot = new RimCorrelationPlot(); plot->dockAsPlotWindow(); applyEnsembleFieldAndTimeStepToPlot( plot, ensemble, { quantityName }, timeStep ); plot->selectAllParameters(); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationMatrixPlot* RimCorrelationPlotCollection::createCorrelationMatrixPlot( bool defaultToFirstEnsembleField ) { RimCorrelationMatrixPlot* plot = new RimCorrelationMatrixPlot(); plot->dockAsPlotWindow(); if ( defaultToFirstEnsembleField ) applyFirstEnsembleFieldAddressesToPlot( plot, { "FOPT", "FWPT", "FGPT" } ); plot->selectAllParameters(); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationMatrixPlot* RimCorrelationPlotCollection::createCorrelationMatrixPlot( RimSummaryEnsemble* ensemble, const std::vector& quantityNames, std::time_t timeStep ) { RimCorrelationMatrixPlot* plot = new RimCorrelationMatrixPlot(); plot->dockAsPlotWindow(); applyEnsembleFieldAndTimeStepToPlot( plot, ensemble, quantityNames, timeStep ); plot->selectAllParameters(); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimParameterResultCrossPlot* RimCorrelationPlotCollection::createParameterResultCrossPlot( bool defaultToFirstEnsembleFopt ) { RimParameterResultCrossPlot* plot = new RimParameterResultCrossPlot; plot->dockAsPlotWindow(); if ( defaultToFirstEnsembleFopt ) applyFirstEnsembleFieldAddressesToPlot( plot, { "FOPT" } ); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimParameterResultCrossPlot* RimCorrelationPlotCollection::createParameterResultCrossPlot( RimSummaryEnsemble* ensemble, const QString& paramName, const QString& quantityName, std::time_t timeStep ) { RimParameterResultCrossPlot* plot = new RimParameterResultCrossPlot; plot->dockAsPlotWindow(); applyEnsembleFieldAndTimeStepToPlot( plot, ensemble, { quantityName }, timeStep ); plot->setEnsembleParameter( paramName ); addPlot( plot ); return plot; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationReportPlot* RimCorrelationPlotCollection::createCorrelationReportPlot( bool defaultToFirstEnsembleField /*= true */ ) { RimCorrelationReportPlot* report = new RimCorrelationReportPlot; report->dockAsPlotWindow(); if ( defaultToFirstEnsembleField ) applyFirstEnsembleFieldAddressesToReport( report, { "FOPT", "FWPT", "FGPT" }, "FOPT" ); report->matrixPlot()->selectAllParameters(); report->correlationPlot()->selectAllParameters(); m_correlationReports.push_back( report ); return report; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCorrelationReportPlot* RimCorrelationPlotCollection::createCorrelationReportPlot( RimSummaryEnsemble* ensemble, const std::vector& matrixQuantityNames, const QString& tornadoAndCrossPlotQuantityName, std::time_t timeStep ) { RimCorrelationReportPlot* report = new RimCorrelationReportPlot; report->dockAsPlotWindow(); applyEnsembleFieldAndTimeStepToReport( report, ensemble, matrixQuantityNames, tornadoAndCrossPlotQuantityName, timeStep ); report->matrixPlot()->selectAllParameters(); report->correlationPlot()->selectAllParameters(); m_correlationReports.push_back( report ); return report; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationReportPlot( RimWellRftPlot* source ) { auto* report = new RimRftCorrelationReportPlot; report->dockAsPlotWindow(); report->initializeFromSourcePlot( source ); auto* rftPlot = report->wellRftPlot(); if ( rftPlot ) { const auto ensembles = rftPlot->selectedEnsembles(); if ( !ensembles.empty() ) { auto* ensemble = ensembles.front(); report->crossPlot()->setEnsemble( ensemble ); // Pick the first numeric ensemble parameter as a default for ( const auto& param : RimSummaryEnsembleTools::alphabeticEnsembleParameters( ensemble->allSummaryCases() ) ) { if ( param.isNumeric() ) { report->crossPlot()->setEnsembleParameter( param.name ); if ( auto* curveSet = rftPlot->findEnsembleCurveSet( ensemble ) ) { curveSet->setColorByEnsembleParameter( param.name ); } break; } } } const QString wellName = rftPlot->simWellOrWellPathName(); report->crossPlot()->setWellName( wellName ); // Default to filtering by formation when a formations file has data for the well if ( auto* project = RimProject::current(); project && project->activeOilField() && project->activeOilField()->wellFormationsCollection() ) { for ( RimWellFormationsFile* file : project->activeOilField()->wellFormationsCollection()->wellFormationsFiles() ) { if ( file->formationsForWell( wellName ) ) { report->crossPlot()->setWellFormations( file ); report->crossPlot()->setFilterMode( RimRftCrossPlotTools::DepthFilterMode::ZONES ); break; } } } const auto timeSteps = rftPlot->selectedTimeSteps(); if ( !timeSteps.empty() ) report->crossPlot()->setTimeStep( timeSteps.front() ); } m_rftCorrelationReports.push_back( report ); return report; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimCorrelationPlotCollection::rftReports() const { return m_rftCorrelationReports.childrenByType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const { menuBuilder << "RicNewCorrelationPlotFeature"; menuBuilder << "RicNewCorrelationMatrixPlotFeature"; menuBuilder << "RicNewParameterResultCrossPlotFeature"; menuBuilder << "RicNewCorrelationReportPlotFeature"; menuBuilder.addSeparator(); menuBuilder << "RicCreateRftCorrelationReportFeature"; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::insertPlot( RimAbstractCorrelationPlot* plot, size_t index ) { m_correlationPlots.insert( index, plot ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::removePlot( RimAbstractCorrelationPlot* plot ) { m_correlationPlots.removeChild( plot ); updateAllRequiredEditors(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimCorrelationPlotCollection::plots() const { return m_correlationPlots.childrenByType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RimCorrelationPlotCollection::plotCount() const { return m_correlationPlots.size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimCorrelationPlotCollection::reports() const { return m_correlationReports.childrenByType(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::deleteAllPlots() { RimTypedPlotCollection::deleteAllPlots(); m_correlationReports.deleteChildren(); m_rftCorrelationReports.deleteChildren(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::applyFirstEnsembleFieldAddressesToPlot( RimAbstractCorrelationPlot* plot, const std::vector& quantityNames /*= {} */ ) { std::vector ensembles = RimProject::current()->descendantsIncludingThisOfType(); if ( !ensembles.empty() ) { std::set allAddresses = ensembles.front()->ensembleSummaryAddresses(); std::vector curveDefs; for ( auto address : allAddresses ) { auto it = std::find( quantityNames.begin(), quantityNames.end(), QString::fromStdString( address.uiText() ) ); if ( it != quantityNames.end() || quantityNames.empty() ) { curveDefs.push_back( RiaSummaryCurveDefinition( ensembles.front(), address ) ); } } plot->setCurveDefinitions( curveDefs ); auto crossPlot = dynamic_cast( plot ); if ( crossPlot ) { // An ensemble without realization parameters has no parameters to select const auto parameters = RimSummaryEnsembleTools::alphabeticEnsembleParameters( ensembles.front()->allSummaryCases() ); if ( !parameters.empty() ) crossPlot->setEnsembleParameter( parameters.front().name ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::applyEnsembleFieldAndTimeStepToPlot( RimAbstractCorrelationPlot* plot, RimSummaryEnsemble* ensemble, const std::vector& quantityNames, std::time_t timeStep ) { if ( ensemble ) { std::set allAddresses = ensemble->ensembleSummaryAddresses(); std::vector curveDefs; std::vector highestCorrelationParameters; for ( auto address : allAddresses ) { auto it = std::find( quantityNames.begin(), quantityNames.end(), QString::fromStdString( address.uiText() ) ); if ( it != quantityNames.end() || quantityNames.empty() ) { curveDefs.push_back( RiaSummaryCurveDefinition( ensemble, address ) ); auto correlationSortedEnsembleParameters = ensemble->correlationSortedEnsembleParameters( address, timeStep ); if ( !correlationSortedEnsembleParameters.empty() ) highestCorrelationParameters.push_back( correlationSortedEnsembleParameters.front().first.name ); } } plot->setCurveDefinitions( curveDefs ); plot->setTimeStep( timeStep ); auto crossPlot = dynamic_cast( plot ); if ( crossPlot && !highestCorrelationParameters.empty() ) { crossPlot->setEnsembleParameter( highestCorrelationParameters.front() ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::applyFirstEnsembleFieldAddressesToReport( RimCorrelationReportPlot* plot, const std::vector& matrixQuantityNames, const QString& tornadoAndCrossPlotQuantityName ) { std::vector ensembles = RimProject::current()->descendantsIncludingThisOfType(); if ( !ensembles.empty() ) { std::set allAddresses = ensembles.front()->ensembleSummaryAddresses(); std::vector curveDefsMatrix; std::vector curveDefsTornadoAndCrossPlot; for ( auto address : allAddresses ) { auto it = std::find( matrixQuantityNames.begin(), matrixQuantityNames.end(), QString::fromStdString( address.uiText() ) ); if ( it != matrixQuantityNames.end() || matrixQuantityNames.empty() ) { curveDefsMatrix.push_back( RiaSummaryCurveDefinition( ensembles.front(), address ) ); } if ( tornadoAndCrossPlotQuantityName.isEmpty() || tornadoAndCrossPlotQuantityName == QString::fromStdString( address.uiText() ) ) { curveDefsTornadoAndCrossPlot.push_back( RiaSummaryCurveDefinition( ensembles.front(), address ) ); } } plot->matrixPlot()->setCurveDefinitions( curveDefsMatrix ); plot->correlationPlot()->setCurveDefinitions( curveDefsTornadoAndCrossPlot ); plot->crossPlot()->setCurveDefinitions( curveDefsTornadoAndCrossPlot ); auto availableTimeSteps = plot->matrixPlot()->allAvailableTimeSteps(); if ( availableTimeSteps.empty() ) return; time_t timeStep = *( availableTimeSteps.rbegin() ); applyBestCorrelatedParameterToCrossPlot( plot->crossPlot(), ensembles.front(), curveDefsTornadoAndCrossPlot, timeStep ); plot->matrixPlot()->setTimeStep( timeStep ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::applyEnsembleFieldAndTimeStepToReport( RimCorrelationReportPlot* plot, RimSummaryEnsemble* ensemble, const std::vector& matrixQuantityNames, const QString& tornadoAndCrossPlotQuantityName, std::time_t timeStep ) { if ( ensemble ) { std::set allAddresses = ensemble->ensembleSummaryAddresses(); std::vector curveDefsMatrix; std::vector curveDefsTornadoAndCrossPlot; for ( auto address : allAddresses ) { auto it = std::find( matrixQuantityNames.begin(), matrixQuantityNames.end(), QString::fromStdString( address.uiText() ) ); if ( it != matrixQuantityNames.end() || matrixQuantityNames.empty() ) { curveDefsMatrix.push_back( RiaSummaryCurveDefinition( ensemble, address ) ); } if ( tornadoAndCrossPlotQuantityName.isEmpty() || tornadoAndCrossPlotQuantityName == QString::fromStdString( address.uiText() ) ) { curveDefsTornadoAndCrossPlot.push_back( RiaSummaryCurveDefinition( ensemble, address ) ); } } plot->matrixPlot()->setCurveDefinitions( curveDefsMatrix ); plot->matrixPlot()->setTimeStep( timeStep ); plot->correlationPlot()->setCurveDefinitions( curveDefsTornadoAndCrossPlot ); plot->correlationPlot()->setTimeStep( timeStep ); plot->crossPlot()->setCurveDefinitions( curveDefsTornadoAndCrossPlot ); plot->crossPlot()->setTimeStep( timeStep ); applyBestCorrelatedParameterToCrossPlot( plot->crossPlot(), ensemble, curveDefsTornadoAndCrossPlot, timeStep ); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimCorrelationPlotCollection::loadDataAndUpdateAllPlots() { for ( const auto& corrPlot : m_correlationPlots ) corrPlot->loadDataAndUpdate(); for ( const auto& report : m_correlationReports ) report->loadDataAndUpdate(); for ( const auto& rftReport : m_rftCorrelationReports ) rftReport->loadDataAndUpdate(); }