#14889: RFT Ensemble: Additional UI fixes

* #14889: Do not change main window when importing well picks
* #14889: Fix clipped bottom of plots in dock windows
* #14889: Add Create RFT Correlation Report to Ensemble Correlation Plots menu
* #14889: Show imported observed FMU RFT data as table
* #14889: Use time step from source RFT plot in RFT correlation report
* #14889: Show observed data in RFT cross plot when no RFT samples are available
* #14889: Keep RFT plot zoom when toggling formation in RFT correlation report
* #14889: Do not change main window when importing formations
* #14889: Use general delete for observed data and improve FMU RFT data name
This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-10-12 18:50:57 +02:00
1 parent fb566f112c
commit c57864df51
36 files changed
+373 -319

No files matched your search

@@ -3,7 +3,6 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicCloseCaseFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCloseSummaryCaseFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCloseSummaryCaseInCollectionFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicCloseObservedDataFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewViewFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewGenericDataViewFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewContourMapViewFeature.cpp
@@ -1,132 +0,0 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicCloseObservedDataFeature.h"
#include "Summary/RiaSummaryTools.h"
#include "RimMainPlotCollection.h"
#include "RimObservedDataCollection.h"
#include "RimObservedFmuRftData.h"
#include "RimObservedSummaryData.h"
#include "RimRftPlotCollection.h"
#include "RimSummaryMultiPlot.h"
#include "RimSummaryMultiPlotCollection.h"
#include "RimSummaryPlot.h"
#include "RimWellRftPlot.h"
#include "cafSelectionManager.h"
#include "cafAssert.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicCloseObservedDataFeature, "RicCloseObservedDataFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCloseObservedDataFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Close" );
actionToSetup->setIcon( QIcon( ":/Close.svg" ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCloseObservedDataFeature::deleteObservedSummaryData( const std::vector<RimObservedSummaryData*>& data )
{
RimSummaryMultiPlotCollection* summaryPlotColl = RiaSummaryTools::summaryMultiPlotCollection();
for ( RimObservedSummaryData* observedData : data )
{
for ( RimSummaryMultiPlot* multiPlot : summaryPlotColl->multiPlots() )
{
for ( RimSummaryPlot* summaryPlot : multiPlot->summaryPlots() )
{
summaryPlot->deleteCurvesAssosiatedWithCases( { observedData } );
}
multiPlot->updateConnectedEditors();
}
RimObservedDataCollection* observedDataCollection = observedData->firstAncestorOrThisOfTypeAsserted<RimObservedDataCollection>();
observedDataCollection->removeObservedSummaryData( observedData );
delete observedData;
observedDataCollection->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCloseObservedDataFeature::deleteObservedRmuRftData( const std::vector<RimObservedFmuRftData*>& data )
{
RimRftPlotCollection* rftPlotColl = RimMainPlotCollection::current()->rftPlotCollection();
for ( RimObservedFmuRftData* observedData : data )
{
RimObservedDataCollection* observedDataCollection = observedData->firstAncestorOrThisOfTypeAsserted<RimObservedDataCollection>();
for ( RimWellRftPlot* plot : rftPlotColl->rftPlots() )
{
plot->deleteCurvesAssosicatedWithObservedData( observedData );
}
observedDataCollection->removeObservedFmuRftData( observedData );
delete observedData;
observedDataCollection->updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicCloseObservedDataFeature::isCommandEnabled() const
{
const auto summarySelection = caf::SelectionManager::instance()->objectsByType<RimObservedSummaryData>();
const auto fmuRftSelection = caf::SelectionManager::instance()->objectsByType<RimObservedFmuRftData>();
if ( summarySelection.empty() && fmuRftSelection.empty() )
{
return false;
}
for ( RimObservedSummaryData* data : summarySelection )
{
if ( !data->isObservedData() )
{
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicCloseObservedDataFeature::onActionTriggered( bool isChecked )
{
const auto summarySelection = caf::SelectionManager::instance()->objectsByType<RimObservedSummaryData>();
const auto fmuRftSelection = caf::SelectionManager::instance()->objectsByType<RimObservedFmuRftData>();
CAF_ASSERT( !( summarySelection.empty() && fmuRftSelection.empty() ) );
RicCloseObservedDataFeature::deleteObservedSummaryData( summarySelection );
RicCloseObservedDataFeature::deleteObservedRmuRftData( fmuRftSelection );
}
@@ -19,14 +19,15 @@
#include "RicImportWellFormationsFeature.h"
#include "RiaApplication.h"
#include "RiaGuiApplication.h"
#include "Formations/RimWellFormationsCollection.h"
#include "Formations/RimWellFormationsFile.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "Riu3DMainWindowTools.h"
#include "RiuFileDialogTools.h"
#include "RiuPlotMainWindowTools.h"
#include <QAction>
#include <QFileInfo>
@@ -41,7 +42,9 @@ void RicImportWellFormationsFeature::onActionTriggered( bool isChecked )
std::vector<RimWellFormationsFile*> importedFiles = importFilesWithDialog();
if ( !importedFiles.empty() )
{
Riu3DMainWindowTools::selectAsCurrentItem( importedFiles.back() );
// Well formations are shown in the plot window data sources tree
RiuPlotMainWindowTools::onObjectAppended( importedFiles.back(),
importedFiles.back()->firstAncestorOrThisOfType<RimWellFormationsCollection>() );
}
}
@@ -52,7 +55,7 @@ std::vector<RimWellFormationsFile*> RicImportWellFormationsFeature::importFilesW
{
RiaApplication* app = RiaApplication::instance();
QString defaultDir = app->lastUsedDialogDirectory( "WELLPATHFORMATIONS_DIR" );
QStringList filePaths = RiuFileDialogTools::getOpenFileNames( Riu3DMainWindowTools::mainWindowWidget(),
QStringList filePaths = RiuFileDialogTools::getOpenFileNames( RiaGuiApplication::widgetToUseAsParent(),
"Import Well Formations",
defaultDir,
"Well Formations (*.csv);;All Files (*.*)" );
@@ -21,6 +21,7 @@
#include "RimCorrelationPlotCollection.h"
#include "RimMainPlotCollection.h"
#include "RimRftCorrelationReportPlot.h"
#include "RimWellPlotTools.h"
#include "RimWellRftPlot.h"
#include "RiuPlotMainWindowTools.h"
@@ -36,7 +37,14 @@ CAF_CMD_SOURCE_INIT( RicCreateRftCorrelationReportFeature, "RicCreateRftCorrelat
//--------------------------------------------------------------------------------------------------
bool RicCreateRftCorrelationReportFeature::isCommandEnabled() const
{
return dynamic_cast<RimWellRftPlot*>( caf::SelectionManager::instance()->selectedItem() ) != nullptr;
if ( dynamic_cast<RimWellRftPlot*>( caf::SelectionManager::instance()->selectedItem() ) ) return true;
if ( dynamic_cast<RimCorrelationPlotCollection*>( caf::SelectionManager::instance()->selectedItem() ) )
{
return !RimWellPlotTools::firstWellNameWithEnsembleRftData().isEmpty();
}
return false;
}
//--------------------------------------------------------------------------------------------------
@@ -44,8 +52,8 @@ bool RicCreateRftCorrelationReportFeature::isCommandEnabled() const
//--------------------------------------------------------------------------------------------------
void RicCreateRftCorrelationReportFeature::onActionTriggered( bool /*isChecked*/ )
{
// Without a source plot, a default report is created for the first available ensemble RFT data
auto* sourcePlot = dynamic_cast<RimWellRftPlot*>( caf::SelectionManager::instance()->selectedItem() );
if ( !sourcePlot ) return;
auto* correlationColl = RimMainPlotCollection::current()->correlationPlotCollection();
if ( !correlationColl ) return;
@@ -145,10 +145,9 @@ std::vector<RimWellPath*> RicImportWellPaths::importWellPaths( const QStringList
{
RicNewGenericDataViewFeature::createInitialViewIfNeeded();
RimWellPath* wellPath = oilField->wellPathCollection->mostRecentlyUpdatedWellPath();
if ( wellPath )
if ( !wellPaths.empty() && wellPaths.back() )
{
Riu3DMainWindowTools::selectAsCurrentItem( wellPath );
Riu3DMainWindowTools::selectAsCurrentItem( wellPaths.back() );
}
}
}
@@ -21,10 +21,7 @@
#include "RiaApplication.h"
#include "RimMainPlotCollection.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "Riu3DMainWindowTools.h"
#include "RiuFileDialogTools.h"
@@ -60,19 +57,6 @@ void RicWellPathFormationsImportFileFeature::onActionTriggered( bool isChecked )
{
project->scheduleCreateDisplayModelAndRedrawAllViews();
RimMainPlotCollection::current()->updatePlotsWithFormations();
RimOilField* oilField = project->activeOilField();
if ( !oilField ) return;
if ( !oilField->wellPathCollection->allWellPaths().empty() )
{
RimWellPath* wellPath = oilField->wellPathCollection->mostRecentlyUpdatedWellPath();
if ( wellPath )
{
Riu3DMainWindowTools::selectAsCurrentItem( wellPath );
}
}
}
}
@@ -284,6 +284,27 @@ void RifReaderFmuRft::importData()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifReaderFmuRft::csvText() const
{
QString text;
QTextStream stream( &text );
stream << "WELL,DATE,MEASUREMENT_ID,UTM_X,UTM_Y,MD,TVD,ZONE,PRESSURE,PRESSURE_ERROR\n";
for ( const auto& obs : m_observations )
{
stream << obs.wellDate.wellName << "," << obs.wellDate.dateTime.toString( "yyyy-MM-dd" ) << "," << obs.wellDate.measurementId << ","
<< QString::number( obs.location.utmx, 'f', 2 ) << "," << QString::number( obs.location.utmy, 'f', 2 ) << ","
<< QString::number( obs.location.mdrkb, 'f', 2 ) << "," << QString::number( obs.location.tvdmsl, 'f', 2 ) << ","
<< obs.location.formation << "," << QString::number( obs.pressure, 'f', 2 ) << ","
<< QString::number( obs.pressureError, 'f', 2 ) << "\n";
}
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -81,6 +81,9 @@ public:
void importData();
// Imported observations as comma separated text with a header row
QString csvText() const;
private:
static std::vector<WellDate> importWellDates( const QString& fileName );
static std::vector<Location> importLocations( const QString& fileName );
@@ -36,6 +36,8 @@
#include "RimWellRftEnsembleCurveSet.h"
#include "RimWellRftPlot.h"
#include "cafCmdFeatureMenuBuilder.h"
CAF_PDM_SOURCE_INIT( RimCorrelationPlotCollection, "CorrelationPlotCollection" );
namespace
@@ -211,12 +213,12 @@ RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationR
{
auto* report = new RimRftCorrelationReportPlot;
report->dockAsPlotWindow();
report->initializeFromSourcePlot( source );
if ( source )
auto* rftPlot = report->wellRftPlot();
if ( rftPlot )
{
report->initializeFromSourcePlot( source );
const auto ensembles = source->selectedEnsembles();
const auto ensembles = rftPlot->selectedEnsembles();
if ( !ensembles.empty() )
{
auto* ensemble = ensembles.front();
@@ -229,7 +231,7 @@ RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationR
{
report->crossPlot()->setEnsembleParameter( param.name );
if ( auto* curveSet = report->wellRftPlot()->findEnsembleCurveSet( ensemble ) )
if ( auto* curveSet = rftPlot->findEnsembleCurveSet( ensemble ) )
{
curveSet->setColorByEnsembleParameter( param.name );
}
@@ -237,7 +239,8 @@ RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationR
}
}
}
report->crossPlot()->setWellName( source->simWellOrWellPathName() );
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();
@@ -245,7 +248,7 @@ RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationR
{
for ( RimWellFormationsFile* file : project->activeOilField()->wellFormationsCollection()->wellFormationsFiles() )
{
if ( file->formationsForWell( source->simWellOrWellPathName() ) )
if ( file->formationsForWell( wellName ) )
{
report->crossPlot()->setWellFormations( file );
report->crossPlot()->setFilterMode( RimRftCrossPlotTools::DepthFilterMode::ZONES );
@@ -254,7 +257,7 @@ RimRftCorrelationReportPlot* RimCorrelationPlotCollection::createRftCorrelationR
}
}
const auto timeSteps = source->selectedTimeSteps();
const auto timeSteps = rftPlot->selectedTimeSteps();
if ( !timeSteps.empty() ) report->crossPlot()->setTimeStep( timeSteps.front() );
}
@@ -270,6 +273,19 @@ std::vector<RimRftCorrelationReportPlot*> RimCorrelationPlotCollection::rftRepor
return m_rftCorrelationReports.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCorrelationPlotCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicNewCorrelationPlotFeature";
menuBuilder << "RicNewCorrelationMatrixPlotFeature";
menuBuilder << "RicNewParameterResultCrossPlotFeature";
menuBuilder << "RicNewCorrelationReportPlotFeature";
menuBuilder.addSeparator();
menuBuilder << "RicCreateRftCorrelationReportFeature";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -81,6 +81,8 @@ public:
std::vector<RimRftCorrelationReportPlot*> rftReports() const;
private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
void applyFirstEnsembleFieldAddressesToPlot( RimAbstractCorrelationPlot* plot, const std::vector<QString>& quantityNames = {} );
void applyEnsembleFieldAndTimeStepToPlot( RimAbstractCorrelationPlot* plot,
RimSummaryEnsemble* ensemble,
@@ -755,7 +755,6 @@ void RimParameterRftCrossPlot::createPoints()
caf::ColorTable colorTable = RiaColorTables::categoryPaletteColors();
auto caseData = createCaseData();
if ( caseData.empty() ) return;
std::set<RimSummaryCase*> selectedSummaryCases;
auto selectedTreeViewItems = RiuDockWidgetTools::selectedItemsInTreeView( RiuDockWidgetTools::plotMainWindowDataSourceTreeName() );
@@ -806,21 +805,14 @@ void RimParameterRftCrossPlot::createPoints()
//--------------------------------------------------------------------------------------------------
void RimParameterRftCrossPlot::attachObservedPressure()
{
const auto observedPressures =
RimRftCrossPlotTools::computeObservedPressures( m_wellName(),
m_selectedTimeStep(),
depthIntervals(),
m_depthType(),
RimRftCrossPlotTools::buildAllZoneIntervals( m_wellFormations(),
m_wellName(),
m_depthType() ) );
if ( observedPressures.empty() ) return;
const auto pressures = observedPressures();
if ( pressures.empty() ) return;
auto attachLine = [this]( double value, Qt::PenStyle style, const QString& label, const QColor& color )
{ RiuRftCorrelationPlotTools::attachHorizontalLine( m_plotWidget, value, style, label, color ); };
bool isFirst = true;
for ( const auto& observed : observedPressures )
for ( const auto& observed : pressures )
{
// Use the formation color when known; otherwise fall back to black lines and no shaded band
std::optional<QColor> zoneColor;
@@ -850,6 +842,20 @@ void RimParameterRftCrossPlot::attachObservedPressure()
}
}
//--------------------------------------------------------------------------------------------------
/// Shared by drawing and range computation so the axis range matches the drawn zone averages
//--------------------------------------------------------------------------------------------------
std::vector<RimRftCrossPlotTools::ObservedPressure> RimParameterRftCrossPlot::observedPressures() const
{
return RimRftCrossPlotTools::computeObservedPressures( m_wellName(),
m_selectedTimeStep(),
depthIntervals(),
m_depthType(),
RimRftCrossPlotTools::buildAllZoneIntervals( m_wellFormations(),
m_wellName(),
m_depthType() ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -895,25 +901,35 @@ void RimParameterRftCrossPlot::updateValueRanges()
yMax = std::max( yMax, pressureValue );
}
for ( const auto& observed :
RimRftCrossPlotTools::computeObservedPressures( m_wellName(), m_selectedTimeStep(), depthIntervals(), m_depthType() ) )
for ( const auto& observed : observedPressures() )
{
yMin = std::min( yMin, observed.rangeMin );
yMax = std::max( yMax, observed.rangeMax );
}
if ( xMin == std::numeric_limits<double>::infinity() )
// Without RFT samples, use the parameter range so the X axis does not keep the range of a previous time step
if ( xMin == std::numeric_limits<double>::infinity() && m_ensemble() && !m_ensembleParameter().isEmpty() )
{
m_xValueRange = std::nullopt;
m_yValueRange = std::nullopt;
return;
const RigEnsembleParameter parameter = m_ensemble->ensembleParameter( m_ensembleParameter );
if ( parameter.isNumeric() && parameter.isValid() )
{
xMin = parameter.minValue;
xMax = parameter.maxValue;
}
}
const double xRange = xMax - xMin;
const double yRange = yMax - yMin;
// Observed data is shown even when there are no RFT samples, so the ranges are computed independently
auto paddedRange = []( double minValue, double maxValue ) -> std::optional<std::pair<double, double>>
{
if ( minValue == std::numeric_limits<double>::infinity() ) return std::nullopt;
m_xValueRange = std::make_pair( xMin - xRange * 0.1, xMax + xRange * 0.1 );
m_yValueRange = std::make_pair( yMin - yRange * 0.1, yMax + yRange * 0.1 );
const double range = maxValue - minValue;
const double padding = range > 0.0 ? range * 0.1 : std::max( std::abs( minValue ) * 0.01, 1.0 );
return std::make_pair( minValue - padding, maxValue + padding );
};
m_xValueRange = paddedRange( xMin, xMax );
m_yValueRange = paddedRange( yMin, yMax );
}
//--------------------------------------------------------------------------------------------------
@@ -132,7 +132,8 @@ private:
void cleanupBeforeClose();
RimSummaryCase* findClosestCase( const QPoint& canvasPos );
std::vector<RimRftCrossPlotTools::DepthInterval> depthIntervals() const;
std::vector<RimRftCrossPlotTools::DepthInterval> depthIntervals() const;
std::vector<RimRftCrossPlotTools::ObservedPressure> observedPressures() const;
private:
caf::PdmPtrField<RimSummaryEnsemble*> m_ensemble;
@@ -25,6 +25,7 @@
#include "RimRftCrossPlotTools.h"
#include "RimRftTornadoPlot.h"
#include "RimWellLogTrack.h"
#include "RimWellPlotTools.h"
#include "RimWellRftEnsembleCurveSet.h"
#include "RimWellRftPlot.h"
@@ -207,14 +208,13 @@ RimParameterRftCrossPlot* RimRftCorrelationReportPlot::crossPlot() const
/// Initialize the owned RimWellRftPlot from the source plot's selected data sources.
/// We keep the fresh (curve-free) child plot and call initializeDataSources(source) so
/// syncCurvesFromUiSelection builds curves from scratch without touching unresolved copies.
/// Without a source plot, the first well with ensemble RFT data is used with all available data sources.
//--------------------------------------------------------------------------------------------------
void RimRftCorrelationReportPlot::initializeFromSourcePlot( RimWellRftPlot* source )
{
if ( !source ) return;
applyDepthTypeToSubPlots();
m_wellRftPlot->setSimWellOrWellPathName( source->simWellOrWellPathName() );
m_wellRftPlot->setSimWellOrWellPathName( source ? source->simWellOrWellPathName() : RimWellPlotTools::firstWellNameWithEnsembleRftData() );
// A fresh RimWellRftPlot has no tracks; syncCurvesFromUiSelection exits early without one.
// Guard against duplicate track creation if this is called more than once.
@@ -227,10 +227,14 @@ void RimRftCorrelationReportPlot::initializeFromSourcePlot( RimWellRftPlot* sour
m_wellRftPlot->initializeDataSources( source );
// The correlation report operates on a single time step; trim any extras that
// initializeDataSources may have preselected when only a few were available.
// The correlation report operates on a single time step; prefer the time step selected in the
// source plot, and trim any extras that initializeDataSources may have preselected.
auto selectedTimeSteps = m_wellRftPlot->selectedTimeSteps();
if ( selectedTimeSteps.size() > 1 )
if ( source && !source->selectedTimeSteps().empty() )
{
m_wellRftPlot->setSelectedTimeSteps( { source->selectedTimeSteps().front() } );
}
else if ( selectedTimeSteps.size() > 1 )
{
m_wellRftPlot->setSelectedTimeSteps( { selectedTimeSteps.front() } );
}
@@ -706,7 +710,12 @@ void RimRftCorrelationReportPlot::onRftTrackDepthClicked( RimWellLogTrack* track
m_parameterRftCrossPlot->setFilterMode( RimRftCrossPlotTools::DepthFilterMode::ZONES );
m_parameterRftCrossPlot->setSelectedZones( zones );
loadDataAndUpdate();
// The zone filter does not affect the RFT curves; skip reloading the RFT plot to keep its zoom
updateSelectedZoneHighlight();
syncTornadoInputsFromCrossPlot();
m_tornadoPlot->loadDataAndUpdate();
m_parameterRftCrossPlot->loadDataAndUpdate();
updateConnectedEditors();
return;
}
@@ -490,6 +490,27 @@ std::vector<RimSummaryEnsemble*> rftEnsembles()
return rftEnsembles;
}
//--------------------------------------------------------------------------------------------------
/// Stops at the first realization with RFT data, as querying the RFT reader of every realization is expensive
//--------------------------------------------------------------------------------------------------
QString firstWellNameWithEnsembleRftData()
{
for ( RimSummaryEnsemble* ensemble : RimProject::current()->summaryEnsembles() )
{
if ( !ensemble || !ensemble->isEnsemble() ) continue;
for ( RimSummaryCase* summaryCase : ensemble->allSummaryCases() )
{
auto reader = summaryCase->rftReader();
if ( !reader ) continue;
const auto wellNames = reader->wellNames();
if ( !wellNames.empty() ) return *wellNames.begin();
}
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -85,6 +85,7 @@ std::vector<RimEclipseResultCase*> gridCasesForWell( const QString& simWellName
std::vector<RimEclipseResultCase*> rftCasesForWell( const QString& simWellName );
std::vector<RimSummaryEnsemble*> rftEnsemblesForWell( const QString& simWellName );
std::vector<RimSummaryEnsemble*> rftEnsembles();
QString firstWellNameWithEnsembleRftData();
std::vector<RimObservedFmuRftData*> observedFmuRftDataForWell( const QString& simWellName );
std::vector<RimObservedFmuRftData*> observedFmuRftData();
QString simWellName( const QString& wellPathNameOrSimWellName );
@@ -946,30 +946,6 @@ const char* RimWellRftPlot::plotNameFormatString()
return PLOT_NAME_QFORMAT_STRING;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellRftPlot::deleteCurvesAssosicatedWithObservedData( const RimObservedFmuRftData* observedFmuRftData )
{
for ( auto plot : plots() )
{
RimWellLogTrack* const track = dynamic_cast<RimWellLogTrack*>( plot );
if ( track )
{
auto curves = track->curves();
for ( auto curve : curves )
{
RimWellLogRftCurve* rftCurve = dynamic_cast<RimWellLogRftCurve*>( curve );
if ( rftCurve && rftCurve->observedFmuRftData() == observedFmuRftData )
{
track->removeCurve( rftCurve );
delete rftCurve;
}
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -93,8 +93,6 @@ public:
static const char* plotNameFormatString();
void deleteCurvesAssosicatedWithObservedData( const RimObservedFmuRftData* observedFmuRftData );
bool showErrorBarsForObservedData() const;
void onLegendDefinitionChanged();
@@ -19,14 +19,13 @@
#include "RimWellFormationsFile.h"
#include "RiaLogging.h"
#include "RifCsvHtmlTableTools.h"
#include "RimMainPlotCollection.h"
#include "RimProject.h"
#include "RimWellPath.h"
#include "Tools/RimCsvPreviewTools.h"
#include "cafPdmUiFilePathEditor.h"
#include "cafPdmUiTextEditor.h"
#include "cafPdmUiTreeOrdering.h"
#include <QFileInfo>
@@ -44,10 +43,7 @@ RimWellFormationsFile::RimWellFormationsFile()
m_filePath.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_contentTable, "ContentTable", "Content" );
m_contentTable.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
m_contentTable.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::HIDDEN );
m_contentTable.uiCapability()->setUiReadOnly( true );
m_contentTable.xmlCapability()->disableIO();
RimCsvPreviewTools::initPreviewField( m_contentTable );
setDeletable( true );
}
@@ -223,12 +219,7 @@ void RimWellFormationsFile::defineEditorAttribute( const caf::PdmFieldHandle* fi
{
if ( field == &m_contentTable )
{
auto myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute );
if ( myAttr )
{
myAttr->wrapMode = caf::PdmUiTextEditorAttribute::NoWrap;
myAttr->textMode = caf::PdmUiTextEditorAttribute::HTML;
}
RimCsvPreviewTools::setPreviewEditorAttribute( attribute );
}
}
@@ -259,15 +250,5 @@ void RimWellFormationsFile::updateUiTreeName()
//--------------------------------------------------------------------------------------------------
void RimWellFormationsFile::updateContentTable()
{
const int maxRowCount = 1000;
auto result = RifCsvHtmlTableTools::generateHtmlTableFromFile( filePath(), maxRowCount );
if ( result )
{
m_contentTable = *result;
}
else
{
m_contentTable = result.error();
}
m_contentTable = RimCsvPreviewTools::htmlTableFromFile( filePath() );
}
@@ -49,7 +49,6 @@
#include "RimColorLegendItem.h"
#include "RimCorrelationMatrixPlot.h"
#include "RimCorrelationPlot.h"
#include "RimCorrelationPlotCollection.h"
#include "RimCustomObjectiveFunction.h"
#include "RimCustomObjectiveFunctionCollection.h"
#include "RimEclipseCase.h"
@@ -603,13 +602,6 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
menuBuilder << "RicNewAnalysisPlotFeature";
menuBuilder << "RicNewPlotDataFilterFeature";
}
else if ( dynamic_cast<RimCorrelationPlotCollection*>( firstUiItem ) )
{
menuBuilder << "RicNewCorrelationPlotFeature";
menuBuilder << "RicNewCorrelationMatrixPlotFeature";
menuBuilder << "RicNewParameterResultCrossPlotFeature";
menuBuilder << "RicNewCorrelationReportPlotFeature";
}
else if ( dynamic_cast<RimCorrelationPlot*>( firstUiItem ) )
{
menuBuilder << "RicNewCorrelationPlotFeature";
@@ -1072,7 +1064,6 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection()
menuBuilder << "RicCloseSummaryCaseFeature";
menuBuilder << "RicCloseSummaryCaseInCollectionFeature";
menuBuilder << "RicDeleteSummaryCaseCollectionFeature";
menuBuilder << "RicCloseObservedDataFeature";
menuBuilder << "RicDeleteSubPlotFeature";
menuBuilder << "RicNewMultiPlotFeature";
@@ -30,6 +30,7 @@
#include "RimObservedEclipseUserData.h"
#include "RimObservedFmuRftData.h"
#include "RimObservedSummaryData.h"
#include "RimPlotCurve.h"
#include "RimPressureDepthData.h"
#include "RimProject.h"
#include "RimSummaryObservedDataFile.h"
@@ -42,7 +43,9 @@
#include "cafPdmUiPropertyViewDialog.h"
#include "cafUtils.h"
#include <QDir>
#include <QFile>
#include <QSet>
CAF_PDM_SOURCE_INIT( RimObservedDataCollection, "ObservedDataCollection" );
@@ -58,24 +61,6 @@ RimObservedDataCollection::RimObservedDataCollection()
CAF_PDM_InitFieldNoDefault( &m_observedPressureDepthArray, "PressureDepthDataArray", "" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimObservedDataCollection::removeObservedSummaryData( RimObservedSummaryData* observedData )
{
m_observedDataArray.removeChild( observedData );
caf::PdmUiObjectEditorHandle::updateUiAllObjectEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimObservedDataCollection::removeObservedFmuRftData( RimObservedFmuRftData* observedFmuRftData )
{
m_observedFmuRftArray.removeChild( observedFmuRftData );
caf::PdmUiObjectEditorHandle::updateUiAllObjectEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -105,6 +90,16 @@ std::vector<RimPressureDepthData*> RimObservedDataCollection::allPressureDepthDa
//--------------------------------------------------------------------------------------------------
void RimObservedDataCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects )
{
// Delete curves that referenced the deleted observed data
std::set<caf::PdmObjectHandle*> uniqueReferringObjects( referringObjects.begin(), referringObjects.end() );
for ( caf::PdmObjectHandle* obj : uniqueReferringObjects )
{
if ( auto curve = dynamic_cast<RimPlotCurve*>( obj ) )
{
curve->deleteIfDataSourceIsMissing();
}
}
RimMainPlotCollection::current()->loadDataAndUpdateAllPlots();
}
@@ -240,7 +235,23 @@ RimObservedSummaryData* RimObservedDataCollection::createAndAddCvsObservedSummar
//--------------------------------------------------------------------------------------------------
RimObservedFmuRftData* RimObservedDataCollection::createAndAddFmuRftDataFromPath( const QString& directoryPath )
{
QString name = QString( "Imported FMU RFT Data %1" ).arg( m_observedFmuRftArray.size() + 1 );
// The data folder is often named e.g. "rft", so include the parent folder to make the name descriptive
const QDir dir( directoryPath );
QStringList pathParts = QDir::cleanPath( dir.absolutePath() ).split( '/', Qt::SkipEmptyParts );
QString baseName = pathParts.size() >= 2 ? pathParts.mid( pathParts.size() - 2 ).join( '/' ) : dir.dirName();
if ( baseName.isEmpty() ) baseName = "Observed FMU Data";
QSet<QString> existingNames;
for ( const auto& existing : m_observedFmuRftArray )
{
existingNames.insert( existing->name() );
}
QString name = baseName;
for ( int i = 2; existingNames.contains( name ); ++i )
{
name = QString( "%1 (%2)" ).arg( baseName ).arg( i );
}
RimObservedFmuRftData* fmuRftData = new RimObservedFmuRftData;
fmuRftData->setDirectoryPath( directoryPath );
@@ -35,8 +35,6 @@ class RimObservedDataCollection : public caf::PdmObject
public:
RimObservedDataCollection();
void removeObservedSummaryData( RimObservedSummaryData* observedSummaryData );
void removeObservedFmuRftData( RimObservedFmuRftData* observedFmuRftData );
RimObservedSummaryData* createAndAddRsmObservedSummaryDataFromFile( const QString& fileName, QString* errorText = nullptr );
RimObservedSummaryData*
createAndAddCvsObservedSummaryDataFromFile( const QString& fileName, bool useSavedFieldsValuesInDialog, QString* errorText = nullptr );
@@ -17,6 +17,8 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RimObservedFmuRftData.h"
#include "Tools/RimCsvPreviewTools.h"
//==================================================================================================
//
//
@@ -30,6 +32,7 @@ CAF_PDM_SOURCE_INIT( RimObservedFmuRftData, "ObservedFmuRftData" );
RimObservedFmuRftData::RimObservedFmuRftData()
{
CAF_PDM_InitObject( "Observed FMU Data", ":/ObservedRFTDataFile16x16.png" );
setDeletable( true );
CAF_PDM_InitFieldNoDefault( &m_directoryPath, "ObservedFolder", "Directory" );
m_directoryPath.uiCapability()->setUiReadOnly( true );
@@ -38,9 +41,8 @@ RimObservedFmuRftData::RimObservedFmuRftData()
m_directoryPath_OBSOLETE.uiCapability()->setUiReadOnly( true );
m_directoryPath_OBSOLETE.xmlCapability()->setIOWritable( false );
CAF_PDM_InitFieldNoDefault( &m_wells, "Wells", "Wells" );
m_wells.uiCapability()->setUiReadOnly( true );
m_wells.registerGetMethod( this, &RimObservedFmuRftData::wells );
CAF_PDM_InitFieldNoDefault( &m_contentTable, "ContentTable", "Content" );
RimCsvPreviewTools::initPreviewField( m_contentTable );
}
//--------------------------------------------------------------------------------------------------
@@ -58,6 +60,7 @@ void RimObservedFmuRftData::createRftReaderInterface()
{
m_fmuRftReader = std::make_unique<RifReaderFmuRft>( m_directoryPath().path() );
m_fmuRftReader->importData();
m_contentTable = "";
}
//--------------------------------------------------------------------------------------------------
@@ -124,3 +127,38 @@ void RimObservedFmuRftData::initAfterRead()
m_directoryPath = m_directoryPath_OBSOLETE();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimObservedFmuRftData::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
// Built on demand, as the table is only needed when the data is shown in the property editor
if ( m_contentTable().isEmpty() ) updateContentTable();
uiOrdering.add( nameField() );
uiOrdering.add( &m_directoryPath );
uiOrdering.add( &m_contentTable );
uiOrdering.skipRemainingFields();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimObservedFmuRftData::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_contentTable )
{
RimCsvPreviewTools::setPreviewEditorAttribute( attribute );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimObservedFmuRftData::updateContentTable()
{
if ( !rftReader() ) return;
m_contentTable = RimCsvPreviewTools::htmlTableFromText( m_fmuRftReader->csvText() );
}
@@ -24,7 +24,6 @@
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmProxyValueField.h"
#include <memory>
@@ -45,11 +44,16 @@ public:
protected:
void initAfterRead() override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
private:
void updateContentTable();
private:
std::unique_ptr<RifReaderFmuRft> m_fmuRftReader;
caf::PdmField<caf::FilePath> m_directoryPath;
caf::PdmField<QString> m_directoryPath_OBSOLETE;
caf::PdmProxyValueField<std::vector<QString>> m_wells;
caf::PdmField<caf::FilePath> m_directoryPath;
caf::PdmField<QString> m_directoryPath_OBSOLETE;
caf::PdmField<QString> m_contentTable;
};
@@ -1241,6 +1241,14 @@ void RimPlotCurve::deletePlotCurve()
m_plotCurve = nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimPlotCurve::deleteIfDataSourceIsMissing()
{
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -133,11 +133,14 @@ public:
void setParentPlotNoReplot( RiuPlotWidget* );
void setParentPlotAndReplot( RiuPlotWidget* );
void attach( RiuPlotWidget* );
void detach( bool deletePlotCurve = false );
void reattach( bool updateParentPlot = true );
bool isSameCurve( const RiuPlotCurve* plotCurve ) const;
void deletePlotCurve();
void attach( RiuPlotWidget* );
void detach( bool deletePlotCurve = false );
void reattach( bool updateParentPlot = true );
bool isSameCurve( const RiuPlotCurve* plotCurve ) const;
void deletePlotCurve();
// Deletes this curve if its data source is missing. Returns true if deleted; the object must not be accessed afterwards.
virtual bool deleteIfDataSourceIsMissing();
RiuPlotCurve* plotCurve() const;
std::vector<RimPlotRectAnnotation*> rectAnnotations() const;
@@ -33,6 +33,7 @@ CAF_PDM_ABSTRACT_SOURCE_INIT( RimObservedSummaryData, "ObservedData" );
RimObservedSummaryData::RimObservedSummaryData()
{
m_isObservedData = true;
setDeletable( true );
CAF_PDM_InitFieldNoDefault( &m_importedSummaryData, "ImportedSummaryData", "Imported Summary Data" );
m_importedSummaryData.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
@@ -1398,6 +1398,21 @@ void RimSummaryCurve::updateTimeAnnotations()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSummaryCurve::deleteIfDataSourceIsMissing()
{
const bool isXCaseMissing = m_xAxisType() == RiaDefines::HorizontalAxisType::SUMMARY_VECTOR && !m_xValuesSummaryCase();
if ( m_yValuesSummaryCase() && !isXCaseMissing ) return false;
auto summaryPlot = firstAncestorOrThisOfType<RimSummaryPlot>();
if ( !summaryPlot ) return false;
summaryPlot->deleteCurves( { this } );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -108,6 +108,8 @@ public:
virtual bool isRegressionCurve() const;
void updateLegendEntryVisibilityNoPlotUpdate() override;
bool deleteIfDataSourceIsMissing() override;
protected:
// RimPlotCurve overrides
QString createCurveAutoName() override;
@@ -3,6 +3,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RimAutomationSettings.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEclipseViewTools.cpp
${CMAKE_CURRENT_LIST_DIR}/RimCsvPreviewTools.cpp
)
list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES})
@@ -0,0 +1,66 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimCsvPreviewTools.h"
#include "RifCsvHtmlTableTools.h"
#include "cafPdmUiFieldHandle.h"
#include "cafPdmUiTextEditor.h"
#include "cafPdmXmlFieldHandle.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCsvPreviewTools::initPreviewField( caf::PdmField<QString>& field )
{
field.uiCapability()->setUiEditorTypeName( caf::PdmUiTextEditor::uiEditorTypeName() );
field.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::HIDDEN );
field.uiCapability()->setUiReadOnly( true );
field.xmlCapability()->disableIO();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCsvPreviewTools::setPreviewEditorAttribute( caf::PdmUiEditorAttribute* attribute )
{
if ( auto myAttr = dynamic_cast<caf::PdmUiTextEditorAttribute*>( attribute ) )
{
myAttr->wrapMode = caf::PdmUiTextEditorAttribute::NoWrap;
myAttr->textMode = caf::PdmUiTextEditorAttribute::HTML;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCsvPreviewTools::htmlTableFromText( const QString& csvText, int maxRowCount )
{
auto result = RifCsvHtmlTableTools::generateHtmlTableFromText( csvText, maxRowCount );
return result ? *result : result.error();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCsvPreviewTools::htmlTableFromFile( const QString& filePath, int maxRowCount )
{
auto result = RifCsvHtmlTableTools::generateHtmlTableFromFile( filePath, maxRowCount );
return result ? *result : result.error();
}
@@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
// 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
@@ -18,26 +18,30 @@
#pragma once
#include "cafCmdFeature.h"
#include "cafPdmField.h"
#include <vector>
#include <QString>
class RimObservedFmuRftData;
class RimObservedSummaryData;
//==================================================================================================
///
//==================================================================================================
class RicCloseObservedDataFeature : public caf::CmdFeature
namespace caf
{
CAF_CMD_HEADER_INIT;
class PdmUiEditorAttribute;
}
public:
static void deleteObservedSummaryData( const std::vector<RimObservedSummaryData*>& data );
static void deleteObservedRmuRftData( const std::vector<RimObservedFmuRftData*>& data );
//==================================================================================================
/// Helpers for showing CSV data as a read-only HTML table in the property editor
//==================================================================================================
namespace RimCsvPreviewTools
{
const int defaultMaxRowCount = 1000;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
// Configures the field as a read-only, non-persistent HTML text editor without label
void initPreviewField( caf::PdmField<QString>& field );
// Call from defineEditorAttribute() for the preview field
void setPreviewEditorAttribute( caf::PdmUiEditorAttribute* attribute );
// Returns the HTML table, or the error message if the content could not be parsed
QString htmlTableFromText( const QString& csvText, int maxRowCount = defaultMaxRowCount );
QString htmlTableFromFile( const QString& filePath, int maxRowCount = defaultMaxRowCount );
} // namespace RimCsvPreviewTools
@@ -327,6 +327,21 @@ RimObservedFmuRftData* RimWellLogRftCurve::observedFmuRftData() const
return m_observedFmuRftData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimWellLogRftCurve::deleteIfDataSourceIsMissing()
{
if ( m_eclipseCase || m_summaryCase || m_ensemble || m_observedFmuRftData || m_pressureDepthData ) return false;
auto track = firstAncestorOrThisOfType<RimWellLogTrack>();
if ( !track ) return false;
track->removeCurve( this );
delete this;
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -96,6 +96,8 @@ public:
void setScaleFactor( double factor );
bool deleteIfDataSourceIsMissing() override;
protected:
QString createCurveAutoName() override;
QString createCurveNameFromTemplate( const QString& templateText ) override;
@@ -392,8 +392,6 @@ void RimWellPathCollection::addWellPath( RimWellPath* wellPath )
m_wellPaths.push_back( wellPath );
rebuildWellPathNodes();
m_mostRecentlyUpdatedWellPath = wellPath;
}
//--------------------------------------------------------------------------------------------------
@@ -569,8 +567,6 @@ void RimWellPathCollection::addWellPathFormations( const QStringList& filePaths
QString wellFormationsCount = QString( "%1" ).arg( formations->formationNamesCount() );
m_mostRecentlyUpdatedWellPath = wellPath;
outputMessage += wellName + "\t\t";
outputMessage += wellPath->name() + " \t\t\t";
outputMessage += wellFormationsCount + "\n";
@@ -925,14 +921,6 @@ void RimWellPathCollection::groupWellPaths( const std::vector<RimWellPath*>& wel
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimWellPath* RimWellPathCollection::mostRecentlyUpdatedWellPath()
{
return m_mostRecentlyUpdatedWellPath;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -124,8 +124,6 @@ public:
bool showMswSegmentBands() const;
RimWellPath* mostRecentlyUpdatedWellPath();
void readWellPathFormationFiles();
void reloadAllWellPathFormations();
RimWellPath* wellPathByName( const QString& wellPathName ) const;
@@ -189,7 +187,6 @@ private:
private:
std::unique_ptr<RifWellPathImporter> m_wellPathImporter;
caf::PdmPointer<RimWellPath> m_mostRecentlyUpdatedWellPath;
caf::PdmChildField<RimWellMeasurementCollection*> m_wellMeasurements;
caf::PdmChildField<RimWellEventTimeline*> m_eventTimeline;
caf::PdmChildArrayField<RimWellPath*> m_wellPaths;
@@ -483,6 +483,10 @@ bool RiuMultiPlotPage::hasHeightForWidth() const
//--------------------------------------------------------------------------------------------------
int RiuMultiPlotPage::heightForWidth( int width ) const
{
// The page aspect ratio is only relevant in page preview mode. Otherwise, a parent scroll area (e.g. a dock widget) will size the
// page taller than the visible area, and the bottom of the plot is clipped.
if ( !m_previewMode ) return -1;
QPageLayout pageLayout = m_plotDefinition->pageLayout();
QRectF rect = pageLayout.fullRectPoints();
double aspectRatio = rect.height() / rect.width();