mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 13:47:12 -05:00
437 lines
18 KiB
C++
437 lines
18 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2026 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 <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RimRftTornadoPlot.h"
|
|
|
|
#include "RiaColorTools.h"
|
|
#include "RiaPreferences.h"
|
|
|
|
#include "RigEnsembleParameter.h"
|
|
#include "RigStatisticsTools.h"
|
|
|
|
#include "RimCorrelationBarChartTools.h"
|
|
#include "RimEclipseResultCase.h"
|
|
#include "RimParameterRftCrossPlot.h"
|
|
#include "RimSummaryEnsemble.h"
|
|
#include "RimSummaryEnsembleTools.h"
|
|
|
|
#include "RiuContextMenuLauncher.h"
|
|
#include "RiuGroupedBarChartBuilder.h"
|
|
#include "RiuPlotItem.h"
|
|
#include "RiuQwtPlotWidget.h"
|
|
|
|
#include "cafPdmUiCheckBoxEditor.h"
|
|
|
|
#include "qwt_plot.h"
|
|
#include "qwt_text.h"
|
|
|
|
#include <QPaintDevice>
|
|
|
|
#include <limits>
|
|
#include <map>
|
|
#include <numeric>
|
|
|
|
CAF_PDM_SOURCE_INIT( RimRftTornadoPlot, "RftTornadoPlot" );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimRftTornadoPlot::RimRftTornadoPlot()
|
|
{
|
|
CAF_PDM_InitObject( "RFT Tornado Plot", ":/CorrelationTornadoPlot16x16.png" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_ensemble, "Ensemble", "Ensemble" );
|
|
CAF_PDM_InitField( &m_wellName, "WellName", QString(), "Well Name" );
|
|
CAF_PDM_InitFieldNoDefault( &m_selectedTimeStep, "TimeStep", "Time Step" );
|
|
CAF_PDM_InitFieldNoDefault( &m_eclipseCase, "EclipseCase", "Eclipse Case (MD fallback)" );
|
|
CAF_PDM_InitField( &m_useDepthRange, "UseDepthRange", false, "Filter by Depth Range" );
|
|
CAF_PDM_InitField( &m_depthRangeMin, "DepthRangeMin", 0.0, "Min Depth (MD)" );
|
|
CAF_PDM_InitField( &m_depthRangeMax, "DepthRangeMax", 5000.0, "Max Depth (MD)" );
|
|
|
|
CAF_PDM_InitField( &m_showAbsoluteValues, "ShowAbsoluteValues", false, "Show Absolute Values" );
|
|
CAF_PDM_InitField( &m_sortByAbsoluteValues, "SortByAbsoluteValues", true, "Sort by Absolute Values" );
|
|
CAF_PDM_InitField( &m_showOnlyTopNCorrelations, "ShowOnlyTopN", true, "Show Only Top Correlations" );
|
|
CAF_PDM_InitField( &m_topNFilterCount, "TopNFilterCount", 10, "Number of Rows" );
|
|
|
|
QColor qColor = QColor( "#3173b2" );
|
|
CAF_PDM_InitField( &m_barColor, "BarColor", RiaColorTools::fromQColorTo3f( qColor ), "Bar Color (Positive)" );
|
|
QColor highlightColor = QColor( "#f5a623" );
|
|
CAF_PDM_InitField( &m_highlightBarColor, "HighlightBarColor", RiaColorTools::fromQColorTo3f( highlightColor ), "Bar Color (Selected)" );
|
|
|
|
CAF_PDM_InitField( &m_useAutoPlotTitle, "UseAutoPlotTitle", true, "Auto Title" );
|
|
CAF_PDM_InitField( &m_description, "Description", QString( "RFT Tornado Plot" ), "Title" );
|
|
|
|
CAF_PDM_InitFieldNoDefault( &m_labelFontSize, "LabelFontSize", "Bar Label Font Size" );
|
|
CAF_PDM_InitFieldNoDefault( &m_axisTitleFontSize, "AxisTitleFontSize", "Axis Title Font Size" );
|
|
CAF_PDM_InitFieldNoDefault( &m_axisValueFontSize, "AxisValueFontSize", "Axis Value Font Size" );
|
|
|
|
m_labelFontSize = caf::FontTools::RelativeSize::Small;
|
|
m_axisTitleFontSize = caf::FontTools::RelativeSize::Small;
|
|
m_axisValueFontSize = caf::FontTools::RelativeSize::Small;
|
|
|
|
m_showPlotLegends = false;
|
|
setLegendsVisible( false );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RimRftTornadoPlot::~RimRftTornadoPlot()
|
|
{
|
|
cleanupBeforeClose();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setEnsemble( RimSummaryEnsemble* ensemble )
|
|
{
|
|
m_ensemble = ensemble;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setWellName( const QString& wellName )
|
|
{
|
|
m_wellName = wellName;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setTimeStep( const QDateTime& timeStep )
|
|
{
|
|
m_selectedTimeStep = timeStep;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setEclipseCase( RimEclipseResultCase* eclipseCase )
|
|
{
|
|
m_eclipseCase = eclipseCase;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setUseDepthRange( bool useDepthRange )
|
|
{
|
|
m_useDepthRange = useDepthRange;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setDepthRange( double minMd, double maxMd )
|
|
{
|
|
m_depthRangeMin = minMd;
|
|
m_depthRangeMax = maxMd;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setSelectedParameter( const QString& paramName )
|
|
{
|
|
m_selectedParameter = paramName;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::setParameterSelectedCallback( ParameterSelectedCallback callback )
|
|
{
|
|
m_parameterSelectedCallback = std::move( callback );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuQwtPlotWidget* RimRftTornadoPlot::viewer()
|
|
{
|
|
return m_plotWidget;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuPlotWidget* RimRftTornadoPlot::plotWidget()
|
|
{
|
|
return m_plotWidget;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::updateAxes()
|
|
{
|
|
if ( !m_plotWidget ) return;
|
|
|
|
const int titleSize = caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_axisTitleFontSize() );
|
|
const int valueSize = caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_axisValueFontSize() );
|
|
|
|
m_plotWidget->setAxisTitleText( RiuPlotAxis::defaultLeft(), "Parameter" );
|
|
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultLeft(), true );
|
|
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultLeft(), titleSize, valueSize, false, Qt::AlignCenter );
|
|
|
|
if ( m_showAbsoluteValues() )
|
|
{
|
|
m_plotWidget->setAxisTitleText( RiuPlotAxis::defaultBottom(), "Pearson Correlation Coefficient ABS" );
|
|
// Use a small negative margin so bar label text (anchored at x=0) remains visible
|
|
m_plotWidget->setAxisRange( RiuPlotAxis::defaultBottom(), -0.15, 1.0 );
|
|
}
|
|
else
|
|
{
|
|
m_plotWidget->setAxisTitleText( RiuPlotAxis::defaultBottom(), "Pearson Correlation Coefficient" );
|
|
m_plotWidget->setAxisRange( RiuPlotAxis::defaultBottom(), -1.0, 1.0 );
|
|
}
|
|
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultBottom(), true );
|
|
m_plotWidget->setAxisFontsAndAlignment( RiuPlotAxis::defaultBottom(), titleSize, valueSize, false, Qt::AlignCenter );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimRftTornadoPlot::asciiDataForPlotExport() const
|
|
{
|
|
RiuGroupedBarChartBuilder chartBuilder;
|
|
addDataToChartBuilder( chartBuilder );
|
|
return chartBuilder.plotContentAsText();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::detachAllCurves()
|
|
{
|
|
if ( m_plotWidget )
|
|
{
|
|
m_plotWidget->qwtPlot()->detachItems( QwtPlotItem::Rtti_PlotBarChart );
|
|
m_plotWidget->qwtPlot()->detachItems( QwtPlotItem::Rtti_PlotScale );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RimRftTornadoPlot::description() const
|
|
{
|
|
return m_description();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QWidget* RimRftTornadoPlot::viewWidget()
|
|
{
|
|
return m_plotWidget;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::deleteViewWidget()
|
|
{
|
|
cleanupBeforeClose();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::doRenderWindowContent( QPaintDevice* paintDevice )
|
|
{
|
|
if ( m_plotWidget ) m_plotWidget->render( paintDevice );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
RiuPlotWidget* RimRftTornadoPlot::doCreatePlotViewWidget( QWidget* parent )
|
|
{
|
|
if ( !m_plotWidget )
|
|
{
|
|
m_plotWidget = new RiuQwtPlotWidget( this, parent );
|
|
updatePlotTitle();
|
|
new RiuContextMenuLauncher( m_plotWidget, { "RicShowPlotDataFeature" } );
|
|
}
|
|
return m_plotWidget;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::onLoadDataAndUpdate()
|
|
{
|
|
updateDockWindowVisibility();
|
|
|
|
if ( m_plotWidget )
|
|
{
|
|
detachAllCurves();
|
|
|
|
RiuGroupedBarChartBuilder chartBuilder;
|
|
chartBuilder.setBarColor( RiaColorTools::toQColor( m_barColor() ) );
|
|
m_lastCorrelations = addDataToChartBuilder( chartBuilder );
|
|
const int labelSize = caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), m_labelFontSize() );
|
|
chartBuilder.setLabelFontSize( labelSize );
|
|
chartBuilder.addBarChartToPlot( m_plotWidget->qwtPlot(), Qt::Horizontal, m_showOnlyTopNCorrelations() ? m_topNFilterCount() : -1 );
|
|
RimCorrelationBarChartTools::highlightSelectedParameterBar( m_plotWidget,
|
|
m_selectedParameter,
|
|
RiaColorTools::toQColor( m_barColor() ),
|
|
RiaColorTools::toQColor( m_highlightBarColor() ) );
|
|
|
|
m_plotWidget->qwtPlot()->insertLegend( nullptr );
|
|
|
|
updateAxes();
|
|
updatePlotTitle();
|
|
m_plotWidget->scheduleReplot();
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
|
{
|
|
auto* settingsGroup = uiOrdering.addNewGroup( "Tornado Settings" );
|
|
settingsGroup->add( &m_showAbsoluteValues );
|
|
if ( !m_showAbsoluteValues() ) settingsGroup->add( &m_sortByAbsoluteValues );
|
|
settingsGroup->add( &m_showOnlyTopNCorrelations );
|
|
if ( m_showOnlyTopNCorrelations() ) settingsGroup->add( &m_topNFilterCount );
|
|
|
|
auto* colorGroup = uiOrdering.addNewGroup( "Colors" );
|
|
colorGroup->setCollapsedByDefault();
|
|
colorGroup->add( &m_barColor );
|
|
colorGroup->add( &m_highlightBarColor );
|
|
|
|
auto* plotGroup = uiOrdering.addNewGroup( "Plot Settings" );
|
|
plotGroup->setCollapsedByDefault();
|
|
plotGroup->add( &m_useAutoPlotTitle );
|
|
plotGroup->add( &m_description );
|
|
plotGroup->add( &m_labelFontSize );
|
|
plotGroup->add( &m_axisTitleFontSize );
|
|
plotGroup->add( &m_axisValueFontSize );
|
|
m_description.uiCapability()->setUiReadOnly( m_useAutoPlotTitle() );
|
|
|
|
uiOrdering.skipRemainingFields( true );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
|
{
|
|
RimPlot::fieldChangedByUi( changedField, oldValue, newValue );
|
|
loadDataAndUpdate();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::onPlotItemSelected( std::shared_ptr<RiuPlotItem> plotItem, bool /*toggle*/, int /*sampleIndex*/ )
|
|
{
|
|
const QString paramName = RimCorrelationBarChartTools::parameterNameFromPlotItem( plotItem );
|
|
if ( !paramName.isEmpty() && m_parameterSelectedCallback ) m_parameterSelectedCallback( paramName );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::map<QString, double> RimRftTornadoPlot::addDataToChartBuilder( RiuGroupedBarChartBuilder& chartBuilder ) const
|
|
{
|
|
std::map<QString, double> correlations;
|
|
|
|
if ( !m_ensemble() || m_wellName().isEmpty() || !m_selectedTimeStep().isValid() ) return correlations;
|
|
|
|
const auto& allCases = m_ensemble->allSummaryCases();
|
|
|
|
// Build pressure vector per case (indices match allCases order)
|
|
const std::vector<double> pressurePerCase = RimParameterRftCrossPlot::computeMeanPressurePerCase( m_ensemble(),
|
|
m_wellName(),
|
|
m_selectedTimeStep(),
|
|
m_eclipseCase(),
|
|
m_useDepthRange(),
|
|
m_depthRangeMin(),
|
|
m_depthRangeMax() );
|
|
|
|
// For each numeric parameter, compute Pearson correlation against pressurePerCase
|
|
for ( const auto& param : RimSummaryEnsembleTools::alphabeticEnsembleParameters( allCases ) )
|
|
{
|
|
if ( !param.isNumeric() ) continue;
|
|
if ( static_cast<size_t>( param.values.size() ) != allCases.size() ) continue;
|
|
|
|
std::vector<double> paramValues;
|
|
std::vector<double> pressureValues;
|
|
paramValues.reserve( allCases.size() );
|
|
pressureValues.reserve( allCases.size() );
|
|
|
|
for ( size_t i = 0; i < allCases.size(); ++i )
|
|
{
|
|
if ( std::isinf( pressurePerCase[i] ) ) continue;
|
|
paramValues.push_back( param.values[i].toDouble() );
|
|
pressureValues.push_back( pressurePerCase[i] );
|
|
}
|
|
|
|
if ( paramValues.size() < 2 ) continue;
|
|
|
|
double pearson = RigStatisticsTools::pearsonCorrelation( paramValues, pressureValues );
|
|
if ( std::isinf( pearson ) || std::isnan( pearson ) ) continue;
|
|
|
|
correlations[param.name] = pearson;
|
|
|
|
RimCorrelationBarChartTools::addCorrelationBar( chartBuilder, param.name, pearson, m_showAbsoluteValues(), m_sortByAbsoluteValues() );
|
|
}
|
|
|
|
return correlations;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::updatePlotTitle()
|
|
{
|
|
if ( !m_plotWidget ) return;
|
|
|
|
if ( m_useAutoPlotTitle() && m_ensemble() )
|
|
{
|
|
const QString rangeStr = m_useDepthRange() ? QString( " [MD %1 - %2 m]" ).arg( m_depthRangeMin() ).arg( m_depthRangeMax() )
|
|
: QString();
|
|
m_description = QString( "Parameter Correlation vs RFT Pressure%1, %2" ).arg( rangeStr ).arg( m_ensemble->name() );
|
|
}
|
|
|
|
m_plotWidget->setPlotTitle( m_description() );
|
|
m_plotWidget->setPlotTitleEnabled( m_showPlotTitle() );
|
|
m_plotWidget->setPlotTitleFontSize( titleFontSize() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RimRftTornadoPlot::cleanupBeforeClose()
|
|
{
|
|
detachAllCurves();
|
|
|
|
if ( m_plotWidget )
|
|
{
|
|
m_plotWidget->setParent( nullptr );
|
|
delete m_plotWidget;
|
|
m_plotWidget = nullptr;
|
|
}
|
|
}
|